Deployment guide

Krill

Overview

This guide covers deploying and configuring Krill on Ubuntu 24.04 on Azure with the SecureAnyCloud Azure Marketplace image. Krill is an open-source RPKI Certificate Authority from NLnet Labs. It lets a network operator run their own Resource Public Key Infrastructure: issuing certificates for the IP address space and AS numbers they hold, and publishing Route Origin Authorizations (ROAs) that state which networks may originate their prefixes.

Krill can run as a delegated child under a parent authority such as a Regional Internet Registry. This gives you direct control over the RPKI objects that protect your routing.

Krill is a single self-contained set of Rust binaries: the krill daemon and the krillc command-line client. It has an embedded data store, so there is no external database, and a built-in web interface.

The image installs Krill from the official NLnet Labs apt repository and bakes it reproducibly. The exact version is recorded in /opt/krill/VERSION. Krill runs under systemd as the unprivileged krill system user.

The Krill daemon binds to loopback only (127.0.0.1:3000) with its own TLS. nginx is the sole network-facing surface. It terminates TLS on port 443 and reverse-proxies to the Krill HTTPS upstream.

On the first boot of every VM, the image generates a unique administrative token, sets the Krill service URL to https://<your public ip>/, and regenerates a self-signed TLS certificate. The certificate's Subject Alternative Names include the VM public IP and hostname.

The token protects the web UI and the full REST API. Unauthenticated requests are refused (HTTP 403), and only the admin token is accepted. The token is written to /root/krill-credentials.txt (mode 0600, root only). No shared secret and no default login ever ships inside the image.

What you get:

  • Krill (latest stable release from the official NLnet Labs apt repository), run under systemd as the unprivileged krill system user
  • The Krill daemon and its embedded store bound to loopback only (127.0.0.1:3000), never directly exposed to the network
  • nginx terminating TLS on :443 and reverse-proxying the web UI and REST API to the Krill upstream
  • Port :80 returning a 301 redirect to HTTPS for every path except an unauthenticated /healthz endpoint (HTTP 200) for load balancer probes
  • A unique admin token generated on first boot and stored in /root/krill-credentials.txt (0600), with no shared secret and no default login
  • A self-signed TLS certificate regenerated per VM on first boot (SAN includes the VM public IP and hostname), which you can replace with your own CA-signed certificate for production
  • Ubuntu 24.04 LTS base with the latest security patches applied at build time and unattended security upgrades enabled
  • Azure Linux Agent for cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with a guaranteed 24-hour response SLA

Prerequisites

Before you deploy, you need:

  • An active Azure subscription, an SSH public key, and a VNet and subnet in the target region
  • A subscription to the Krill listing on Azure Marketplace
  • To issue live ROAs, a parent CA (typically your Regional Internet Registry, over RFC 8183) and a publication repository

The image runs the CA out of the box. You connect a parent and a repository from the web UI (Step 8) when you are ready.

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for a Certificate Authority managing your own resources and ROAs. Krill is light on CPU and needs no GPU.

1

Deploy from the Azure Portal

Search the Azure Marketplace for Krill, select the SecureAnyCloud publisher, and choose Create.

Configure the network security group (NSG) with these inbound rules from the networks you manage the CA from:

  • TCP 22 for administration
  • TCP 443 for the web UI and REST API over HTTPS
  • TCP 80 for the HTTP to HTTPS redirect and the health probe
2

Deploy from the Azure CLI

RG="krill-prod"; LOCATION="eastus"; VM_NAME="krill-01" IMAGE_URN="sac1647283583153:krill-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name krill-vnet --address-prefix 10.100.0.0/16 --subnet-name krill-subnet --subnet-prefix 10.100.1.0/24 az network nsg create -g "$RG" --name krill-nsg az network nsg rule create -g "$RG" --nsg-name krill-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name krill-nsg --name allow-https --priority 110 \
  --destination-port-ranges 443 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name krill-nsg --name allow-http --priority 120 \
  --destination-port-ranges 80 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:krill-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name krill-vnet --subnet krill-subnet --nsg krill-nsg --public-ip-sku Standard
3

Verify the Krill and nginx services

Connect over SSH, then confirm that both services are active and that Krill is bound to loopback only. In the listener output, 127.0.0.1:3000 (Krill) is loopback only, while nginx listens publicly on :443 and :80:

sudo systemctl is-active krill.service nginx.service krill --version sudo ss -tlnH '( sport = :443 or sport = :3000 )'

Both services report active, Krill reports its version, and the listener table shows Krill on 127.0.0.1:3000 (loopback only) with nginx public on :443 and :80.

4

Retrieve your per-instance admin token

On the first boot, the image generates a unique admin token, the service URL and quick-start commands, and stores them in a root-only file. Read the file over SSH:

sudo ls -l /root/krill-credentials.txt
sudo cat /root/krill-credentials.txt

The ls -l output confirms that the file is 0600 and owned by root. The file contains the service URL (https://<your public ip>/), the per-instance krill.admin_token, and quick-start commands.

Store the token somewhere safe. It is unique to this VM and protects the web UI and the full API.

5

Log in to the Krill web interface

Open https://<your public ip>/ in a browser. The image ships a self-signed certificate, so your browser warns on the first visit. Accept the warning to proceed, or install your own certificate (see Step 9).

Krill shows a sign-in page that asks for a password. Paste the admin token from Step 4 and select Sign In.

Once you are signed in, Krill shows the Certificate Authority dashboard. For a Certificate Authority named sac-demo, it has tabs for ROAs, ASPAs, Parents and Repository, plus controls to add and analyse ROAs. This is where you manage the RPKI objects for your resources.

6

Create and read back a Certificate Authority from the CLI

The krillc client talks to the local Krill daemon. Point it at the loopback endpoint, authenticate with your admin token, then create a Certificate Authority and read it back. Creating a CA and confirming that it persists is the core round trip this image verifies before it ships:

export KRILL_CLI_SERVER=https://127.0.0.1:3000/
export
KRILL_CLI_TOKEN=$(sudo grep '^krill.admin_token=' /root/krill-credentials.txt | cut -d= -f2-) sudo -E krillc add --ca my-first-ca
sudo -E krillc list
sudo -E krillc show --ca my-first-ca

krillc list now includes my-first-ca, and krillc show prints the CA with its identity certificate and resources. This proves that the Certificate Authority was created and persisted in Krill's embedded store.

7

Confirm the API rejects anonymous access

The /health and /healthz endpoints are served without authentication, which suits load balancer and Azure health probes, and return HTTP 200. The REST API requires the admin token. An anonymous request is refused, and only the token returns 200.

The self-signed certificate lives at /etc/nginx/tls/krill.crt, so pass it with --cacert:

CA=/etc/nginx/tls/krill.crt
TOKEN=$(sudo grep '^krill.admin_token=' /root/krill-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'public /health -> HTTP %{http_code}\n' --cacert $CA https://127.0.0.1/health echo "# Anonymous REST API request (no token) is refused:"
curl -s -o /dev/null -w 'anonymous /api/v1/cas -> HTTP %{http_code}\n' --cacert $CA https://127.0.0.1/api/v1/cas echo "# Authenticated request with the admin token:"
curl -s -o /dev/null -w 'authenticated /api/v1/cas -> HTTP %{http_code}\n' -H "Authorization: Bearer $TOKEN" --cacert $CA https://127.0.0.1/api/v1/cas

The health endpoint returns HTTP 200, the anonymous API request is refused (HTTP 403), and the authenticated request returns HTTP 200. There is no anonymous access to the management API.

8

Connect a parent and a publication repository

A newly created CA holds no resources until you connect it to a parent (the authority that delegates your IP space and AS numbers to you, typically your Regional Internet Registry) and a publication repository (where your certificate and ROAs are published for relying party software to fetch). You configure both from the CA in the web interface.

On the Parents tab, add your parent authority using the RFC 8183 exchange your registry provides.

On the Repository tab, configure the publication server where Krill will publish your RPKI objects.

Once a parent and a repository are configured, add ROAs from the ROAs tab (or with sudo -E krillc roas update --ca my-first-ca ...). Relying party software then starts fetching your certificate and ROAs from the repository.

9

Use your own domain and a trusted certificate (production)

The self-signed certificate is a convenience for getting started. For production, front Krill with your own DNS name and a CA-signed certificate, so browsers and clients trust it without any manual step.

  • Point a DNS record (for example rpki.example.com) at the VM public IP.
  • Replace /etc/nginx/tls/krill.crt and /etc/nginx/tls/krill.key with your CA-signed certificate and key, for example from Let's Encrypt or your internal CA.
  • Update service_uri in /etc/krill.conf to https://rpki.example.com/.
  • Reload nginx and restart Krill with sudo nginx -t && sudo systemctl reload nginx && sudo systemctl restart krill.service.

The service_uri is embedded in the RFC 8183 identity exchanges, so set it before you connect a parent or repository.

10

How Krill is wired

The Krill configuration at /etc/krill.conf binds the daemon to loopback only, sets the per-VM service URL, and points at the embedded data store. nginx is the only network-facing surface. It terminates TLS and reverse-proxies to the Krill HTTPS upstream.

sudo grep -E '^ip|^port|^service_uri|^data_dir|^log_type' /etc/krill.conf grep -nE 'listen 443 ssl|ssl_certificate|proxy_pass|proxy_ssl_verify|return 301' /etc/nginx/sites-available/sac-krill

The output shows Krill on ip = 127.0.0.1, port = 3000, the service_uri set to your VM public URL, the embedded data_dir under /var/lib/krill, and the nginx TLS and reverse-proxy directives (listen 443 ssl, ssl_certificate, proxy_pass to https://127.0.0.1:3000, proxy_ssl_verify off, and return 301 on :80).

11

Server components

  • RPKI CA: Krill (latest stable release, baked reproducibly, see /opt/krill/VERSION)
  • Daemon binding: 127.0.0.1:3000 (loopback only, own TLS behind the proxy)
  • Front proxy: nginx (TLS on :443, reverse proxy to the Krill HTTPS upstream, :80 redirects with 301 to HTTPS)
  • Data store: embedded store under /var/lib/krill (no external database)
  • CLI: krillc (authenticated with the admin token, KRILL_CLI_SERVER / KRILL_CLI_TOKEN)
  • Credential: per-instance admin token, generated on first boot, in /root/krill-credentials.txt (0600)
  • TLS certificate: self-signed, regenerated per VM on first boot (SAN = public IP + hostname), in /etc/nginx/tls/
  • Operating system: Ubuntu 24.04 LTS (patched at build)
  • License: MPL-2.0 (Krill, Copyright (c) NLnet Labs)
12

Managing the Krill service

sudo systemctl status krill.service --no-pager sudo systemctl restart krill.service
sudo journalctl -u krill.service -n 20 --no-pager sudo systemctl reload nginx

CA state, keys and ROAs live under /var/lib/krill. They persist across service restarts and VM reboots.

13

Security recommendations

  • Restrict the NSG. Allow TCP 443 (and 22 for administration) only from the networks you manage the CA from. The management interface does not need to be reachable from the whole internet.
  • Guard the admin token. It grants full control of the CA. Keep /root/krill-credentials.txt root-only. To rotate the token, update admin_token in /etc/krill.conf and restart Krill.
  • Use a trusted certificate (Step 9) for production, so browsers and clients validate the interface without a manual trust step.
  • Set service_uri before connecting a parent. It is embedded in the RFC 8183 exchanges, so changing it afterwards means redoing them.
  • Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
  • Back up /var/lib/krill to preserve your CA identity, keys, delegations and ROAs.
14

Support and Licensing

Krill is distributed under the Mozilla Public License 2.0 (Copyright (c) NLnet Labs). This SecureAnyCloud image installs the unmodified official release from the NLnet Labs apt repository.

SecureAnyCloud provides the packaging, hardening, per-instance admin token and TLS automation, and 24/7 support with a guaranteed 24-hour response SLA. Krill is an independent open-source project of NLnet Labs, and this image is not affiliated with or endorsed by NLnet Labs.

Deploy on Azure

Find Krill on Ubuntu 24.04 on the Azure Marketplace, published by SecureAnyCloud. Deploy from the Portal or the Azure CLI as shown above.

Need Help?

SecureAnyCloud provides 24/7 support with a guaranteed 24-hour response SLA. Contact us through the Azure Marketplace listing or at secureanycloud.com for deployment assistance, configuration guidance or production RPKI questions.

Deploy on Azure

Launch Krill on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure