Deploy Confidential Container (CoCo) Workloads on AMD SEV-SNP Platform

Prev Next

1.0 Introduction

This article describes how to deploy and run Confidential Containers (CoCo) using Fortanix Confidential Computing Manager (CCM) and Fortanix Data Security Manager (DSM).

The solution is based on the open-source CNCF Confidential Containers (CoCo) and Kata Containers projects, with Fortanix components integrated on top. It runs containerized applications in a confidential computing environment. Fortanix DSM protects the encryption keys used to encrypt the container image, while Fortanix CCM verifies the confidential workload through remote attestation.

2.0 Definitions

  • Fortanix Node Agent - The Fortanix Node Agent software enables the registration of compute nodes to CCM when installed on a compute node. It assists in the verification of hardware and platform software running on compute nodes and application attestation.

  • Container Registry: A repository used to store and distribute container images. In this guide, the container registry stores the encrypted container image and makes it available to the Kubernetes environment for deployment.

  • TEE (Trusted Execution Environment): A hardware-isolated environment that protects code and data during execution from unauthorized access, including access from the host operating system.

  • Confidential Containers (CoCo): An open-source technology for running Kubernetes pod in confidential computing environments.

  • Kata Containers: The runtime environment used by Confidential Containers to provide a VM-based isolation for containers.

  • ccm_as: A Fortanix Attestation Service module implemented in the CoCo Attestation Agent (AA) that collects TEE (Trusted Execution Environment) attestation evidence, performs attestation with Fortanix CCM, and obtains the application certificate issued by CCM.

  • ccm_kbc: A Fortanix Key Broker Client (KBC) module implemented in the Confidential Data Hub (CDH) that communicates with Fortanix DSM for secure key operations.

  • Key Encryption Key (KEK): A key stored and managed in Fortanix DSM that protects encryption keys used for the container image.

  • Layer Encryption Key (LEK): The key used for the container-layer encryption operation. The LEK remains protected and non-exportable in Fortanix DSM.

  • Mutual TLS (mTLS): A TLS authentication mechanism in which both the client and server authenticate each other using certificates.

  • Fortanix Data Security Manager (DSM): A platform that provides centralized key management and cryptographic operations for protecting data. In this guide, DSM securely stores the non-exportable KEK and performs the required key operation to unwrap the LEK used to decrypt the protected container image.

  • Fortanix Confidential Computing Manager (CCM): A centralized control plane for managing and attesting confidential workloads. In this guide, CCM verifies the measurements of the confidential workload and, after successful attestation, issues a short-lived X.509 application certificate used by the workload to authenticate to DSM.

  • Fortanix CoCo Encryption Tool: A tool (coco-keyprovider Docker image) used to encrypt container images. It uses Fortanix DSM to protect the encryption key used to encrypt the container image.

  • Fortanix CoCo Helm Chart: A Helm chart used to install and configure the Kata artifacts required to run Confidential Containers in a Kubernetes environment, including the image, kernel, and runtime class configuration. The CoCo AA integrated with the ccm_as module and the CDH integrated with the ccm_kbc module are embedded in the Kata guest image.

3.0 Prerequisites

Before deploying Confidential Containers, ensure that the required hardware, software, and Fortanix services are available.

3.1 Hardware and Software Requirements

You will require a Linux machine to containerize the application and create the encrypted container image. The machine is recommended to meet the following minimum requirements:

COMPONENT

MINIMUM REQUIREMENT

CPU

16 cores

Memory

128 GB

Disk

More than 100 GB

NOTE

The required disk space depends on the size of the application or model.

Operating System

Ubuntu 24.04 LTS

Required software

docker.io, jq, python3

3.2 Networking Requirements

The machine must have network access to Fortanix DSM to perform the required key operations during container image encryption.

  • Protocol: HTTPS

  • Port: 443

  • Destination: DSM endpoint URL

    • DSM SaaS: Use the endpoint of your DSM region.

    • DSM on-premises: Use the appropriate DSM endpoint configured.

3.3 Confidential Computing Host Requirements

The end user requires a Confidential Computing Host, which is a bare-metal host with hardware and platform support for confidential computing. The host must support Advanced Micro Devices (AMD) Secure Encrypted Virtualization – Secure Nested Paging (SEV-SNP) platform.

The host must be configured with the required hardware, firmware, operating system, kernel, and confidential-computing prerequisites to support launching confidential VMs.

For NVIDIA-validated hardware configurations, refer to the supported hardware tables for AMD SEV-SNP here.

NOTE

The Fortanix CoCo Helm chart does not configure the host kernel, firmware, or other host-level confidential-computing settings. Complete these host-level prerequisites before installing the Fortanix CoCo Helm Chart.

The following AMD SEV-SNP environments are supported:

COMPONENT

SUPPORTED CONFIGURATION

CPU

AMD SEV-SNP

Host OS

Ubuntu 26.04.1 LTS

Host kernel

6.17.0

Operating System

Ubuntu 24.04 LTS

GPU

NVIDIA Hopper, NVIDIA Blackwell, RTX PRO6000

For more information, refer to Supported Platforms.

3.4 Kubernetes Requirements

You must have a Kubernetes cluster installed on the confidential computing host before installing the Confidential Containers components.

The following Kubernetes software versions are supported:

COMPONENT

SUPPORTED CONFIGURATION

Kubernetes

1.24 or later

Containerd

1.7 or later

Helm

3.8 or later

SELinux

Disabled

1 Node

At least one node with the node.kubernetes.io/worker label

NOTE

Kind and Minikube are not recommended for this deployment because QEMU is known to be incompatible with these cluster environments. Fortanix recommends using kubeadm for setting up the Kubernetes cluster.

Reference: https://confidentialcontainers.org/docs/getting-started/prerequisites/software/

4.0 Architecture

Figure 1: Architecture flow

4.1 Architecture Flow

The following steps describe the end-to-end process for deploying an encrypted application or model as a Confidential Container using Fortanix CCM, Fortanix DSM, and NVIDIA GPU.

  1. Containerize the Application: Containerize the application or model for deployment in the confidential environment. Refer to Section 3.1: Hardware and Software Requirements.

  2. Configure DSM for Secure Key Release: Configure the DSM account to securely release the cryptographic keys required to access the protected container image. For detailed instructions, refer to Section 6.0: Configure Fortanix DSM.

  3. Encrypt the Container Image: Encrypt the container image using the Fortanix Encryption Tool, which uses DSM to protect the application or model. For detailed instructions, refer to Section 7.0: Prepare the Encrypted Container Image.

  4. Publish to the Container Registry: Push the encrypted container image to a container registry accessible by your Kubernetes environment. For detailed instructions, refer to Section 7.0: Prepare the Encrypted Container Image.

  5. Configure CCM: Configure the CCM application for application registration, node enrollment, and attestation. For detailed instructions, refer to Section 5.0: Configure Fortanix CCM.

  6. Prepare the Confidential Environment: Configure the Kubernetes environment on a supported TEE platform, such as AMD SEV-SNP. For more information, refer to Section 8.0: Prepare the Confidential Computing Environment.

  7. Register Application Measurements: Register the application measurements required for CCM to verify the confidential workload. For detailed instructions, refer to Section 9.0: Register Application Measurements with CCM.

  8. Deploy the Confidential Container: Configure and deploy the encrypted container image using Kubernetes. For detailed instructions, refer to Section 10.0: Deploy the Confidential Container.

  9. Attest and Run the Workload: Attest the workload and, after successful attestation and authentication with DSM, run the application or model inside the confidential environment.

5.0 Configure Fortanix CCM

Configure Fortanix CCM to register the confidential workload, enroll the compute node, and enable workload attestation.

5.1 Create an Account

A Fortanix Armor account is the top-level container for Fortanix CCM, builds, and nodes. An account is generally associated with an organization, rather than an individual. Different accounts are fully isolated from each other.

To get started with Fortanix CCM you must first sign up on Fortanix Armor and create an account. If you already have an existing account, log in to that account.

For more information on how to sign up, log in, and create a Fortanix Armor account, refer to Getting Started with Fortanix Armor.

5.2 Create a Group

In Fortanix CCM, a group is a collection of users and objects that helps users manage identities, create collaborating groups, and organize and secure applications, datasets, and workflows that belong to the group.

  1. Create a Fortanix Armor IAM group. For detailed instructions, refer to Fortanix Armor Identity and Access Management.

5.3 Download Zone CA Certificate from your Fortanix CCM Account

NOTE

You must download the Zone CA Certificate from your Fortanix CCM account for upload to the Fortanix DSM account to enable Secure Key Release (SKR) functionality. The SKR feature ensures that cryptographic keys are released from Fortanix DSM only when the application proves it is running in a trusted and secure environment, thereby protecting both the data and model.

Perform the following steps to download the Zone CA Certificate from your Fortanix CCM user interface (UI):

  1. In the CCM UI left navigation panel, click Infrastructure → COMPUTE NODES → AMD SEV-SNP, and then click ADD NODE.

  2. On the Enroll Compute Node dialog box, click DOWNLOAD ZONE CA. The downloaded certificate will be uploaded by the Publisher (Model Owner) to Fortanix DSM in Section 5.0: Configure Fortanix DSM.

    Figure 2: Download Zone CA

5.4 Create an Application in CCM

Perform the following steps to add an application:

  1. In the CCM UI left navigation panel, click Applications.

  2. On the ACTIVE APPLICATIONS tab, click ADD APPLICATION to add an application.

  3. In the Add Application form,

    1. Under Select application type, select Confidential Container - CoCo.

    2. Under Select platform type, select AMD SEV-SNP.

    3. Click NEXT.

  4. In the Add Application Confidential Container - CoCo form:

    1. Application name: Enter the name of the application.

    2. Description (optional): Enter the application’s description.

    3. Group: Select the required group from the drop down menu.

    4. Certificate Configuration: Add certificates using ADD CERTIFICATE. An application can request a certificate from Fortanix CCM when the application starts. The certificates are signed by the Fortanix CCM Certificate Authority, which issues certificates only to trusted workloads presenting a valid attestation.

      • Domain: Enter the allowed domain for the application. This is the domain that appears in the TLS certificate issued by Fortanix CCM.

      • Type: Select the certificate type for the application from the drop down menu.

  5. Click ADD APPLICATION to configure the application.

The application is added for approval and appears on the Applications page. You can approve the request from the Tasks page.

After the application is created, deploy the workload on a platform that supports AMD SEV-SNP and obtain the required attestation measurements. These values are used when creating the application build for the Confidential Container - CoCo application on AMD SEV-SNP in Fortanix CCM.

For detailed instructions on creating an AMD SEV-SNP application, refer to Add Coco - AMD SEV-SNP Application.

6.0 Configure Fortanix DSM

Configure Fortanix DSM to create the account, group, application, and security objects required to protect the container image encryption keys.

6.1 Create an Account and Group

A Fortanix DSM account is the top-level container for security objects managed by Fortanix DSM. An account is generally associated with an organization, rather than an individual. Security objects, groups, and applications belong to exactly one account. Different accounts are fully isolated from each other.

To get started with Fortanix DSM you must first sign up in and create an account. If you already have an existing account, log in to that account.

6.2 Create an Application (app) with Trusted CA Authentication

Create an application to authenticate to Fortanix DSM using a Transport Layer Security (TLS) client certificate signed by a Trusted Certificate Authority (CA). This app will be used for decrypting the model and weights when the Confidential Virtual Machine (CVM) launches.

  1. Click the Groups menu item from the DSM left navigation panel and select the group you created in Section 6.1: Create an Account and Group to go to its detailed view.

  2. Click APPS → ADD APP to create a new application.

    Figure 3: Create an app

  3. Follow the steps here to configure a new app with the following details:

    1. Interface: REST API

    2. Authentication Method: Trusted CA

    3. DNS Name: my-server

    4. Upload Trusted CA Cert: Upload the Zone CA Certificate downloaded and shared by Consumer (Enterprise) in Section 5.3: Download Zone CA Certificate from your Fortanix CCM Account.

  4. Click SAVE.

    Figure 4: App with Trusted CA authentication

6.3 Create an App with API Key Authentication

Create an application to authenticate to Fortanix DSM using an API key. This API key is a random, secret token that identifies an app in the same way as a password identifies a user. This app will be used for encrypting the model and weights.

  1. Repeat Steps 1-2 from previous Section 6.2: Create an Application (app) with Trusted CA Authentication.

  2. Follow the steps here to configure a new app with the following details

    1. Interface: REST API

    2. Authentication Method: API Key

  3. Click SAVE.

    Figure 5: App with API key authentication

3. Click SAVE.

7.0 Prepare the Encrypted Container Image

The following sections describe the steps to encrypt the container image using the Fortanix CoCo Encryption Tool (coco-keyprovider Docker image) with keys managed by Fortanix DSM. The encrypted image is then published to a container registry so that it can be pulled by your Kubernetes cluster.

7.1 Containerize the Application

Create a container image for the application that will run in the Confidential Container environment.

For example, the following image can be used for testing

nginx:latest

The same procedure can be used with an application-specific container image.

7.2 Configure DSM Authentication for Image Encryption

Create a JSON configuration file containing the Fortanix DSM endpoint and API key for the DSM application used for container image encryption.

For example (JSON):

{
  "api-endpoint": "<DSM_URL>",
  "api-key": "<DSM_API_KEY>"
}

Where,

  • <DSM_API_KEY>: The API key generated for the DSM application in Section 6.0: Configure Fortanix DSM.

  • <DSM_URL>: The Fortanix DSM endpoint URL.

    • DSM SaaS: Use the endpoint for your DSM region.

    • DSM on-premises: Use the configured DSM endpoint.

7.3 Encrypt the Container Image

Run the following command which pulls Fortanix CoCo Encryption Tool Docker image and encrypts the application container image. The tool publishes the encrypted image to the given output image registry:

docker run -v <path>/dsm-config.json:/dsm-config.json:ro \
  -v ~/.docker/config.json:/root/.docker/config.json \
  fortanix/coco-keyprovider:0.2.12 /dsm-encrypt.sh \
  --fortanix-dsm-config /dsm-config.json \
  --input-image docker://<DOCKER_REPO>:<DOCKER_TAG> \
  --output-image docker://<DOCKER_REPO>:<DOCKER_TAG> \
  --kek-name <KEK_NAME> \
  --kek-mode shared

Where,

  • --fortanix-dsm-config <file>: The DSM configuration file containing the API Key and the DSM endpoint.

  • --input-image <ref>: The source container image and tag.

  • --output-image <ref>: The destination for the encrypted container image and tag.

  • --socket <host:port>: The keyprovider gRPC socket. The default is 127.0.0.1:50000.

  • --keyid <uuid|kbs:///dsm/key/uuid>: Reuses an existing DSM KEK. By default, a new KEK is created. When --keyid is specified, one KEK is used for the whole image.

  • --kek-name <name>: The DSM object name for the KEK or KEKs created. In per-layer mode, the layer index is appended to the name, such as <name>-0, <name>-1, and so on.

  • --kek-mode <shared|per-layer>: The KEK configuration for the image. shared uses one KEK to wrap every encrypted layer, while per-layer creates a separate KEK for each encrypted layer.

  • --encrypt-layer <spec>: The layers to encrypt. Use all to encrypt every layer or specify comma-separated zero-based layer indexes. Negative indexes count from the end. For example:

    • all: encrypts every layer

    • 0,1: encrypts the first two layers

    • -1: encrypts the last layer only

  • --dest-tls-verify <true|false>: Specifies whether to verify TLS certificates for Docker destinations. The value is passed through to Skopeo.

  • --ready-timeout <seconds>: The keyprovider startup wait time. The default is 30 seconds.

  • -h, --help: Displays the command usage and available options.

The encryption tool generates or uses a KEK in DSM to protect the LEKs generated by Skopeo to encrypt the container image layers. You can verify the generated keys in the DSM UI.

NOTE

Only the encrypted container image is shared, you do not need to share the plaintext container image or protected application artifacts

8.0 Prepare the Confidential Computing Environment

You must prepare the confidential computing and Kubernetes environment before deploying the encrypted container. The environment consists of a confidential-computing host, a Kubernetes cluster, the Fortanix Node Agent, the NVIDIA GPU Operator, and Fortanix CoCo Helm Chart.

The following procedures must be completed on the host and Kubernetes environment.

8.1 Prepare the Confidential Computing Host

Ensure that the confidential-computing host meets the requirements described in Section 3.3: Confidential Computing Host Requirements and is configured according to the applicable AMD SEV-SNP host prerequisites.

8.2 Set Up the Kubernetes Cluster

Ensure that the Kubernetes environment meets the requirements described in Section 3.4: Kubernetes Requirements before proceeding with the following steps.

8.3 Enroll Node with CCM

The Fortanix Node Agent enables compute-node registration with Fortanix CCM and supports application attestation and workload visibility. It verifies the integrity of the underlying hardware and software running on the node. The Fortanix Node Agent runs on the host and provides the communication path between the CoCo Attestation Agent and Fortanix CCM.

For detailed instructions on how to download and install the Fortanix Node Agent on your confidential computing host and enroll a compute node with CCM, refer to Enroll a Compute Node Using Bare Metal - AMD SEV-SNP.

8.4 Install the NVIDIA GPU Operator

Install the NVIDIA GPU Operator on the Kubernetes cluster to enable NVIDIA GPU resources for the Confidential Containers workload as described in the following steps:

NOTE

Ensure that NVIDIA GPU drivers are not installed or loaded on the host before installing the NVIDIA GPU Operator

  1. Run the following command to label the Kubernetes node for GPU passthrough:

    kubectl label node <NODE_NAME> \
      nvidia.com/gpu.workload.config=vm-passthrough
    

  2. Run the following commands to add the NVIDIA Helm repository, which provides the NVIDIA GPU Operator Helm chart:

    helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
    helm repo update
    

  3. Run the following command to install the NVIDIA GPU Operator:

    helm install --generate-name \
      -n gpu-operator --create-namespace \
      nvidia/gpu-operator \
      --set sandboxWorkloads.enabled=true \
      --set sandboxWorkloads.mode=kata \
      --set nfd.enabled=true \
      --set nfd.nodefeaturerules=true \
      --version=v26.3.1
    
  4. Enable the KubeletPodResourcesGet and RuntimeClassInImageCriApi feature gates in the Kubernetes cluster:

    1. Open the Kubelet configuration file, for example:

      sudo vi /var/lib/kubelet/config.yaml

    2. Add the following configuration to the file:

      volumeStatsAggPeriod: 0s
      featureGates:
        KubeletPodResourcesGet: true
        RuntimeClassInImageCriApi: true
      

    3. Run the following command to restart the Kubelet service:

      sudo systemctl restart kubelet

  5. Run the following command to verify that the NVIDIA GPU Operator pods are running:

    kubectl get pods -n gpu-operator

    Verify that the required GPU Operator pods are in the Running state. Pod names and restart counts may vary.

    Example output:

    NAME                                                      READY   STATUS    RESTARTS   AGE
    gpu-operator-1783520009-node-feature-discovery-gc-66d748c4dtvbb   1/1     Running   1 (100s ago)   15m
    gpu-operator-1783520009-node-feature-discovery-master-58cckrzql   1/1     Running   1 (100s ago)   15m
    gpu-operator-1783520009-node-feature-discovery-worker-xpcxg       1/1     Running   1 (100s ago)   15m
    gpu-operator-67866486c9-j8t8p                                     1/1     Running   1 (100s ago)   15m
    nvidia-cc-manager-54vwm                                           1/1     Running   1 (100s ago)   15m
    nvidia-kata-sandbox-device-plugin-daemonset-7zvqh                 1/1     Running   1 (100s ago)   15m
    nvidia-sandbox-validator-kdrdf                                    1/1     Running   0              66s
    nvidia-vfio-manager-schl8                                         1/1     Running   0              15m
    

    NOTE

    The nvidia-vfio-manager-* pods do not start if the NVIDIA driver (nvidia-driver) is already installed on the host. Follow the steps in Removing the Driver - NVIDIA Driver Installation Guide to remove the driver. A system reboot is required after removing the driver.

8.5 Install Fortanix CoCo Helm Chart

Install the Fortanix CoCo Helm Chart on the Kubernetes cluster. Helm chart installs the Fortanix-specific Confidential Containers runtime, including the runtime configurations required for AMD SEV-SNP workloads.

Perform the following steps:

  1. Run the following command to install the Fortanix CoCo Helm chart:

    helm install coco \
      oci://ghcr.io/confidential-containers/charts/confidential-containers \
      --version 0.21.0 \
      --namespace coco-system \
      --create-namespace \
      --set kata-as-coco-runtime.image.reference=<IMAGE_REFERENCE> \
      --set kata-as-coco-runtime.image.tag=<IMAGE_TAG>

    Where,

    • <IMAGE_REFERENCE>: The image reference for the Beta release is fortanix/kata-deploy.

    • <IMAGE_TAG>: The image tag for the Beta release is 0.21.0-fortanix-ccm-0.2.12.

  2. Run the following command to verify that the Fortanix CoCo DaemonSet is successfully deployed:

    kubectl -n coco-system rollout status ds/kata-as-coco-runtime

    The command should report that the DaemonSet rollout has completed successfully.

    Expected output:

    The command should report that the DaemonSet rollout has completed successfully
  3. Run the following command to verify the Fortanix CoCo logs:

    kubectl -n coco-system logs \
      -l name=kata-as-coco-runtime \
      --tail=50
    

    Verify that the logs indicate that the required runtimes were configured successfully and the node became ready.

    Example output:

    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] Configuring runtime for shim: qemu-nvidia-gpu-snp-runtime-rs
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] configure_containerd_runtime: Writing to "/host/opt/kata/containerd/config.d/kata-deploy.toml", pluginid="io.containerd.cri.v1.runtime"
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] Successfully configured runtime for shim: qemu-nvidia-gpu-snp-runtime-rs
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] Configuring runtime for shim: qemu-snp
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] configure_containerd_runtime: Starting for shim=qemu-snp
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] configure_containerd_runtime: Writing to "/host/opt/kata/containerd/config.d/kata-deploy.toml", pluginid="io.containerd.cri.v1.runtime"
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] Successfully configured runtime for shim: qemu-snp
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] Configuring runtime for shim: qemu-sev[2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] configure_containerd_runtime: Starting for shim=qemu-snp
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] configure_containerd_runtime: Writing to "/host/opt/kata/containerd/config.d/kata-deploy.toml", pluginid="io.containerd.cri.v1.runtime"
    
    [2026-09-16T05:50:49Z INFO kata_deploy::runtime::containerd] Successfully configured all containerd runtimes
    [2026-09-16T05:50:49Z INFO kata_deploy::artifacts::snapshotters] Deploying nydus-for-kata-tee
    [2026-09-16T05:50:50Z INFO kata_deploy::artifacts::snapshotters] Configuring nydus-for-kata-tee
    [2026-09-16T05:50:50Z INFO kata_deploy] About to restart runtime: containerd
    [2026-09-16T05:50:50Z INFO kata_deploy::runtime::lifecycle] restart_runtime: Starting restart for runtime=containerd
    [2026-09-16T05:50:50Z INFO kata_deploy::runtime::lifecycle] restart_runtime: Running daemon-reload
    [2026-09-16T05:50:51Z INFO kata_deploy::runtime::lifecycle] restart_runtime: Restarting containerd service
    [2026-09-16T05:50:51Z INFO kata_deploy::runtime::lifecycle] restart_runtime: Successfully restarted containerd service
    [2026-09-16T05:50:51Z INFO kata_deploy::runtime::lifecycle] restart_runtime: Waiting for node to become ready
    [2026-09-16T05:50:51Z INFO kata_deploy::runtime::lifecycle] wait_till_node_is_ready: Node try-72165-gpu01 ready status = 'True' (attempt 1)
    [2026-09-16T05:50:51Z INFO kata_deploy::runtime::lifecycle] Node try-72165-gpu01 is ready
    [2026-09-16T05:50:51Z INFO kata_deploy::runtime::lifecycle] restart_runtime: Node is ready
    [2026-09-16T05:50:51Z INFO kata_deploy] Runtime restart completed successfully
    [2026-09-16T05:50:51Z INFO kata_deploy::k8s::client] Setting label katacontainers.io/kata-runtime=true on node try-72165-gpu01
    [2026-09-16T05:50:51Z INFO kata_deploy] Kata Containers installation completed successfully
    [2026-09-16T05:50:51Z INFO kata_deploy] Install completed, re-exec'ing into post-install waiter
    [2026-09-16T05:50:51Z INFO kata_deploy::config] Action:
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * internal-post-install-wait
    [2026-09-16T05:50:51Z INFO kata_deploy::config] 
    [2026-09-16T05:50:51Z INFO kata_deploy::config] Environment variables passed to this script
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * NODE_NAME: try-72165-gpu01
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * DEBUG: false
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * SHIMS: clh-runtime-rs qemu-coco-dev qemu-coco-dev-runtime-rs qemu-nvidia-gpu-runtime-rs qemu-nvidia-gpu-snp qemu-nvidia-gpu-snp-runtime-rs qemu-snp
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * DEFAULT_SHIM: qemu-snp
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * ALLOWED_HYPERVISOR_ANNOTATIONS: 
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * SNAPSHOTTER_HANDLER_MAPPING: Some("qemu-coco-dev:nydus,qemu-coco-dev-runtime-rs:nydus,qemu-nvidia-gpu-snp:nydus,qemu-nvidia-gpu-snp-runtime-rs:nydus,qemu-nvidia-gpu-snp:nydus,qemu-snp:nydus")
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * AGENT_HTTPS_PROXY: None
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * AGENT_NO_PROXY: None
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * PULL_TYPE_MAPPING: Some("qemu-coco-dev:guest-pull,qemu-coco-dev-runtime-rs:guest-pull,qemu-nvidia-gpu-snp:guest-pull,qemu-nvidia-gpu-snp-runtime-rs:guest-pull,qemu-nvidia-gpu-snp:guest-pull,qemu-snp:guest-pull")
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * INSTALLATION_PREFIX: None
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * MULTI_INSTALL_SUFFIX: None
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * HELM_POST_DELETE_HOOK: false
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * EXPERIMENTAL_SETUP_SNAPSHOTTER: Some(["nydus"])
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * EXPERIMENTAL_FORCE_GUEST_PULL: qemu-nvidia-gpu-snp
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * CONTAINERD_CONF_FILE: /etc/containerd/config.toml
    [2026-09-16T05:50:51Z INFO kata_deploy::config] * CUSTOM_RUNTIMES_ENABLED: false
    [2026-09-16T05:50:51Z INFO kata_deploy::health] Health server resumed from inherited fd=9
    [2026-09-16T05:50:51Z INFO kata_deploy] Post-install waiter ready, blocking on SIGTERM
    

  4. Run the following command to verify that the Helm release is deployed:

    helm list -n coco-system

    Expected output:

    NAME    NAMESPACE    REVISION    UPDATED    STATUS     CHART                         APP VERSION
    coco    coco-system  1           <timestamp> deployed   confidential-containers-0.21.0   0.21.0
    

9.0 Register Application Measurements with CCM

You must register the application measurements in Fortanix CCM before deploying the workload to enable CCM to verify that the Confidential Container is running in the expected trusted environment.

9.1 Create the InitData Configuration

Create an initdata.toml file containing the configuration required by the Confidential Containers runtime to communicate with Fortanix CCM and DSM.

Configure ccm_as to communicate with CCM and ccm_kbc to communicate with DSM for the required key operation.

For example:

version = "0.1.0"
algorithm = "sha384"

[data]
"aa.toml" = '''
[token_configs.ccm_as]
ccm_domain_names = ["fortanix.com"]
'''

"cdh.toml" = '''
[kbc]
name = "ccm_kbc"
url = "https://apps.dsm.example.com"

[kbc_configs.ccm_kbc]
dsm_app_id = "<DSM_TRUSTED_CA_APP_UUID>"
'''

Where,

NOTE

Replace the example CCM domain, DSM endpoint, and DSM application UUID with the values provided for your environment.

9.2 Encode the InitData

  1. Run the following command to compress the initdata.toml file using gzip and encode the result using Base64:

    initdata=$(cat initdata.toml | gzip | base64 -w0)

    Note the resulting Base64-encoded value. Use this value in the Kubernetes workload configuration for the annotation: io.katacontainers.config.hypervisor.cc_init_data in Section 9.3: Obtain Application Measurements.

9.3 Obtain Application Measurements

To calculate the measurements, perform the following steps.

  1. Create a sample pod YAML file on the host to obtain the application measurements.

    1. For an AMD SEV-SNP workload, use the following configuration:

      apiVersion: v1
      kind: Pod
      metadata:
        name: <MEASUREMENT_POD>
        annotations:
          io.containerd.cri.runtime-handler: kata-qemu-nvidia-gpu-snp
          io.katacontainers.config.hypervisor.kernel_params: "agent.guest_components_rest_api=all"
          io.katacontainers.config.hypervisor.cc_init_data: "<BASE64_ENCODED_INITDATA>"
      
      spec:
        runtimeClassName: kata-qemu-nvidia-gpu-snp
        restartPolicy: Never
      
        containers:
        - name: sample-os-container
          image: ubuntu:22.04
          resources:
            limits:
              nvidia.com/pgpu: "1"
              memory: 16Gi
      
          securityContext:
            privileged: true
          ports:
          - containerPort: 80
      

      Where,

      • <MEASUREMENT_POD>: The container image used to generate the attestation measurements

      • <BASE64_ENCODED_INITDATA>: The base64 encoded initdata.toml content generated in Section 9.2: Encode the InitData. required by the Confidential Containers runtime to communicate with Fortanix CCM and DSM.

      NOTE

      • For non-GPU workloads, remove the resources section from the pod configuration.

      • The sample measurement workload requires privileged access for the validation procedure. Do not use this configuration for production workloads unless privileged access is required by the application.

  2. Run the following command to deploy the sample measurement workload:

    kubectl apply -f measurements.yaml

  3. Run the following command to verify that the pod is running:

    kubectl get pods

    For example:

    NAME          READY   STATUS    RESTARTS   AGE
    <MEASUREMENT_POD>   1/1     Running   0          1m

    Replace <MEASUREMENT_POD> with the name of the measurement pod.

  4. Run the following command to obtain the attestation evidence from the running pod for AMD SEV-SNP:

    kubectl exec <MEASUREMENT_POD> -- bash -c "
      apt-get update -qq && apt-get install -qq -y curl python3 >/dev/null
    "

  5. Then run the following command to generate the measurements:

    kubectl exec <MEASUREMENT_POD> -- bash -c "curl -s 'http://127.0.0.1:8006/aa/evidence?runtime_data=dGVzdA==' | python3 -c '
    import sys, json
    d = json.load(sys.stdin)
    r = d[\"attestation_report\"]
    print(\"measurement:\", bytes(r[\"measurement\"]).hex())
    print(\"host_data:  \", bytes(r[\"host_data\"]).hex())
    '"
    

    The output displays the measurement and host_data values. For example:

    measurement: b71ad03793de8c0cc4bca04c00ddc7b441c03bc1548b94a880b33f1b8af22fb846c11ff9f492817c4a2b7178396888fb
    host_data:   695462b3eb927997e7a704a6df90f1abf174ef4efc5a1f4e20a07c6684cae001

9.4 Register the Measurements in CCM

Perform the following steps to register the measurements in CCM:

  1. In the Fortanix CCM UI, open the application created in Section 5.4: Create an Application in CCM.

  2. On the following page, click ADD BUILD to configure the build of the AMD SEV-SNP application.

  3. In the Add Build form:

    1. Build Version: Enter a unique tag for the build.

    2. In the Secure VM attestation section,

      1. Measurement: Enter the platform-specific attestation measurement value generated in Section 9.3: Obtain Application Measurements to register the required SEV-SNP measurement information.

      2. HOST_DATA: Enter the hash of the InitData configuration generated in Section 9.3: Obtain Application Measurements. CoCo embeds this hash in the HOST_DATA field at pod launch. CCM uses the registered hash to verify the integrity of the InitData configuration during the attestation flow

      3. VMPL: Select the VMPL0, VMPL1, VMPL2, or VMPL3 as Virtual Machine Privilege Level.

    3. Coprocessors: Select an option to configure the NVIDIA Graphics Processing Unit (GPU) attestation setting:

      1. Ignored: The virtual machine (VM) must have a GPU, and the attestation agent collects GPU attestation data, but Fortanix CCM does not validate this attestation, it only checks that GPU attestation data is present. The actual attestation result is ignored during verification.

      2. Required: The VM must have a GPU, and the attestation agent collects GPU attestation data, and Fortanix CCM validates this data using NVIDIA Remote Attestation Service (NRAS).

  4. Click ADD BUILD to create the build.

  5. A build approval task is created and added, which is visible on the Tasks page. You can approve the task to approve the build.

    For more information on how to approve the application build tasks for the CoCo AMD SEV-SNP application, refer to Domain and Application Build Approval.

  6. After the build is approved, a green tick will appear in the Approval status column for that build.

Figure 6: Create Build - CoCo AMD SEV-SNP

10.0 Deploy the Confidential Container

After preparing the environment registering the application measurements with CCM, deploy the encrypted container image as a Confidential Container.

The workload is deployed through Kubernetes using the Kata runtime. The Kata deployment on the host provides the confidential VM image, kernel, and runtime configuration required to run the workload in a TEE environment

The workload configuration specifies the encrypted container image, the Confidential Containers runtime, and the configuration required for attestation and secure key release.

When the workload starts, the CoCo runtime launches the workload in a TEE. Inside the TEE, the kata-agent manages the Kubernetes pod lifecycle, while image-rs retrieves the encrypted container image from the container registry. The ccm_kbc module uses the CCM-issued certificate to authenticate to Fortanix DSM using mTLS (mutual TLS). After successful attestation, DSM authorizes the workload and performs the LEK unwrapping operation using the non-exportable KEK, while keeping the key protected in DSM. After the LEK is unwrapped, image-rs, with the help of ocicrypt-rs, decrypts the encrypted image layers using the unwrapped LEK.

10.1 Create the Kubernetes Workload

Create a Kubernetes YAML file for the encrypted container.

  • For an AMD SEV-SNP workload, specify the following:

runtimeClassName: kata-qemu-nvidia-gpu-snp
runtimeClassName: kata-qemu-snp
  • Enter the Base64-encoded InitData using the following annotation:

    io.katacontainers.config.hypervisor.cc_init_data: "<BASE64_ENCODED_INITDATA>"

    The required CoCo guest and Fortanix configuration can be provided either through InitData or kernel parameters.

    Use the following kernel parameters:

    io.katacontainers.config.hypervisor.kernel_params: agent.guest_components_rest_api=all agent.aa_kbc_params=ccm_kbc::default ccm.kbc_dsm_endpoint=https://apps.amer.smartkey.io"

    Where:

    • agent.guest_components_procs: Enables the required CoCo guest processes.

    • agent.guest_components_rest_api: Enables the guest component REST API.

    • agent.aa_kbc_params: Configures the ccm_kbc Key Broker Client.

    • ccm.kbc_dsm_endpoint: Specifies the Fortanix DSM endpoint used for secure key release.

    NOTE

    Using InitData is the recommended approach. Do not configure the same parameters in both locations.

  • Enter the encrypted container image that you published:

    image: <REGISTRY>/<REPOSITORY>:<TAG>

  • If the workload requires an NVIDIA GPU, specify the GPU resource:

    NOTE

    The Confidential Container workload configuration must match the configuration used to obtain the application measurements, including the runtime configuration and InitData. Changes to the measured configuration can result in an attestation measurement mismatch and prevent the workload from being attested by CCM

    resources:
      limits:
        nvidia.com/pgpu: "1"

  • Example Kubernetes Workload YAML file (workload-gpu.yaml):

    apiVersion: v1
    kind: Pod
    metadata:
      name: <WORKLOAD_NAME>
      annotations:
        io.containerd.cri.runtime-handler: kata-qemu-nvidia-gpu-snp
        io.katacontainers.config.hypervisor.kernel_params: "agent.guest_components_rest_api=all"
        io.katacontainers.config.hypervisor.cc_init_data: "<BASE64_ENCODED_INITDATA>"
    io.containerd.cri.runtime-handler: kata-qemu-nvidia-gpu-snp
    spec:
      runtimeClassName: kata-qemu-nvidia-gpu-snp
      restartPolicy: Never
      containers:
        - name: <CONTAINER_NAME>
          image: <REGISTRY>/<REPOSITORY>:<TAG>
          resources:
            limits:
              nvidia.com/pgpu: "1"
              memory: 16Gi
          securityContext:
            privileged: true
          ports:
            - containerPort: 80

10.2 Deploy the Workload

Run the following command to apply the workload configuration:

kubectl apply -f workload-gpu.yaml

Run the following command to verify the workload:

kubectl get pods

After the workload starts, image-rs, with the help of ocicrypt-rs, decrypts the encrypted container image layers using the unwrapped LEK. The application or model can then run inside the confidential environment.

11.0 Verify the Confidential Container

When the workload starts, the CoCo Attestation Agent uses the ccm_as module to collect TEE attestation evidence and obtain an application certificate from Fortanix CCM. The ccm_kbc module uses the certificate to authenticate to Fortanix DSM through Trusted CA Authentication and perform the required key operation. Verify the attestation and key-operation flow using the CCM application certificate, application deployment state, and DSM audit logs.

Perform the following verification steps:

11.1 Verify the DSM Audit Logs

In Fortanix DSM, open the application configured for Trusted CA Authentication. Verify that the application activity logs contain audit entries corresponding to the key operations performed by the attested workload.

Figure 7: DSM app audit logs

11.2 Verify the Application Certificate in CCM

In Fortanix CCM, open the AMD SEV-SNP application and select the CERTIFICATE tab. Verify that the certificate issued to the successfully attested workload is displayed. The certificate details include the certificate domain, issuer, validity period, and public key information.

Figure 8: Application Certificate

11.3 Verify the Application Deployment

In Fortanix CCM, open the AMD SEV-SNP application and select the BUILDS tab. Verify that the application build shows the deployment state as Deployed.

Figure 9: Application Build Deployed

12.0 Troubleshooting

This section describes common issues that may occur during the deployment and execution of Confidential Containers (CoCo) and provides recommended resolutions for each issue.

PROBLEM

RESOLUTION

failed to get stream processor for application/vnd.oci.image.layer .v1.tar+gzip+encrypted: exec: "ctd-decoder": executable file not found in $PATH

Add the following annotation to the workload.yaml file: io.containerd.cri.runtime-handler: kata-qemu-nvidia-gpu-snp

Error from server (BadRequest): container "kube-kata" in pod "kata-as-coco-runtime-..." is waiting to start: trying and failing to pull image

The kata-as-coco-runtime installation is not complete. Verify that the DaemonSet has rolled out successfully using kubectl -n coco-system rollout status ds/kata-as-coco-runtime.

failed to create containerd task: failed to create shim task: cold_plug_vfio= or hot_plug_vfio= port is not set for device

Remove the nvidia.com/pgpu: "1" resource from the workload YAML for a non-GPU workload.

Warning FailedCreatePodSandBox 119s (x890 over 16m) kubelet (combined from similar events): Failed to create pod sandbox: rpc error: code = Unknown desc = failed to start sandbox "a9330562ec2d2b965d2e8704b1f8 fd9f421e56bebc5b25bf312318554b41f0f4": failed to create containerd task: failed to create shim task: device cold plug failed: cold plug: CDI device injection failed: CDI registry refresh failed: failed to load CDI Spec failed to parse CDI Spec "/var/run/cdi/nvidia.yaml": failed to unmarshal CDI Spec: error unmarshaling JSON: while decoding JSON: json: unknown field "additionalGids"

This is caused by a CDI version mismatch with NVIDIA Container Toolkit 1.20.0. If you do not want to downgrade to version 1.19.x, delete /var/run/cdi/nvidia.yaml.

Failed to decrypt the image layer, please ensure that the decryption key is placed and correct followed by Build with attested BaremetalAmdSevSnp measurements not found

Recreate the CCM application build with valid measurements.

Build with attested BaremetalAmdSevSnp measurements not found or Build with attested BaremetalSnp measurements not found

Verify that the measurements registered in CCM match the measurement workload configuration. The measurement YAML and workload YAML must contain the same relevant fields, particularly GPU configuration and annotations. To avoid measurement mismatch:

  1. Create the workload YAML you intend to run.

  2. Create a copy and change only the image to the measurement image.

  3. Obtain and register the measurements in CCM.

  4. Change only the image field back to the workload image.

Coprocessor evidence with identifier: 1.3.6.1.4.1.49690.2.2.11.1 not found

The CCM build was configured with GPU coprocessor attestation set to Required for a non-GPU workload. Recreate the CCM build with NVIDIA GPU attestation set to Ignored.

Node Agent reports Address not available for an SEV-SNP workload.

The underlying vhost_vsock kernel module may not be loaded properly. Run sudo modprobe vhost_vsock.

SNP quote obtained (CSR/NA enrollment not yet implemented) snp_quote_bytes=0 snp_quote_first_32_hex=

  1. Verify that the qgsd service is running: sudo systemctl start qgsd.

  2. Verify that the VSOCK port is configured in /etc/qgs.conf, then restart the service using sudo systemctl restart qgsd.

  3. If the issue persists, check /etc/sgx_default_qcnl.conf for the PCCS configuration and contact Fortanix.

Warning FailedScheduling 3m44s (x5 over 24m) default-scheduler 0/1 nodes are available: 1 node(s) didn't match Pod's node affinity/selector. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.

Warning FailedScheduling 13s default-scheduler 0/1 nodes are available: 1 Insufficient sev-snp.amd.com/esids. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod.

IOMMU in passthrough · Issue #88 · AMDESE/AMDSEV

1. Remove iommu=pt from /etc/default/grub.

2. Run sudo update-grub and reboot the node.

Policy error: SEV-SNP VM has launch mitigation vector of X, minimum expected Y

Update the kernel on the host.

SNP TCB verification failed: DCAP certificate error: CertificateVerificationFailed: TCB Status of Out of Date can't be trusted

The microcode is out of date. Contact the server vendor for a BIOS update that includes the latest microcode and update the BIOS.

Workload is not scheduled on the node.

Verify the following:

  1. Verify that the required AMD/Intel and GPU node labels are present.

  2. Verify that the GPU is in the Ready CC state.

  3. Verify that the GPU Operator pods are healthy. If the VFIO Manager pod fails repeatedly, check the GPU Operator deployment.

  4. Run the following command to verify node labels:

    kubectl get nodes -l nvidia.com/gpu.workload.config=vm-passthrough
    kubectl get node $NODE_NAME -o json | jq '.metadata.labels | with_entries(select(.key | startswith("nvidia.com/cc")))'
    kubectl get pods -n gpu-operator

    If the required labels are missing, run the following commands to label the node:

    kubectl label node <node-name> nvidia.com/gpu.workload.config=vm-passthrough
    kubectl label node $NODE_NAME nvidia.com/cc.mode=on --overwrite
    

Os { code: 28, kind: StorageFull, message: "No space left on device" }

Increase the memory allocated to the workload in the workload YAML. For example:

resources:
   limits:
    nvidia.com/pgpu: "1"
    memory: 16Gi #increase this and restart

Increase the memory value as needed and restart the workload.

Warning FailedScheduling 36s default-scheduler 0/1 nodes are available: 1 Insufficient nvidia.com/pgpu. no new c

laims to deallocate, preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.

  1. Check the uncompressed size of the container image, such as on Docker Hub.

  2. Set the workload memory limit to at least 2× the uncompressed size of the container image.

Fortanix-logo

4.6

star-ratings

As of August 2025