Networking Azure

Krill on Ubuntu 24.04 on Azure User Guide

| Product: Krill on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Krill on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. 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 are allowed to originate their prefixes. Krill can run as a delegated child under a parent authority such as a Regional Internet Registry, giving operators direct control over the RPKI objects that protect their routing.

Krill is a single self contained Rust binary set — the krill daemon and the krillc command line client — with an embedded data store (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 and terminates TLS on port 443, reverse proxying to the Krill HTTPS upstream. On the very first boot this image generates a unique administrative token for this specific VM, sets the Krill service URL to https://<your public ip>/, and regenerates a self signed TLS certificate whose 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 is included:

  • 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 network exposed

  • nginx terminating TLS on :443 and reverse proxying the web UI and REST API to the Krill upstream

  • Port :80 returns 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) — no shared secret, no default login

  • A self signed TLS certificate regenerated per VM on first boot (SAN includes the VM public IP + hostname) — replace it with your own CA signed certificate for production

  • Ubuntu 24.04 LTS base with latest security patches applied at build time and unattended security upgrades enabled

  • Azure Linux Agent for seamless cloud integration and SSH key injection

  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region

  • 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. This image runs the CA out of the box; connecting a parent and a repository is done 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 CPU light and needs no GPU.

Step 1: Deploy from the Azure Portal

Search Krill in Marketplace, select the cloudimg publisher, click Create. NSG rules: TCP 22 (admin), TCP 443 (web UI and REST API over HTTPS) and TCP 80 (HTTP to HTTPS redirect and health probe) from the networks you manage the CA from.

Step 2: Deploy from the Azure CLI

RG="krill-prod"; LOCATION="eastus"; VM_NAME="krill-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/krill-ubuntu-24-04/versions/<version>"
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
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --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

Step 3: Verify the Krill and nginx services

Connect over SSH, then confirm 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.

krill.service and nginx.service both active; krill --version prints the baked release; ss shows Krill bound to 127.0.0.1:3000 loopback only, with nginx public on :443 and :80

Step 4: Retrieve your per instance admin token

The unique admin token, the service URL and quick start commands are generated on the first boot and stored in a root only file. Read it over SSH:

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

The ls -l confirms 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.

The per instance krill-credentials.txt file shown by ls -l as 0600 root-only; a unique admin token is generated on first boot and retrieved with sudo cat

Step 5: Log in to the Krill web interface

Open https://<your public ip>/ in a browser. Because the image ships a self signed certificate, your browser will warn on first visit — accept it 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 click Sign In.

The Krill web interface sign in page served over HTTPS, asking for the admin token as the password

Once signed in, Krill shows the Certificate Authority dashboard. The example below shows a Certificate Authority named cloudimg-demo with tabs for ROAs, ASPAs, Parents and Repository, and the controls to add and analyse ROAs. This is where you manage the RPKI objects for your resources.

The Krill dashboard after login showing the Certificate Authority cloudimg-demo, with the ROAs, ASPAs, Parents and Repository tabs and the Add ROA control

Step 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 and authenticate with your admin token, then create a Certificate Authority and read it back. Creating a CA and confirming 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 — proving the Certificate Authority was created and persisted in Krill's embedded store.

krillc creates a Certificate Authority and reads it back: krillc list shows the CA handle and krillc show prints its details, proving it persisted in Krill's embedded store

Step 7: Confirm the API rejects anonymous access

The /health and /healthz endpoints are served without authentication (ideal for load balancer and Azure health probes) and return HTTP 200. The REST API, in contrast, 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 we 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.

curl of /health returns HTTP 200 over TLS; an anonymous /api/v1/cas request is refused with HTTP 403; the same request with the admin token returns HTTP 200

Step 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). Both are configured from the CA in the web interface.

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

The Parents tab of the cloudimg-demo Certificate Authority in the Krill web interface, with the controls to add and refresh a parent authority

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

The Repository tab of the cloudimg-demo Certificate Authority in the Krill web interface, where the publication repository is configured

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

Step 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/; then reload nginx and restart Krill with sudo nginx -t && sudo systemctl reload nginx && sudo systemctl restart krill.service. Note that the service_uri is embedded in the RFC 8183 identity exchanges, so set it before you connect a parent or repository.

Step 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/cloudimg-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 + 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).

Step 11: Server components

Component Version / Detail
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 -> 301 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 first boot, /root/krill-credentials.txt (0600)
TLS certificate self signed, regenerated per VM first boot (SAN = public IP + hostname), /etc/nginx/tls/
Operating system Ubuntu 24.04 LTS (patched at build)
License MPL-2.0 (Krill, Copyright (c) NLnet Labs)

Step 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 and persist across service restarts and VM reboots.

Step 13: Security recommendations

  • Restrict the NSG. Allow TCP 443 (and 22 for admin) 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, and rotate the token by updating admin_token in /etc/krill.conf and restarting 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; changing it afterwards means re-doing 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.

Step 14: Support and Licensing

Krill is distributed under the Mozilla Public License 2.0 (Copyright (c) NLnet Labs). This cloudimg image installs the unmodified official release from the NLnet Labs apt repository. cloudimg 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 cloudimg. Deploy from the Portal or the Azure CLI as shown above.

Need Help?

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