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
krillsystem 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
:80returning a301redirect to HTTPS for every path except an unauthenticated/healthzendpoint (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.
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
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 StandardVerify 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.
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.txtThe 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.
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.
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-cakrillc 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.
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/casThe 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.
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.
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.crtand/etc/nginx/tls/krill.keywith your CA-signed certificate and key, for example from Let's Encrypt or your internal CA. - Update
service_uriin/etc/krill.conftohttps://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.
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-krillThe 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).
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)
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 nginxCA state, keys and ROAs live under /var/lib/krill. They persist across service restarts and VM reboots.
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.txtroot-only. To rotate the token, updateadmin_tokenin/etc/krill.confand restart Krill. - Use a trusted certificate (Step 9) for production, so browsers and clients validate the interface without a manual trust step.
- Set
service_uribefore 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/krillto preserve your CA identity, keys, delegations and ROAs.
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
Overview
This image runs Krill, the open-source Resource Public Key Infrastructure (RPKI) Certificate Authority from NLnet Labs. Krill lets a network operator run their own CA and publish Route Origin Authorizations (ROAs) for their IP prefixes. Other networks can then cryptographically verify which Autonomous System may originate each route.
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 to run. The RPKI state lives in the embedded store under /var/lib/krill.
The Krill daemon binds to the loopback interface only, on 127.0.0.1:3000, with its own TLS. nginx is the sole network-facing surface. It terminates public TLS on port 443 and reverse-proxies to the daemon, so you reach the web UI and REST API over HTTPS. Port 80 redirects to HTTPS and answers an unauthenticated health probe.
On the first boot of every deployed instance, a one-shot service generates a fresh admin token that is unique to that instance. It also regenerates the TLS certificate for that instance and records the token in /root/krill-credentials.txt with mode 0600. No shared or default credential ships in the image, and anonymous and wrong-token API calls are rejected.
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network, inbound port 443 from where you will reach the web UI and API, and inbound port 80 if you want the HTTP to HTTPS redirect and the health probe
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Connecting to your instance
This listing offers Krill as one product across its operating system variants. Connect over SSH as the default login user for the variant you launched:
- Ubuntu 24.04: SSH login user ubuntu
Launch the instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Krill. Select the SecureAnyCloud listing, choose Select, then choose Continue on the subscription summary.
Choose an instance type. The listing recommends m5.large, but Krill itself is light, so a smaller type is fine for evaluation. Select your key pair and configure the security group as described in Step 2. Leave the default root volume and launch the instance.
To launch from the command line instead, subscribe to the product in the console first. Then run the following command, substituting your own AMI ID, key pair, subnet and security group:
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-pair> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=krill}]'Security group ports
Krill on this image uses three ports. Configure the instance security group to allow:
- 22/tcp (SSH) from your management network
- 443/tcp (HTTPS) from where you will reach the web UI and REST API
- 80/tcp (HTTP) from the same source if you want the redirect to HTTPS and the unauthenticated health probe
The Krill daemon is never exposed directly. It listens only on 127.0.0.1:3000, and nginx proxies to it.
Connect over SSH
Connect to the instance as the login user for your variant (for Ubuntu 24.04 that is ubuntu):
ssh -i /path/to/key.pem ubuntu@<public-ip>Retrieve the admin token
The image generates a fresh admin token on first boot and stores it in a file that only the root user can read. Retrieve it with:
sudo cat /root/krill-credentials.txtThe file records the token and how to reach the instance. For example:
krill.host=<public-ip> krill.url=https://<public-ip>/ krill.admin_token=REDACTED_64_HEX_TOKENThe krill.admin_token value protects both the web UI and the full REST API. Store it somewhere safe.
Sign in to the web UI
Open the Krill web UI in your browser at https://<public-ip>/. The TLS certificate is self-signed and unique to your instance, so your browser warns on the first visit. Accept the warning to continue, or add your own CA-signed certificate as described in Step 9.
Paste the admin token from the previous step into the Password field and choose Sign In.
Create a Certificate Authority
After you sign in, you manage your Certificate Authorities. Create one from the web UI, or from the instance with the krillc client. The client reads its server and token from environment variables. Paste the admin token you retrieved earlier in place of <your-token>:
export KRILL_CLI_TOKEN=<your-token>
export KRILL_CLI_SERVER=https://127.0.0.1:3000/
sudo -E krillc add --ca my-caList your Certificate Authorities at any time. This command reads the token from the credentials file for you:
export
KRILL_CLI_TOKEN=$(sudo grep '^krill.admin_token=' /root/krill-credentials.txt | cut -d= -f2-)
export KRILL_CLI_SERVER=https://127.0.0.1:3000/
sudo -E krillc listThe Certificate Authority view lists your Route Origin Authorizations and lets you add new ones:
Connect a parent CA and publication repository
To issue real ROAs, connect your Certificate Authority to a parent on the Parents tab. The parent is typically your Regional Internet Registry, which delegates your resources.
On the Repository tab, configure the RPKI publication server that relying party software fetches your certificate and ROAs from.
Once the parent and repository are configured, add ROAs on the ROAs tab. They state which Autonomous System may originate each of your prefixes. Relying party software then fetches and validates them.
Health and status checks
Confirm the services are running:
systemctl is-active krill nginxAn unauthenticated health endpoint answers on the reverse proxy for load balancer and uptime checks:
curl -sk https://127.0.0.1/healthzThe baked Krill version is recorded on the image:
cat /opt/krill/VERSIONHTTPS with a custom domain
The image ships a self-signed certificate that is regenerated for each instance. For production, point a DNS name at the instance and replace the certificate with a CA-signed one.
Obtain a certificate for your domain, for example with a Let's Encrypt client. Install it into /etc/nginx/tls/krill.crt and /etc/nginx/tls/krill.key, set service_uri in /etc/krill.conf to your domain, and reload both services:
sudo cp /path/to/fullchain.pem /etc/nginx/tls/krill.crt
sudo cp /path/to/privkey.pem /etc/nginx/tls/krill.key
sudo sed -i 's#^service_uri = .*#service_uri = "https://<your-domain>/"#' /etc/krill.conf
sudo systemctl restart nginx krillBackup and maintenance
Krill's entire state lives in the embedded store under /var/lib/krill. To preserve your Certificate Authorities, keys and ROAs, back up the store while Krill is stopped, or snapshot the instance's EBS volume.
To update Krill, install the newer package from the official NLnet Labs repository and restart the service:
sudo apt-get update && sudo apt-get install --only-upgrade krillSupport
SecureAnyCloud provides this image with 24/7 technical support by email and chat. We can help with deployment, HTTPS and custom domain setup, configuring a parent CA and a publication server, creating and managing ROAs, and storage and upgrade planning.
All product and company names are trademarks or registered trademarks of their respective holders; use of them does not imply any affiliation with or endorsement by them.
Deploy on AWS
Launch Krill on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com