3.2. Podman

This guide describes how to deploy a pair of QKDLite nodes as rootless Podman containers, using the QKDLite Podman installer. Each node runs its components as containers inside a single Podman pod.

For devices with no route to the QKDLite registry, see Delivering QKDLite in a air-gapped environment (Podman).

3.2.2. Prerequisites

Hosts

  • Two Linux hosts, one per QKDLite node, each able to run rootless Podman.

    • Validated on Rocky Linux 10.2 and on Ubuntu 24.04 LTS

  • Network reachability between the two hosts on TCP port 2222, used for key replication between nodes

    Note

    Key replication uses a quantum-safe SSH connection between the two nodes on port 2222. How that connection is routed, for example directly across a LAN or through an existing VPN, is a network design decision and is not configured by the installer.

Tooling

  • Podman, as packaged by the distributions above. Validated with Podman 5.8.2 on Rocky Linux 10.2, and with the Podman package shipped by Ubuntu 24.04 LTS

  • OpenSSL

Security material

  • For a QKD KME deployment: the Root CA certificate, client certificate and client key issued by the KME operator. The client key must be unencrypted, as the QKDLite node runs unattended

Note

The certificates for the node’s own quantum-safe TLS front end are generated by the installer, so they are not required in advance.

Artifacts and access

  • Credentials for the QKDLite registry (qkdlite.azurecr.io)

  • The QKDLite Podman installer package, containing install_qkdlite_podman.sh, remove_qkdlite_podman.sh, qkdlite.conf, the place-kme-certs-here directory and the pqtls-nginx templates

3.2.3. Installing the dependencies

Install Podman and OpenSSL on both hosts.

Listing 3.21  console on both QKDLite nodes
$ sudo apt update && sudo apt install -y podman openssl
$ export PODMAN_USERNS=keep-id

On Rocky Linux, install the same packages with dnf.

Listing 3.22  console on both QKDLite nodes
$ sudo dnf install -y podman openssl
$ export PODMAN_USERNS=keep-id

3.2.4. Quick Installation

The installer is run on the main node first, then on the remote node. Every secret must be identical on both nodes, so the main node generates them and the remote node reuses the same values.

The installer can be re-run at any time. It skips every step that is already complete, so it is also the way to resume an interrupted installation.

3.2.4.1. Main node

  1. Edit qkdlite.conf and set the topology values for this node. The file ships with the main node’s values as defaults.

    Listing 3.23  qkdlite.conf on QKDLite main node
    POD_NAME=pod-a1
    REMOTE_POD_NAME=pod-b1
    LOCAL_SAE_NAME=SAE_A
    REMOTE_SAE_NAME=SAE_B
    HSM_SLOT=1234
    UPSTREAM_PREFIX=ALICE
    REMOTE_POD_IP="<remote node's IP address>"
    LOCAL_IP="<this node's own IP address>"
    

    Note

    The Security Application Entity (SAE) name is required for the proper labelling of quantum keys to be provided via the ETSI server. In this example the main node uses SAE_A as its local name and SAE_B as the remote name. The remote node uses the two values the other way round.

  2. Make the installer executable and run it.

    Listing 3.24  console on QKDLite main node
    $ chmod +x install_qkdlite_podman.sh remove_qkdlite_podman.sh
    $ ./install_qkdlite_podman.sh
    
  3. State whether this device can reach the registry, then enter the registry credentials used to pull the QKDLite images. Answer N for a normal installation.

    Listing 3.25  console on QKDLite main node
    ==> Step 1: Container images
    Is this an offline (airgapped) install, with the images already loaded? [y/N]: N
    Container registry to pull images from [qkdlite.azurecr.io]:
    Registry token name: user
    Registry token/password:
    Login Succeeded
    

    Note

    Answer y only on a device with no route to the registry, where the images have already been loaded. See Delivering QKDLite in a air-gapped environment (Podman).

  4. Choose whether to save a copy of the images for transfer into an air-gapped environment. Answer N unless you are preparing such a transfer.

    Listing 3.26  console on QKDLite main node
    Do you need an offline copy of the images to transfer into an airgapped environment? [y/N]:
    

    Answering y saves every image to ~/qkdlite-images as it is pulled, ready to transfer to the air-gapped device.

  5. Confirm the topology values. Any value already set in qkdlite.conf is used without prompting.

    Listing 3.27  console on QKDLite main node
    ==> Step 2: Topology configuration
    This device's pod name (e.g. pod-a1):
    Remote peer's pod name (e.g. pod-b1):
    This device's local SAE name (e.g. SAE_A):
    Remote peer's SAE name (e.g. SAE_B):
    HSM slot number (e.g. 1234):
    Remote peer's real IP (leave blank if same host):
    This device's own real IP (for the 1-way TLS proxy cert):
    Upstream prefix for 1-way TLS (ALICE or BOB):
    
  6. Choose the source of the quantum keys. Answer v to generate keys from the QRNG source, or q to request keys from a QKD KME. This question is asked on every run, so a node can be switched later.

    Listing 3.28  console on QKDLite main node
    QRNG or real QKD KME mode? [v/q]:
    

    For q, see QKD KME mode below.

  7. Enter the secrets. On the main node, press Enter at each prompt to generate a value.

    Listing 3.29  console on QKDLite main node
    ==> Step 3: Secrets
    Type 'first' for the first device being set up (usually Alice), or 'second' to pair with an existing one [first/second]: first
    SO_PIN [press Enter to auto-generate, or type your own]:
      Generated SO_PIN: 12345678
    

    The installer asks the same for USER_PIN, TRANSPORT_KEY_DATA, BOOTSTRAP_KEY_DATA, SSH_PASSPHRASE and TLS_CERT_PASSPHRASE.

    Note

    The Transport Key and the Bootstrap Key must be identical on both nodes, otherwise key replication fails. The installer writes every generated value to qkdlite_secrets.txt next to the pod directory, for use when installing the remote node. Keep this file private.

  8. The installer creates the pod, pulls the images and starts the containers. It then displays this node’s public key for key replication.

    Listing 3.30  console on QKDLite main node
    ==> Step 6: SSH cross-registration
    This device's public SSH key, copy this to the remote device:
      ecdsa-sha2-nistp384 AAAA...
    Paste the remote device's public SSH key here
    (you can find it in its qkdlite_secrets.txt)
    Or press Enter to skip, if not available yet:
    

    Press Enter to skip for now: the remote node does not exist yet.

3.2.4.2. Remote node

  1. Edit qkdlite.conf on the remote node, swapping the local and remote values.

    Listing 3.31  qkdlite.conf on QKDLite remote node
    POD_NAME=pod-b1
    REMOTE_POD_NAME=pod-a1
    LOCAL_SAE_NAME=SAE_B
    REMOTE_SAE_NAME=SAE_A
    HSM_SLOT=5678
    UPSTREAM_PREFIX=BOB
    REMOTE_POD_IP="<main node's IP address>"
    LOCAL_IP="<this node's own IP address>"
    
  2. Copy the six secrets from the main node’s qkdlite_secrets.txt (SO_PIN, USER_PIN, TRANSPORT_KEY_DATA, BOOTSTRAP_KEY_DATA, SSH_PASSPHRASE and TLS_CERT_PASSPHRASE) into this node’s qkdlite.conf.

  3. Run the installer and answer second at the device role prompt. With the secrets already in place, the installer reuses them instead of generating new ones.

    Listing 3.32  console on QKDLite remote node
    $ ./install_qkdlite_podman.sh
    
  4. When prompted, paste the main node’s public SSH key.

3.2.4.3. Completing key replication

Run the installer once more on the main node and paste the remote node’s public SSH key, which is shown in its output and in its qkdlite_secrets.txt. Both nodes can then authenticate to each other, and key replication begins.

Listing 3.33  console on QKDLite main node
$ ./install_qkdlite_podman.sh

3.2.5. QKD KME mode

To request keys from a QKD KME instead of the QRNG source, answer q at the key source prompt. The installer then asks for the KME URL and the peer SAE name registered on that KME, which differ per node.

Listing 3.34  console on QKDLite node
QRNG or real QKD KME mode? [v/q]: q
QKD KME URL (e.g. https://kme1.example.com:443):
This KME's registered peer SAE name (e.g. SAE_PEER):

Place the CA.crt, client.crt and client.key files provided by the KME operator into the place-kme-certs-here directory next to the installer, using those exact file names. The installer copies them into the node’s configuration. If the files are missing, the installer stops and reports where to put them.

Note

client.key must be an unencrypted PEM file, as the QKDLite node runs unattended and cannot supply a passphrase. An encrypted key can be converted with openssl pkey -in <encrypted key> -out client.key.

3.2.6. Boot-time auto-start

Every container is created with --restart=always, and the installer enables podman-restart.service for the current user. One step requires sudo and is therefore not performed by the installer. Run it once on each node.

Listing 3.35  console on both QKDLite nodes
$ sudo loginctl enable-linger <username>

Without this, the user’s services stop when the user logs out, and the containers do not start after a reboot.

3.2.7. Verifying the Installation

  1. Confirm that every container in the pod is running.

    Listing 3.36  console on both QKDLite nodes
    $ podman ps -a --pod --format "table {{.PodName}}\t{{.Names}}\t{{.Status}}"
    

    All containers should report Up, and the engine and key-sync containers should report healthy.

  2. Confirm that keys are being created and replicated.

    Listing 3.37  console on QKDLite main node
    $ podman logs <engine container name>
    

    The log reports the number of keys held locally, and reports success for each key created locally and replicated to the remote node.

  3. Confirm that both nodes hold the same key. Request a key on the main node, then retrieve the same key by its identifier on the remote node.

    Listing 3.38  console on QKDLite main node
    $ curl -s http://127.0.0.1:8000/api/v1/keys/SAE_B/enc_keys
    
    Listing 3.39  console on QKDLite remote node
    $ curl -s "http://127.0.0.1:8000/api/v1/keys/SAE_A/dec_keys?key_ID=<key_ID from the main node>"
    

    Both nodes return the same key value. This check uses the loopback address on the node itself. See REST APIs for the key delivery interface offered to external Security Application Entities (SAEs).

Note

The pod publishes the ETSI server on 127.0.0.1:8000, the key replication service on port 2222, and the quantum-safe TLS front end on port 8443.

3.2.8. Upgrading

Re-run the installer to apply changes made in qkdlite.conf. Steps that are already complete are skipped, and containers that already exist are left in place.

Listing 3.40  console on QKDLite node
$ ./install_qkdlite_podman.sh

3.2.9. Removing QKDLite

To remove the containers, the pod, its data directory and the local images, run the removal script. It asks for confirmation first.

Listing 3.41  console on QKDLite node
$ ./remove_qkdlite_podman.sh