Deploying confidential containers on bare-metal servers

OpenShift sandboxed containers 1.13

Protecting containers and data by leveraging trusted execution environments

Red Hat Customer Content Services

Abstract

Confidential containers provide a confidential computing environment to protect containers and data by leveraging trusted execution environments. You install the OpenShift sandboxed containers Operator on an OpenShift Container Platform cluster for your confidential containers workload after configuring an attestation service such as Red Hat build of Trustee in a trusted environment.

Preface

Confidential containers provide a confidential computing environment to protect containers and data by leveraging trusted execution environments. You install the OpenShift sandboxed containers Operator on an OpenShift Container Platform cluster for your confidential containers workload after configuring an attestation service such as Red Hat build of Trustee in a trusted environment.

Chapter 1. Provide feedback on Red Hat documentation

You can provide feedback or report an error by submitting the Create Issue form in Jira.

Procedure

  1. Ensure that you are logged in to Jira. If you do not have a Jira account, you must create a This content is not included.Red Hat Jira account.
  2. Launch the Content from redhat.atlassian.net is not included.Create Issue form.
  3. Replace the pre-filled Summary text with a short title that describes your specific issue.
  4. In the Description field, include the documentation URL, chapter or section number, and a detailed description of the issue.
  5. Click Create.

Chapter 2. Confidential containers workload protection

You can deploy confidential containers workloads on a Red Hat OpenShift Container Platform cluster running on bare-metal servers with the Intel® Trust Domain Extensions (TDX) and AMD SEV-SNP Trusted Execution Environments (TEEs). Confidential containers provides a confidential computing environment to protect containers and data by leveraging hardware-based Trusted Execution Environments (TEEs).

2.1. Confidential containers compatibility with OpenShift Container Platform

You must ensure that your Red Hat OpenShift Container Platform version supports the features you require.

The required functionality for OpenShift Container Platform is supported by two main components:

Kata runtime
The Kata runtime is included with Red Hat Enterprise Linux CoreOS (RHCOS) and receives updates with every OpenShift Container Platform release. When enabling peer pods with the Kata runtime, the OpenShift sandboxed containers Operator requires external network connectivity to pull the necessary image components and helper utilities to create the pod virtual machine (VM) image.
OpenShift sandboxed containers Operator
The OpenShift sandboxed containers Operator is a Rolling Stream Operator, which means the latest version is the only supported version. It works with all currently supported versions of OpenShift Container Platform.

The Operator depends on the features that come with the RHCOS host and the environment it runs in.

Note

You must install RHCOS on the worker nodes. Red Hat Enterprise Linux (RHEL) nodes are not supported.

The following compatibility matrix for confidential containers and OpenShift Container Platform releases identifies compatible features and environments.

Table 2.1. Supported architectures

ArchitectureOpenShift Container Platform version (without GPU)OpenShift Container Platform version (with GPU)

x86_64

4.19.38+

4.21.24+

s390x

4.19.38+

 — 

There are two ways to deploy the Kata containers runtime:

  • Bare metal
  • Peer pods

You can deploy confidential containers by using peer pods on Microsoft Azure, Microsoft Azure Red Hat OpenShift, and IBM Z. With the release of OpenShift sandboxed containers 1.13.1, the OpenShift sandboxed containers Operator requires OpenShift Container Platform version 4.19.38 or later for deployments without support for a graphics processing unit (GPU).

The following table describes OpenShift Container Platform versions and features with the following support levels:

  • GA: General Availability
  • TP: Technology Preview
Note

The version numbers in the table represent the minimum supported version. For example, "4.21.24+" means version 4.21.24 or any later version.

For Microsoft Azure Red Hat OpenShift, the minimum OpenShift Container Platform version listed in the table is supported only after the corresponding z-stream release is available on the Azure Red Hat OpenShift managed service.

Table 2.2. Confidential containers: feature availability by OpenShift Container Platform version

PlatformTrusted execution environment (TEE)GPU4.19.38+4.20.29+4.21.24+4.22.5+

Bare metal

Intel® TDX or AMD SEV-SNP

No

GA

GA

GA

GA

Intel® TDX or AMD SEV-SNP

NVIDIA H100 or DGX B200

 — 

 — 

GA

GA

IBM Z bare metal

IBM SE for Linux

No

GA

GA

GA

GA

IBM Z peer pods

IBM SE for Linux

No

GA

GA

GA

GA

Microsoft Azure

Intel® TDX or AMD SEV-SNP

No

GA

GA

GA

GA

AMD SEV-SNP

NVIDIA H100

 — 

 — 

 — 

TP

Microsoft Azure Red Hat OpenShift

Intel® TDX or AMD SEV-SNP

No

GA

GA

GA

GA

Amazon Web Services

Intel® TDX or AMD SEV-SNP

No

 — 

 — 

 — 

 — 

Google Cloud

Intel® TDX or AMD SEV-SNP

No

 — 

 — 

 — 

 — 

Note

Confidential containers includes Red Hat build of Trustee.

GPU support with Kata requires the KubeletPodResourcesGet feature gate to be enabled. This feature gate is available only in OpenShift Container Platform 4.21 and later. Additionally, the CRI-O fix for extending the timeout that is required for peer pods GPU support is available only in OpenShift Container Platform 4.22 and later.

Azure does not currently support GPU nodes with Intel® TDX.

2.2. Common terms

The following terms are used throughout the documentation.

Attestation
The process of verifying the integrity and trustworthiness of a Trusted Execution Environment (TEE) and the confidential containers workloads running within it, ensuring that only trusted code and data are executed. Red Hat build of Trustee performs this function.
Confidential containers
A technology that provides a confidential computing environment to protect containers and data by leveraging Trusted Execution Environments.
Initdata
A specification used to securely initialize a pod with workload-specific data (such as certificates, cryptographic keys, or an optional Kata Agent policy) at runtime, preventing the need to embed this data directly in the virtual machine (VM) image.
Kata Agent
A component within the pod Virtual Machine (VM) that enforces runtime policies and manages the lifecycle of the containers running inside the VM. Its policy controls application programming interface (API) requests for peer pods.
Kata containers
Kata containers is a core upstream project that is used to build OpenShift sandboxed containers. OpenShift sandboxed containers integrates Kata containers with OpenShift Container Platform.
kata runtime
The optional runtime installed by the OpenShift sandboxed containers Operator when configuring bare metal deployments.
kata-cc runtime
The runtime class used specifically for confidential containers deployments on bare-metal servers.
kata-remote runtime
The runtime class used for peer pod deployments on cloud platforms or remote hypervisors.
KataConfig
A custom resource used to configure and launch OpenShift sandboxed containers.
TrusteeConfig
A custom resource used to configure and launch Red Hat build of Trustee.
OpenShift sandboxed containers
OpenShift sandboxed containers integrates Kata containers as an optional runtime to provide enhanced security and isolation for container workloads by running applications in lightweight virtual machines.
OpenShift sandboxed containers Operator
The OpenShift sandboxed containers Operator manages the lifecycle of OpenShift sandboxed containers and confidential containers on a cluster.
Peer pod

A peer pod in OpenShift sandboxed containers extends the concept of a standard pod. Unlike a standard sandboxed container, where the virtual machine is created on the worker node itself, in a peer pod, the virtual machine is created through a remote hypervisor using any supported hypervisor or cloud provider API.

The peer pod acts as a regular pod on the worker node, with its corresponding VM running elsewhere. The remote location of the VM is transparent to the user and is specified by the runtime class in the pod specification. The peer pod design circumvents the need for nested virtualization.

Pod

A pod is a construct that is inherited from Kubernetes and OpenShift Container Platform. It represents resources where containers can be deployed. Containers run inside pods, and pods are used to specify resources that can be shared between multiple containers.

In the context of OpenShift sandboxed containers, a pod is implemented as a virtual machine. Several containers can run in the same pod on the same virtual machine.

Red Hat build of Trustee
Red Hat build of Trustee is an attestation service that verifies the trustworthiness of the location where you plan to run your workload or where you plan to send confidential information. Red Hat build of Trustee includes components deployed on a trusted side and used to verify whether the remote workload is running in a Trusted Execution Environment (TEE).
Red Hat build of Trustee Operator
The Red Hat build of Trustee Operator manages the installation, lifecycle, and configuration of Red Hat build of Trustee.
Runtime class
An object that describes the specific runtime configuration used to run a workload.
Sandbox

A sandbox is an isolated environment where programs can run. In a sandbox, you can run untested or untrusted programs without risking harm to the host machine or the operating system.

In the context of OpenShift sandboxed containers, sandboxing is achieved by running workloads in a different kernel using virtualization, providing enhanced control over the interactions between multiple workloads that run on the same host.

Trusted Execution Environment (TEE)
Hardware-based security technology leveraged by confidential containers to protect containers and data. Examples: Intel® TDX, AMD SEV-SNP.

2.3. Initrd images

An initial ramdisk (initrd) is a compressed file system used in a virtual machine (VM) boot process. In a confidential containers environment, an initrd is essential for booting the confidential virtual machine (CVM) and is a critical "link in the chain of trust".

Before a pod initializes in the CVM, hardware, such as AMD SEV-SNP or Intel® Trust Domain Extensions (TDX), evaluates the initrd contents.

Important

For confidential containers use cases, you must build initrd in a secure, isolated environment and add its hash to the reference values in Red Hat build of Trustee. Do not build initrd on a standard worker node at runtime. A compromised worker node could modify initrd during the build process, rendering the hardware measurement untrustworthy. initrd images provide a verified, static starting point for your confidential containers workloads.

initrd images provide the following benefits:

  • Established root of trust: initrd images from a trusted vendor contain a known Measurement Hash. You can hard-code the hash value into your Red Hat build of Trustee (Attestation Service) policy.
  • Operational simplicity: Using initrd images eliminates the need to maintain a private build pipeline and manage the dependencies required to create the correct initrd for a specific kernel.

The following Red Hat initrd image variants are available:

  • Standard (kata-cc.initrd): Includes a minimal root file system (RHEL 10 based), kernel drivers, kata-agent, confidential-data-hub, attestation-agent, and default restrictive kata-agent policy.
  • GPU (kata-nvidia-gpu-cc.initrd): Includes a minimal root file system (RHEL 10 based), kernel drivers (RHEL 10 based), kata-agent, confidential-data-hub, attestation-agent, default restrictive kata-agent policy, NVIDIA GPU driver (version 595.58.03), and nvidia-container toolkit.

The OpenShift sandboxed containers setup process installs the initrd images. You do not need to take any specific action.

Chapter 3. Installation

You install confidential containers on bare-metal servers with the Intel® Trust Domain Extensions (TDX) and AMD SEV-SNP Trusted Execution Environments (TEEs) by configuring your environment and installing the OpenShift sandboxed containers Operator.

Perform the following steps:

  1. Intel® TDX: Create a machine config for your cluster.
  2. Install the OpenShift sandboxed containers Operator.

3.1. Prerequisites

Review the following prerequisites before deploying confidential containers.

  • You have installed the latest version of Red Hat OpenShift Container Platform on the cluster where you are running your confidential containers workload.

    Important

    Check the Compatibility with OpenShift Container Platform for the specific minimum version required for confidential containers in release 1.13, as it requires a higher version than OpenShift sandboxed containers.

  • You have deployed Red Hat build of Trustee on an OpenShift Container Platform cluster in a trusted environment. For more information, see This content is not included.Deploying Red Hat build of Trustee.
  • Your bare-metal servers are configured for Unified Extensible Firmware Interface (UEFI) boot mode.

    Important

    The OpenShift Container Platform Assisted Installer does not enforce UEFI boot mode during cluster installation. Verify that your server firmware is set to UEFI mode before you deploy confidential containers. Confidential containers workloads cannot run on servers that use legacy BIOS.

3.2. Create an Intel TDX machine config

To enable Intel® TDX support, create a MachineConfig object that configures the required kernel parameters and modules on your cluster nodes.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • Your cluster nodes have Intel® TDX-capable hardware.
  • The node kernel has initialized the Intel® TDX module.
  • Intel® TDX is enabled in the node firmware (BIOS/UEFI).

Procedure

  1. Create a tdx-machine-config.yaml manifest file according to the following example:

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    metadata:
      labels:
        machineconfiguration.openshift.io/role: <role>
      name: 99-enable-intel-tdx
    spec:
      kernelArguments:
      - kvm_intel.tdx=1
      - nohibernate
      config:
        ignition:
          version: 3.5.0
        storage:
          files:
            - path: /etc/kata-containers/kata-tdx/config.d/96-kata-kernel-config
              mode: 0644
              contents:
                source: data:text/plain;charset=utf-8;base64,W2h5cGVydmlzb3IucWVtdV0KdGR4X3F1b3RlX2dlbmVyYXRpb25fc2VydmljZV9zb2NrZXRfcG9ydD0wCg==
    <role>
    Specify master for single-node OpenShift or worker for a multi-node cluster.
  2. Create the MachineConfig object by running the following command:

    $ oc create -f tdx-machine-config.yaml

    Updating the machine config triggers node reboot.

Verification

  1. Verify that the machine config is correctly configured by running the following command:

    $ oc get machineconfig 99-enable-intel-tdx
  2. Verify that the machine config pool rollout is complete by running the following command:

    $ oc get mcp worker

    The UPDATED column must display True and the UPDATING column must display False.

3.3. Install the OpenShift sandboxed containers Operator

You can install the OpenShift sandboxed containers Operator by using the command-line interface (CLI).

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create an osc-namespace.yaml manifest file:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: openshift-sandboxed-containers-operator
  2. Create the namespace by running the following command:

    $ oc create -f osc-namespace.yaml
  3. Create an osc-operatorgroup.yaml manifest file:

    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: sandboxed-containers-operator-group
      namespace: openshift-sandboxed-containers-operator
    spec:
      targetNamespaces:
      - openshift-sandboxed-containers-operator
  4. Create the Operator group by running the following command:

    $ oc create -f osc-operatorgroup.yaml
  5. Create an osc-subscription.yaml manifest file:

    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: sandboxed-containers-operator
      namespace: openshift-sandboxed-containers-operator
    spec:
      channel: stable
      installPlanApproval: Automatic
      name: sandboxed-containers-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
      startingCSV: sandboxed-containers-operator.v1.13.1
  6. Create the subscription by running the following command:

    $ oc create -f osc-subscription.yaml

Verification

  1. Verify that the Operator is correctly installed by running the following command:

    $ oc get csv -n openshift-sandboxed-containers-operator

    This command can take several minutes to complete.

  2. Watch the installation progress by running the following command:

    $ watch oc get csv -n openshift-sandboxed-containers-operator
    NAME                             DISPLAY                                  VERSION         PHASE
    sandboxed-containers-operator.v1.13.1   OpenShift sandboxed containers Operator   1.13.1          Succeeded

    The installation is complete when the PHASE column shows Succeeded.

Chapter 4. Configuration

You can configure confidential containers on bare-metal servers with the Intel® Trust Domain Extensions (TDX) and AMD SEV-SNP Trusted Execution Environments (TEEs).

Perform the following steps:

  1. Configure worker nodes so that trusted execution environments (TEEs) are automatically detected.
  2. Intel® TDX: Configure the remote attestation infrastructure.
  3. Enable confidential containers.
  4. Create initdata to initialize a pod with sensitive or workload-specific data at runtime.

    Important

    Do not use the default permissive Kata Agent policy in a production environment. You must configure a restrictive policy, preferably by creating initdata.

    As a minimum requirement, you must disable ExecProcessRequest to prevent a cluster administrator from accessing sensitive data by running the oc exec command on a confidential containers pod.

  5. Add initdata to a pod manifest.
  6. Create the KataConfig custom resource (CR).
  7. Verify the attestation process.
  8. Configure your workload for confidential containers.

4.1. TEE auto-detection

You must label your worker nodes so that the OpenShift sandboxed containers Operator can detect the Trusted Execution Environments (TEEs).

You label the nodes by installing and configuring the Node Feature Discovery (NFD) Operator.

4.1.1. Create a NodeFeatureDiscovery custom resource

You create a NodeFeatureDiscovery custom resource (CR) to define the configuration parameters that the Node Feature Discovery (NFD) Operator checks to automatically detect your trusted execution environment (TEE).

Prerequisites

Procedure

  1. Create a my-nfd.yaml manifest file according to the following example:

    apiVersion: nfd.openshift.io/v1
    kind: NodeFeatureDiscovery
    metadata:
      name: nfd-instance
      namespace: openshift-nfd
    spec:
      operand:
        image: registry.redhat.io/openshift4/ose-node-feature-discovery-rhel9:v4.22
        imagePullPolicy: Always
        servicePort: 12000
      workerConfig:
        configData: |
  2. Create the NodeFeatureDiscovery CR:

    $ oc create -f my-nfd.yaml

4.1.2. Create the NodeFeatureRule custom resource

Create a NodeFeatureRule custom resource for your Trusted Execution Environment (TEE).

Prerequisites

  • You have installed the Node Feature Discovery (NFD) Operator.
  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create a custom resource manifest named my-nodefeaturerule.yaml:

    apiVersion: nfd.openshift.io/v1alpha1
    kind: NodeFeatureRule
    metadata:
      name: consolidated-hardware-features
      namespace: openshift-nfd
    spec:
      rules:
        - name: "runtime.kata"
          labels:
            feature.node.kubernetes.io/runtime.kata: "true"
          matchAny:
            - matchFeatures:
                - feature: cpu.cpuid
                  matchExpressions:
                    SSE42: { op: Exists }
                    VMX: { op: Exists }
                - feature: kernel.loadedmodule
                  matchExpressions:
                    kvm: { op: Exists }
                    kvm_intel: { op: Exists }
            - matchFeatures:
                - feature: cpu.cpuid
                  matchExpressions:
                    SSE42: { op: Exists }
                    SVM: { op: Exists }
                - feature: kernel.loadedmodule
                  matchExpressions:
                    kvm: { op: Exists }
                    kvm_amd: { op: Exists }
        - name: "amd.sev-snp"
          labels:
            amd.feature.node.kubernetes.io/snp: "true"
          extendedResources:
            sev-snp.amd.com/esids: "@cpu.security.sev.encrypted_state_ids"
          matchFeatures:
            - feature: cpu.cpuid
              matchExpressions:
                SVM: { op: Exists }
            - feature: cpu.security
              matchExpressions:
                sev.snp.enabled: { op: Exists }
    
        - name: "intel.sgx"
          labels:
            intel.feature.node.kubernetes.io/sgx: "true"
          extendedResources:
            sgx.intel.com/epc: "@cpu.security.sgx.epc"
          matchFeatures:
            - feature: cpu.cpuid
              matchExpressions:
                SGX: { op: Exists }
                SGXLC: { op: Exists }
            - feature: cpu.security
              matchExpressions:
                sgx.enabled: { op: IsTrue }
            - feature: kernel.config
              matchExpressions:
                X86_SGX: { op: Exists }
    
        - name: "intel.tdx"
          labels:
            intel.feature.node.kubernetes.io/tdx: "true"
          extendedResources:
            tdx.intel.com/keys: "@cpu.security.tdx.total_keys"
          matchFeatures:
            - feature: cpu.cpuid
              matchExpressions:
                VMX: { op: Exists }
            - feature: cpu.security
              matchExpressions:
                tdx.enabled: { op: Exists }
  2. Create the NodeFeatureRule CR by running the following command:

    $ oc create -f my-nodefeaturerule.yaml
    Note

    A relabeling delay of up to 1 minute might occur.

Verification

  1. Verify that the NodeFeatureRule CR was created by running the following command:

    $ oc get nodefeaturerule -n openshift-nfd

    Confirm that consolidated-hardware-features appears in the output.

  2. Verify that the expected hardware feature labels were applied to your nodes by running the following command:

    $ oc get nodes --show-labels | grep feature.node.kubernetes.io

4.2. Deploy Intel TDX remote attestation

To enable quote generation and attestation for Intel® Trust Domain Extensions (TDX) pod virtual machines, set up the Intel® remote attestation infrastructure.

The Intel TDX DCAP Operator automates per-node certificate provisioning and Quote Generation Service (QGS) deployment. The operator supports both online and air-gapped registration flows.

Important

If you previously deployed Intel® TDX remote attestation by following the OpenShift sandboxed containers 1.12 documentation, the attestation will not work on later versions of OpenShift sandboxed containers.

To fix this, you must first uninstall the existing deployment. Toggle Intel® SGX Factory Reset in the BIOS, then install the Intel® TDX DCAP Operator as described in the following procedure.

Prerequisites

Procedure

  1. Install the Intel® TDX DCAP Operator. For details, see This content is not included.Installing from the software catalog by using the web console in the OpenShift Container Platform documentation.
  2. Configure the PCS API key Secret in the operator’s namespace by following the Deploy and Use documentation available in the OperatorHub console for the This content is not included.Intel® TDX DCAP Operator.
  3. Create an instance of the TdxQuoteGenerationService CR by following the Deploy and Use documentation available in the OperatorHub console for the This content is not included.Intel® TDX DCAP Operator.

Verification

  1. Verify that the TdxQuoteGenerationService CR is created by running the following command:

    $ oc get TdxQuoteGenerationService
  2. Verify that the PCCS and QGS pods are running in the intel-dcap namespace by running the following command:

    $ oc get pods -n intel-dcap

    Confirm that the pccs and tdx-qgs pods show a Running status.

4.3. Enable confidential containers

You enable confidential containers and specify the deployment mode by creating an osc-feature-gates config map.

The deployment mode determines how the Operator installs and configures the Kata runtime. This flexibility allows the Operator to work consistently in clusters with or without the Machine Config Operator (MCO).

Select one of the following deployment modes:

MachineConfig
Use this mode for clusters that have the MCO installed. If the deploymentMode key is missing in the config map, the Operator defaults to MachineConfig for backward compatibility.
DaemonSetFallback

Use this mode for clusters where the MCO availability is uncertain or may change.

Important

Do not use the DaemonSet deployment mode in clusters without the MCO. Otherwise, the installation fails. Use DaemonSetFallback in these clusters instead.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create a my-feature-gate.yaml manifest file:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: osc-feature-gates
      namespace: openshift-sandboxed-containers-operator
    data:
      confidential: "true"
      deploymentMode: <deployment_mode>

    Replace <deployment_mode> with MachineConfig for clusters with the MCO, or DaemonSetFallback for clusters without the MCO or where the MCO availability may change. Do not specify DaemonSet.

  2. Create the config map by running the following command:

    $ oc create -f my-feature-gate.yaml

Verification

  1. Verify that the config map exists by running the following command:

    $ oc get configmap osc-feature-gates -n openshift-sandboxed-containers-operator
    NAME                DATA   AGE
    osc-feature-gates   1      10s
  2. Confirm that confidential: "true" is present in the config map data by running the following command:

    $ oc get configmap osc-feature-gates -n openshift-sandboxed-containers-operator -o jsonpath='{.data}'
    {"confidential":"true","deploymentMode":"<deployment_mode>"}

4.4. Initializing pods at runtime by using initdata

You can initialize a pod with workload-specific data at runtime by creating and applying initdata.

This approach enhances security by reducing the exposure of confidential information and improves flexibility by eliminating custom image builds. For example, initdata can include three configuration settings:

  • An X.509 certificate for secure communication.
  • A cryptographic key for authentication.
  • An optional Kata Agent policy.rego file to enforce runtime behavior when overriding the default Kata Agent policy.

The initdata content configures the following components:

  • Attestation Agent (AA), which verifies the trustworthiness of the pod by sending evidence for attestation.
  • Confidential Data Hub (CDH), which manages secrets and secure data access within the pod virtual machine (VM).
  • Kata Agent, which enforces runtime policies and manages the lifecycle of the containers inside the pod VM.

You create an initdata.toml file and convert it to a gzip-format Base64-encoded string.

You apply initdata to a confidential containers pod by adding an annotation to the pod manifest.

4.5. Create the KataConfig custom resource

To install kata-cc as a runtime class on your worker nodes, you must create the KataConfig custom resource (CR).

Prerequisites

  • Your worker nodes are not currently running a critical workload. Creating the KataConfig CR automatically reboots the worker nodes. The reboot can take from 10 to more than 60 minutes depending on your deployment size, hardware type, and other factors.

Procedure

  1. Create an example-kataconfig.yaml manifest file according to the following example:

    apiVersion: kataconfiguration.openshift.io/v1
    kind: KataConfig
    metadata:
      name: example-kataconfig
    spec:
      enablePeerPods: false
      checkNodeEligibility: true
      logLevel: info
    #  kataConfigPoolSelector:
    #    matchLabels:
    #      <label_key>: '<label_value>'
    <label_key>: '<label_value>'
    Optional: If you have applied node labels to install kata-cc on specific nodes, specify the key and value, for example, kata-cc: 'true'.
  2. Create the KataConfig CR by running the following command:

    $ oc create -f example-kataconfig.yaml

    This command creates the KataConfig CR, which installs kata-cc as a runtime class on the worker nodes.

    Wait for the kata-cc installation to complete and the worker nodes to reboot before verifying the installation.

  3. Optional: Monitor the installation progress by running the following command:

    $ watch "oc describe kataconfig | sed -n /^Status:/,/^Events/p"

    When the status of all workers under kataNodes is installed and the condition InProgress is False without specifying a reason, the kata-cc is installed on the cluster.

Verification

  • Verify the runtime classes by running the following command:

    $ oc get runtimeclass
    NAME             HANDLER             AGE
    kata             kata                34m
    kata-nvidia-gpu  kata-nvidia-gpu     34m
    kata-cc        kata-tdx   152m

    You can also see the default kata runtime class in addition to kata-cc.

4.5.1. The checkNodeEligibility parameter

To manage node selection for your workloads, configure the checkNodeEligibility parameter in the KataConfig resource. This determines if runtime classes are created based on hardware labels or unconditionally. From 1.13.1, this applies to all standard and confidential container (CC) runtimes.

When checkNodeEligibility is set to true

The Operator performs the following actions:

  • Node eligibility verification: The Operator verifies that nodes have the required hardware capabilities by using node labels before installing the Kata runtime.
  • Conditional runtime class creation: The Operator creates runtime classes only if nodes with the required labels exist in the cluster:

    • Standard runtime classes: The kata or kata-nvidia-gpu runtime classes are created only if nodes with the required base and graphics processing unit (GPU) labels exist.
    • Confidential container runtime classes: The kata-cc or kata-cc-nvidia-gpu runtime classes are created only if nodes with the required Trusted Execution Environment (TEE) labels (such as Intel® Trust Domain Extensions (TDX) or AMD SEV-SNP) and the corresponding confidential containers and GPU labels exist.
  • Dynamic runtime class management: If no nodes match the required labels, the corresponding runtime class is not created. This prevents workload scheduling failures by ensuring users cannot select a runtime that the cluster cannot support.
When checkNodeEligibility is set to false (default)

The Operator performs the following actions:

  • Unconditional creation for standard runtimes: The Operator always creates the kata and kata-nvidia-gpu runtime classes, regardless of whether nodes currently have the required hardware labels.
  • Identification-based creation for CC runtimes: For the kata-cc and kata-cc-nvidia-gpu runtime classes, the Operator still depends on the TEE label for identification, but it does not verify the base or GPU labels during the installation phase.
  • Manual scheduling: The Operator skips the detailed node label check during installation. The cluster will only schedule pods using these runtime classes if a node eventually matches the nodeSelector defined in the runtime class.

4.6. Create initdata

You create initdata to securely initialize a pod with sensitive or workload-specific data at runtime, avoiding the need to embed this data in a virtual machine image. This approach provides additional security by reducing the risk of exposure of confidential information and eliminates the need for custom image builds.

Prerequisites

  • You have deleted the kbs_cert setting if you configure insecure_http = true in the kbs-config config map for Red Hat build of Trustee.

Procedure

  1. Obtain the Red Hat build of Trustee uniform resource locator (URL) by running the following command:

    $ TRUSTEE_URL=$(oc get route kbs-service \
      -n trustee-operator-system -o jsonpath='{.spec.host}') \
      && echo $TRUSTEE_URL
  2. Create the initdata.toml file:

    algorithm = <algorithm>
    version = "0.1.0"
    [data]
    "aa.toml" = '''
    [token_configs]
    [token_configs.coco_as]
    
    url = '<trustee_url>'
    
    [token_configs.kbs]
    url = '<trustee_url>'
    '''
    "cdh.toml" = '''
    socket = 'unix:///run/confidential-containers/cdh.sock'
    credentials = []
    
    [kbc]
    name = 'cc_kbc'
    url = '<trustee_url>'
    kbs_cert = """
    -----BEGIN CERTIFICATE-----
    <kbs_certificate>
    -----END CERTIFICATE-----
    """
    [image]
    image_security_policy_uri = 'kbs:///default/<secret_policy_name>/<key>'
    '''
    
    "policy.rego" = '''
    package agent_policy
    
    import future.keywords.in
    import future.keywords.if
    
    default AddARPNeighborsRequest := true
    default AddSwapRequest := true
    default CloseStdinRequest := true
    default CreateSandboxRequest := true
    default DestroySandboxRequest := true
    default GetMetricsRequest := true
    default GetOOMEventRequest := true
    default GuestDetailsRequest := true
    default ListInterfacesRequest := true
    default ListRoutesRequest := true
    default MemHotplugByProbeRequest := true
    default OnlineCPUMemRequest := true
    default PauseContainerRequest := true
    default PullImageRequest := true
    default RemoveContainerRequest := true
    default RemoveStaleVirtiofsShareMountsRequest := true
    default ReseedRandomDevRequest := true
    default ResumeContainerRequest := true
    default SetGuestDateTimeRequest := true
    default SignalProcessRequest := true
    default StartContainerRequest := true
    default StartTracingRequest := true
    default StatsContainerRequest := true
    default StopTracingRequest := true
    default TtyWinResizeRequest := true
    default UpdateContainerRequest := true
    default UpdateEphemeralMountsRequest := true
    default UpdateInterfaceRequest := true
    default UpdateRoutesRequest := true
    default WaitProcessRequest := true
    default WriteStreamRequest := true
    default CreateContainerRequest := true
    default ReadStreamRequest := false
    default CopyFileRequest := false
    default SetPolicyRequest := false
    default ExecProcessRequest := false
    
    CopyFileRequest if {
        print("CopyFileRequest: input =", input)
        allow_copy_file
        print("CopyFileRequest: true")
    }
    
    allow_copy_file if {
        print("allow_copy_file regular")
        input.file_type == "Regular"
        allow_copy_file_path(input.path, "")
        print("allow_copy_file regular: true")
    }
    
    allow_copy_file if {
        print("allow_copy_file directory")
        input.file_type == "Directory"
        allow_copy_file_path(input.path, "")
        print("allow_copy_file directory: true")
    }
    
    allow_copy_file if {
        print("allow_copy_file symlink")
        input.file_type == "Symlink"
        allow_copy_file_path(input.path, ".*/.+")
        check_directory_traversal(input.symlink_target)
        not startswith(input.symlink_target, "/")
        print("allow_copy_file symlink: true")
    }
    
    allow_copy_file_path(path, regex_suffix) if {
        check_directory_traversal(path)
        some regex1 in policy_data.request_defaults.CopyFileRequest
        regex2 := replace(regex1, "$(sfprefix)", policy_data.common.sfprefix)
        regex3 := replace(regex2, "$(cpath)", policy_data.common.cpath)
        regex4 := replace(regex3, "$(bundle-id)", "[a-z0-9]{64}")
        regex5 := concat("", [regex4, regex_suffix])
        print("allow_copy_file_path: regex5 =", regex5)
        regex.match(regex5, path)
    }
    
    check_directory_traversal(i_path) if {
        not regex.match("(^|/)\\.\\.($|/)", i_path)
    }
    
    policy_data := {
        "common": {
            "cpath": "/run/kata-containers/shared/containers(?:/passthrough)?",
            "sfprefix": "^$(cpath)/(watchable/)?$(bundle-id)-[a-z0-9]{16}-"
        },
        "request_defaults": {
            "CopyFileRequest": [
                "$(sfprefix)"
            ]
        }
    }
    '''
    algorithm
    Specify sha256, sha384, or sha512.
    URL
    Specify Red Hat build of Trustee
    kbs_certificate
    Specify the Base64-encoded TLS certificate for the attestation agent.
    kbs_cert
    See the prerequisite above regarding kbs_cert and insecure_http.
    image_security_policy_uri
    Optional, only if you enabled the container image signature verification policy. Replace <secret_policy_name> with the name of the secret that contains the policy and <key> with the key within that secret.
  3. Convert the initdata.toml file to a gzipped, Base64-encoded string in a text file by running the following command:

    $ cat initdata.toml | gzip | base64 -w0 > initdata.txt

    Record this string to use in the pod manifest.

  4. Calculate the hash of the initdata.toml file and assign its value to the hash variable by running the command that corresponds to the algorithm value you set in the initdata.toml file:

    For sha256:

    +

    $ hash=$(sha256sum initdata.toml | cut -d' ' -f1)

    For sha384:

    +

    $ hash=$(sha384sum initdata.toml | cut -d' ' -f1)

    For sha512:

    +

    $ hash=$(sha512sum initdata.toml | cut -d' ' -f1)
  5. Assign 32 bytes of 0s to the initial_pcr variable by running the following command:

    $ initial_pcr=0000000000000000000000000000000000000000000000000000000000000000
  6. Calculate the SHA-256 hash of hash and initial_pcr and assign its value to the PCR8_HASH variable by running the following command:

    $ PCR8_HASH=$(echo -n "$initial_pcr$hash" | xxd -r -p | sha256sum | cut -d' ' -f1) && echo $PCR8_HASH

    Record the PCR8_HASH value for the RVPS config map.

Verification

  1. Verify that the initdata.txt file exists and is not empty by running the following command:

    $ ls -lh initdata.txt && cat initdata.txt

    Confirm that the file exists and has a Base64-encoded string.

  2. Verify that the PCR8_HASH variable was set by running the following command:

    $ echo $PCR8_HASH

    Confirm that the output is a non-empty hash value.

4.7. Apply initdata to a pod

Prerequisites

  • The kata-cc runtime class is available on your cluster.

Procedure

  1. Add the initdata string to the pod manifest and save the file as my-pod.yaml:

    apiVersion: v1
    kind: Pod
    metadata:
      name: ocp-cc-pod
      labels:
        app: ocp-cc-pod
      annotations:
        io.katacontainers.config.hypervisor.cc_init_data: <initdata_string>
    spec:
      runtimeClassName: kata-cc
      containers:
      - name: <container_name>
        image: registry.access.redhat.com/ubi9/ubi:latest
        command:
        - sleep
        - "36000"
        securityContext:
          privileged: false
          seccompProfile:
            type: RuntimeDefault

    where

    <initdata_string>
    Specify the gzipped, Base64-encoded initdata value in a pod annotation to override the global INITDATA setting in the peer pods config map.
    <container_name>
    Specify a container name.
  2. Create the pod by running the following command:

    $ oc create -f my-pod.yaml

Verification

  1. Verify that the pod is running by running the following command:

    $ oc get pod ocp-cc-pod
    NAME          READY   STATUS    RESTARTS   AGE
    ocp-cc-pod    1/1     Running   0          30s
  2. Verify that the pod is using the expected runtime class by running the following command:

    $ oc get pod <pod_name> -o jsonpath='{.spec.runtimeClassName}'

    Confirm the output matches the expected runtime class, for example, kata-remote.

4.8. Verify attestation

You can verify the attestation process by creating a test pod to retrieve a specific resource from Red Hat build of Trustee.

Important

This procedure is an example to verify that attestation is working. Do not write sensitive data to standard I/O, because the data can be captured by using a memory dump. Only data written to memory is encrypted.

Prerequisites

  • You have deployed the confidential containers workload.
  • You have configured initdata with the Red Hat build of Trustee URL.
  • You have configured the Red Hat build of Trustee.

Procedure

  1. Create a test-pod.yaml manifest file:

    apiVersion: v1
    kind: Pod
    metadata:
      name: ocp-cc-pod
      labels:
        app: ocp-cc-pod
      annotations:
        io.katacontainers.config.hypervisor.cc_init_data: "<initdata_string>"
    spec:
      runtimeClassName: kata-cc
      containers:
        - name: skr-openshift
          image: registry.access.redhat.com/ubi9/ubi:latest
          command:
            - sleep
            - "36000"
          securityContext:
            privileged: false
            seccompProfile:
              type: RuntimeDefault
    metadata:
      name: coco-test-pod
      labels:
        app: coco-test-pod
      annotations:
        io.katacontainers.config.hypervisor.cc_init_data: "<initdata_string>"
    spec:
      runtimeClassName: kata-cc
      containers:
        - name: test-container
          image: registry.access.redhat.com/ubi9/ubi:9.3
          command:
            - sleep
            - "36000"
          securityContext:
            privileged: false
            seccompProfile:
              type: RuntimeDefault

    where:

    io.katacontainers.config.hypervisor.cc_init_data
    Optional: Specifies initdata in a pod annotation, which overrides the global INITDATA setting in the peer pods config map.
  2. Create the pod by running the following command:

    $ oc create -f test-pod.yaml
  3. Log in to the pod by running the following command:

    $ oc exec -it ocp-cc-pod -- bash

Verification

  1. Fetch the Red Hat build of Trustee resource to confirm that attestation succeeded:

    $ curl http://127.0.0.1:8006/cdh/resource/default/attestation-status/status
    success #/

4.9. Configure your workload

You configure your workload for confidential containers by setting kata-cc as the runtime class for the following pod-templated objects:

  • Pod objects
  • ReplicaSet objects
  • ReplicationController objects
  • StatefulSet objects
  • Deployment objects
  • DeploymentConfig objects
Important

Do not deploy workloads in an Operator namespace. Create a dedicated namespace for these resources.

Procedure

  1. Add spec.runtimeClassName: kata-cc to the manifest of each pod-templated workload object as in the following example:

    apiVersion: v1
    kind: <object>
    # ...
    spec:
      runtimeClassName: kata-cc
    # ...
  2. Apply the changes to the workload object by running the following command:

    $ oc apply -f <object.yaml>

    OpenShift Container Platform creates the workload object and begins scheduling it.

Verification

  • Inspect the spec.runtimeClassName field of a pod-templated object. If the value is kata-cc, then the workload is running on confidential containers.

4.9.1. Encrypt the block volumes

You must encrypt volumes inside the trusted execution environment (TEE) to ensure data stays private. Rather than relying on host-level CSI drivers, you attach raw blocks, use an init container for Linux Unified Key Setup (LUKS) formatting, and mount to your app by using shared namespaces and hooks. This keeps data secure in use, in memory, and at rest.

Prerequisites

  • You have installed the Container Storage Interface (CSI) driver configured for raw block volumes. For more information, see This content is not included.Understanding persistent storage.
  • You have installed OpenShift sandboxed containers on a bare-metal server.
  • You have configured an attestation service, such as Red Hat build of Trustee, to provide secrets like the encryption passphrase.

Procedure

  1. Create a storage-encrypted.yaml manifest file for the PersistentVolumeClaim object with the volumeMode parameter set to Block:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: storage-encrypted
    spec:
      accessModes:
        - ReadWriteOnce
      volumeMode: Block
      resources:
        requests:
          storage: <size>
  2. Create the PersistentVolumeClaim object by running the following command:

    $ oc create -f storage-encrypted.yaml
  3. Create an encrypted-pod.yaml manifest file with the complete pod specification:

    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        io.katacontainers.config.hypervisor.cc_init_data: <init_data>
      name: storage-encrypted
      labels:
        app: storage-encrypted
    spec:
      runtimeClassName: kata-cc
      shareProcessNamespace: true
      initContainers:
      - name: format-disk
        image: quay.io/redhat-user-workloads/ose-osc-tenant/osc-storage-helper:on-pr-3fe822e41e1bd31cd2cbfd9468ab087abc58d9a1-linux-x86-64
        command: ["/usr/local/bin/luks-helper", "format-disk"]
        securityContext:
          privileged: true
        restartPolicy: Always
        env:
          - name: PASS
            valueFrom:
              secretKeyRef:
                name: <my_sealed_secret>
                key: <secret_key>
        volumeMounts:
          - name: storage-ipc
            mountPath: /dev/shm
        volumeDevices:
          - name: luks-block
            devicePath: /dev/block-device
      - name: check-ready
        image: quay.io/redhat-user-workloads/ose-osc-tenant/osc-storage-helper:on-pr-3fe822e41e1bd31cd2cbfd9468ab087abc58d9a1-linux-x86-64
        command: ["/usr/local/bin/luks-helper", "wait-ready"]
        securityContext:
          privileged: true
        volumeMounts:
          - name: storage-ipc
            mountPath: /dev/shm
      containers:
      - name: <container_name>
        image: <image_name>
        ports:
          - containerPort: 8888
        env:
          - name: DATA_DIR
            value: <mount_point>
        lifecycle:
          postStart:
            exec:
              command:
                - /bin/sh
                - -c
                - |
                  PID=$(cat /dev/shm/luks-helper.pid)
                  chmod ug+w "$(dirname "$DATA_DIR")"
                  ln -sfn "/proc/$PID/root/mnt/storage" "$DATA_DIR"
        securityContext:
          privileged: true
        volumeMounts:
          - name: storage-ipc
            mountPath: /dev/shm
      volumes:
      - name: luks-block
        persistentVolumeClaim:
          claimName: storage-encrypted
      - name: storage-ipc
        emptyDir:
          medium: Memory

    where:

    <init_data>
    Specifies the initdata for the runtime configuration.
    <my_sealed_secret>
    Specifies the name of the sealed secret that contains the LUKS encryption passphrase.
    <secret_key>
    Specifies the key within the sealed secret that contains the encryption passphrase.
    <container_name>
    Specifies the container name for your application container.
    <image_name>
    Specifies the image name.
    <mount_point>
    Specifies the mount point for encrypted storage inside your application container.
  4. Create the pod by running the following command:

    $ oc create -f encrypted-pod.yaml

Verification

  1. Verify that the pod is running by running the following command:

    $ oc get pod storage-encrypted
    NAME                READY   STATUS    RESTARTS   AGE
    storage-encrypted   1/1     Running   0          30s
  2. Confirm that the LUKS formatting completed without errors by checking the pod logs:

    $ oc logs storage-encrypted -c format-disk

    Confirm that the LUKS formatting completed without errors.

4.10. Configuring confidential containers for NVIDIA GPUs

Configure confidential containers to use NVIDIA graphics processing units (GPUs). By configuring the required Operators and custom resources, you can provision both regular and confidential GPUs for your sandboxed workloads.

4.10.1. NVIDIA GPUs as trusted execution environments

Use NVIDIA graphics processing units (GPUs) as a trusted execution environment (TEE) to provide hardware-based isolation for your confidential workloads. Leveraging NVIDIA GPUs within a TEE protects data and code in memory from unauthorized access or tampering, even from privileged users or the host operating system.

When you deploy confidential containers on bare-metal servers with NVIDIA GPU support, you must manually configure the MachineConfig with the required kernel arguments for GPU integration. After configuring the MachineConfig, verify that the kernel arguments are correctly applied to the machine config pool where Kata containers and GPU support are configured to run.

4.10.2. Create a MachineConfig for NVIDIA GPUs

Enable Input-Output Memory Management Unit (IOMMU) kernel parameters on your worker nodes. This configuration helps you support graphics processing unit (GPU) pass-through for your sandboxed containers.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create a gpu-machine-config.yaml manifest file according to the following example:

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    metadata:
      labels:
        machineconfiguration.openshift.io/role: worker
      name: 100-iommu-kernel-args
    spec:
      config:
        ignition:
          version: 3.2.0
      kernelArguments:
      - amd_iommu=on
      - intel_iommu=on
    Note

    If using Single Node OpenShift (SNO), replace worker with master in the machineconfiguration.openshift.io/role label.

    The nodes will reboot after applying this configuration.

  2. Create the config map by running the following command:

    $ oc create -f gpu-machine-config.yaml

Verification

  • Verify the kernel parameters are set by running the following commands:

    $ oc debug node/<node_name>
    $ cat /proc/cmdline | grep iommu

4.10.3. Install the Node Feature Discovery Operator

Install the Node Feature Discovery (NFD) Operator to detect hardware features and system configurations on your cluster nodes. This tool enables automatic labeling based on the detected features

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Install the Node Feature Discovery (NFD) Operator by following the This content is not included.OpenShift Container Platform documentation.

Verification

  • Verify the NFD Operator is active by running the following command:

    $ oc get pods -n openshift-nfd

    Example output

    NAME                                      READY   STATUS    RESTARTS   AGE
    nfd-controller-manager-5d8d9d9f8b-abcde   2/2     Running   0          2m

4.10.4. Create a node feature rule for NVIDIA GPUs

Create a NodeFeatureRule custom resource to match NVIDIA kernel modules on your cluster. This custom resource enables the automatic labeling of nodes with compatible NVIDIA graphics processing units.

Prerequisites

  • You have created the NodeFeatureDiscovery custom resource.
  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create a NodeFeatureRule custom resource to match NVIDIA kernel modules by running the following command:

    apiVersion: nfd.openshift.io/v1alpha1
    kind: NodeFeatureRule
    metadata:
      name: nvidia-kernel-modules
    spec:
      rules:
        - name: kernel-module-gdrdrv
          labels:
            nvidia.com/gdrcopy.capable: "true"
          matchFeatures:
            - feature: kernel.loadedmodule
              matchExpressions:
                gdrdrv:
                  op: Exists
        - name: kernel-module-nvidia_fs
          labels:
            nvidia.com/gds.capable: "true"
          matchFeatures:
            - feature: kernel.loadedmodule
              matchExpressions:
                nvidia_fs:
                  op: Exists
        - name: kernel-module-nvidia_peermem
          labels:
            nvidia.com/peermem.capable: "true"
          matchFeatures:
            - feature: kernel.loadedmodule
              matchExpressions:
                nvidia_peermem:
                  op: Exists
  2. Create the NodeFeatureRule CR by running the following command:

    $ oc create -f my-nfd-gpu.yaml

Verification

  1. Verify that the NodeFeatureRule CR is present by running the following command:

    $ oc get nodefeaturerule -n openshift-nfd

    Confirm that nvidia-kernel-modules appears in the output.

  2. Verify that GPU-related node labels appear on your worker nodes by running the following command:

    $ oc get nodes --show-labels | grep nvidia

4.10.5. Install the NVIDIA GPU Operator

You must install the NVIDIA graphics processing unit (GPU) Operator to manage GPU resources in your cluster.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

Verification

  1. Verify that the GPU Operator pods are running by running the following command:

    $ oc get pods -n nvidia-gpu-operator
    NAME                                       READY   STATUS    RESTARTS   AGE
    gpu-operator-1234567890-abcde              1/1     Running   0          10m

4.10.6. Create the ClusterPolicy CR for NVIDIA GPUs

Create a ClusterPolicy custom resource (CR) to configure the NVIDIA graphics processing unit (GPU) Operator. This policy helps you correctly set up and manage the Operator for use with OpenShift sandboxed containers.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create a my-cluster-policy-gpu.yaml manifest file according to the following example:

    apiVersion: nvidia.com/v1
    kind: ClusterPolicy
    metadata:
      name: gpu-cluster-policy
    spec:
      ccManager:
        defaultMode: "on"
        enabled: true
      cdi:
        default: false
        enabled: true
        nriPluginEnabled: false
      daemonsets:
        rollingUpdate:
          maxUnavailable: '1'
        updateStrategy: RollingUpdate
      dcgm:
        enabled: false
      dcgmExporter:
        config:
          name: ''
        enabled: false
        serviceMonitor:
          enabled: true
      devicePlugin:
        config:
          default: ''
          name: ''
        enabled: false
        mps:
          root: /run/nvidia/mps
      driver:
        certConfig:
          name: ''
        enabled: false
        kernelModuleConfig:
          name: ''
        kernelModuleType: auto
        licensingConfig:
          configMapName: ''
          nlsEnabled: true
        repoConfig:
          configMapName: ''
        upgradePolicy:
          autoUpgrade: true
          drain:
            deleteEmptyDir: false
            enable: false
            force: false
            timeoutSeconds: 300
          maxParallelUpgrades: 1
          maxUnavailable: 25%
          podDeletion:
            deleteEmptyDir: false
            force: false
            timeoutSeconds: 300
          waitForCompletion:
            timeoutSeconds: 0
        useNvidiaDriverCRD: false
        useOpenKernelModules: false
        virtualTopology:
          config: ''
      gdrcopy:
        enabled: false
      gds:
        enabled: false
      gfd:
        enabled: true
      kataManager:
        enabled: false
      mig:
        strategy: single
      migManager:
        enabled: false
      nodeStatusExporter:
        enabled: true
      operator:
        defaultRuntime: crio
        initContainer: {}
        runtimeClass: nvidia
        use_ocp_driver_toolkit: true
      kataSandboxDevicePlugin:
        enabled: true
        env:
          - name: P_GPU_ALIAS
            value: pgpu
          - name: NVSWITCH_ALIAS
            value: nvswitch
      sandboxWorkloads:
        defaultWorkload: vm-passthrough
        enabled: true
        mode: kata
      toolkit:
        enabled: false
        installDir: /usr/local/nvidia
      validator:
        plugin:
          env:
            - name: WITH_WORKLOAD
              value: 'false'
      vfioManager:
        enabled: true
        env:
          - name: BIND_NVSWITCHES
            value: 'true'
      vgpuDeviceManager:
        enabled: false
      vgpuManager:
        enabled: false
  2. Create the ClusterPolicy CR by running the following command:

    $ oc create -f my-cluster-policy-gpu.yaml

Verification

  1. Verify that the required labels are present on your worker nodes by running the following command:

    $ oc get nodes -o json | jq '.items[].metadata.labels | with_entries(select(.key | startswith("nvidia.com")))'
    "nvidia.com/cc.mode.state"
    "nvidia.com/cc.ready.state"
    "nvidia.com/gpu.deploy.cc-manager"
    "nvidia.com/gpu.deploy.kata-manager"
    "nvidia.com/gpu.deploy.kata-sandbox-device-plugin"
    "nvidia.com/gpu.deploy.sandbox-validator"
    "nvidia.com/gpu.deploy.vfio-manager"
    "nvidia.com/gpu.present"
  2. Verify the GPU Operator setup by running the following command:

    $ oc get pods -n nvidia-gpu-operator
    NAME                                                READY   STATUS    RESTARTS      AGE
    gpu-operator-cb99f5757-djl7k                        1/1     Running   2             16h
    nvidia-cc-manager-hjd6t                             1/1     Running   5 (42m ago)   16h
    nvidia-kata-sandbox-device-plugin-daemonset-wn6bc   1/1     Running   2             16h
    nvidia-sandbox-validator-7cvx5                      1/1     Running   0             70m
    nvidia-vfio-manager-zsmqn                           1/1     Running   2             16h
  3. Verify the nvidia-cc-manager daemon set by running the following command:

    $ oc get daemonset -n nvidia-gpu-operator | grep cc-manager
    nvidia-cc-manager     1         1         1       1            1           nvidia.com/gpu.deploy.cc-manager=true   7m43s

4.10.7. Create a sample GPU pod

To confirm that GPU resources are allocated correctly, create a sample pod.

Procedure

  1. Create a sample-gpu-pod.yaml manifest file with the following content:

    apiVersion: v1
    kind: Pod
    metadata:
      name: sample-gpu-pod
      annotations:
        io.katacontainers.config.hypervisor.default_memory: "32768"
        io.katacontainers.config.hypervisor.cc_init_data: "H4sIAAAAAAAAA6WUS2/TQBCA7/4Vli85xQ1IoKpSDyUJUIkQy07JoYqiyXpir7IPszsONb++YyIQINauxMGHnfk875kzOi+tiW/jZJa+SmdJBKqyTlKte5mv4fWbt0n0WALBLkoaq6ToUoeVTVg/mUyiBsQJKoz5M7S/AFFU4hFaRfFdWd7l2WeUVX2wzuf4tUVP8c1tTK7F37HiGzQh9VxZjwWV0gQJ23TvpcKg3iEQzq0hkAbdMFaAKQ/2KQQtWOhsN0Itn1Bkzgr0waw/IK2QnBRDxHq9Wp65tEGkly6Q81JBM5+kp3tD6I7A8QxRuW0pTKxQf7TUqLZ613Fuh2C510ZxmefZA/8RYjJo/XhHslape83DFQJyhLIg7lvQUY7ansc9XbCCQOEX6Ujaoy9qcLiyraFgSXL0iGXOs2D1As8DWKvHYyiQLv3kKdxIHUyauezHpgUBWRlQI/PHuToaj6mnNg6ENNUAQ/4FlmwzYmhD3bbfci+/B5N/aMqX7PIFWzY1anSghtt4gX/tyDA2vCRbkDRS+C0fWPz30PYnNQFIyWr188Q+kj2h2QtrjrLyu7/e6enAstap/mDXRM3N1RWLph7dWQpM2awnxKltuAxk3dR3/NY317NrPve9/SgRZf2nx9NB7CIDGnujQuz5nfyXj2f3zZjpaQYAAA=="
    spec:
      runtimeClassName: kata-cc-nvidia-gpu
      restartPolicy: OnFailure
      containers:
        - name: gpu-cc-verifier
          image: quay.io/openshift_sandboxed_containers/gpu-verifier:ubi9
          imagePullPolicy: IfNotPresent
          command: ["/bin/bash"]
          args:
            - -c
            - |
              /opt/cuda-samples/Samples/0_Introduction/vectorAdd/build/vectorAdd
              sleep 36000
          resources:
            limits:
              nvidia.com/pgpu: 1
          securityContext:
            privileged: false
    Note

    The io.katacontainers.config.hypervisor.cc_init_data annotation includes a permissive kata-agent policy for verification purposes. The embedded kata-agent policy disables the exec and log APIs. This configuration does not include a Key Broker Service (KBS) URL, which prevents issues in customer environments where the KBS URL might not align to the actual deployment.

  2. Apply the manifest by running the following command:

    $ oc apply -f sample-gpu-pod.yaml

Verification

  1. Verify that the sample pod is running by running the following command:

    $ oc get pods
    NAME               READY   STATUS    RESTARTS   AGE
    sample-gpu-pod     1/1     Running   0          2m
  2. Check the pod logs to verify GPU functionality by running the following command:

    $ oc logs sample-gpu-pod
    [Vector addition of 50000 elements]
    Copy input data from the host memory to the CUDA device
    CUDA kernel launch with 196 blocks of 256 threads
    Copy output data from the CUDA device to the host memory
    Test PASSED
    Done

4.10.8. Required node labels for GPU runtime classes

Apply specific labels to your worker nodes so you can use NVIDIA graphics processing units (GPUs) with OpenShift sandboxed containers. The NVIDIA GPU Operator typically adds these labels automatically when it detects compatible hardware configured for VFIO passthrough mode.

The required labels depend on whether you are deploying confidential GPUs.

Labels for confidential GPUs

For confidential GPU workloads using the kata-cc-nvidia-gpu runtime class, nodes must have the base Kata and GPU labels, plus additional labels for confidential computing and the Trusted Execution Environment (TEE). Nodes must have the following labels:

  • Base Kata label:

    • feature.node.kubernetes.io/runtime.kata: "true"
  • Base GPU labels:

    • nvidia.com/gpu.present: "true"
    • nvidia.com/gpu.deploy.vfio-manager: "true"
    • nvidia.com/gpu.deploy.kata-sandbox-device-plugin: "true"
  • Confidential computing GPU labels:

    • nvidia.com/cc.mode.state: "on"
    • nvidia.com/cc.ready.state: "true"
    • nvidia.com/gpu.deploy.cc-manager: "true"
  • TEE label (one of the following):

    • intel.feature.node.kubernetes.io/tdx: "true"
    • amd.feature.node.kubernetes.io/snp: "true"

4.11. Configure workloads in multi-GPU NVIDIA DGX B200 environments

The NVIDIA DGX B200 system requires additional host-level configuration beyond the standard graphics processing unit (GPU) setup for OpenShift sandboxed containers. Unlike standard GPU configurations, the NVIDIA driver runs inside the guest virtual machine (VM) rather than on the host.

To enable multi-GPU NVLink workloads, You must install Fabric Manager and the NVLink Switch Manager (NVLSM) on the host. To do so install Fabric Manager and NVLSM on the Red Hat Enterprise Linux CoreOS (RHCOS) hotfix layer, you can use use the rpm-ostree usroverlay command. Because the hotfix layer is non-persistent, you must reinstall these components after each node reboot or OpenShift Container Platform upgrade.

For confidential containers workloads with four or more GPUs, you must also configure extended kubelet and CRI-O timeouts to prevent premature termination of the GPU initialization process.

4.11.1. Create the ClusterPolicy CR

To configure the NVIDIA graphics processing unit (GPU) Operator for the DGX B200 system. create a ClusterPolicy custom resource (CR). This policy helps you correctly set up and manage the NVIDIA GPU Operator for use with OpenShift sandboxed containers.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create a dgx-b200-cluster-policy.yaml manifest file according to the following example:

    apiVersion: nvidia.com/v1
    kind: ClusterPolicy
    metadata:
      name: gpu-cluster-policy
    spec:
      ccManager:
        defaultMode: "on"
        enabled: true
      cdi:
        default: false
        enabled: true
        nriPluginEnabled: false
      daemonsets:
        rollingUpdate:
          maxUnavailable: '1'
        updateStrategy: RollingUpdate
      dcgm:
        enabled: false
      dcgmExporter:
        config:
          name: ''
        enabled: false
        serviceMonitor:
          enabled: true
      devicePlugin:
        config:
          default: ''
          name: ''
        enabled: false
        mps:
          root: /run/nvidia/mps
      driver:
        certConfig:
          name: ''
        enabled: false
        kernelModuleConfig:
          name: ''
        kernelModuleType: auto
        licensingConfig:
          configMapName: ''
          nlsEnabled: true
        repoConfig:
          configMapName: ''
        upgradePolicy:
          autoUpgrade: true
          drain:
            deleteEmptyDir: false
            enable: false
            force: false
            timeoutSeconds: 300
          maxParallelUpgrades: 1
          maxUnavailable: 25%
          podDeletion:
            deleteEmptyDir: false
            force: false
            timeoutSeconds: 300
          waitForCompletion:
            timeoutSeconds: 0
        useNvidiaDriverCRD: false
        useOpenKernelModules: false
        virtualTopology:
          config: ''
      gdrcopy:
        enabled: false
      gds:
        enabled: false
      gfd:
        enabled: true
      kataManager:
        enabled: false
      mig:
        strategy: single
      migManager:
        enabled: false
      nodeStatusExporter:
        enabled: true
      operator:
        defaultRuntime: crio
        initContainer: {}
        runtimeClass: nvidia
        use_ocp_driver_toolkit: true
      kataSandboxDevicePlugin:
        enabled: true
        env:
          - name: P_GPU_ALIAS
            value: pgpu
          - name: NVSWITCH_ALIAS
            value: nvswitch
      sandboxWorkloads:
        defaultWorkload: vm-passthrough
        enabled: true
        mode: kata
      toolkit:
        enabled: false
        installDir: /usr/local/nvidia
      validator:
        plugin:
          env:
            - name: WITH_WORKLOAD
              value: 'false'
      vfioManager:
        enabled: true
        env:
          - name: BIND_NVSWITCHES
            value: 'true'
      vgpuDeviceManager:
        enabled: false
      vgpuManager:
        enabled: false
    Note

    The kataSandboxDevicePlugin section registers GPUs under the nvidia.com/pgpu resource name.

  2. Create the ClusterPolicy CR by running the following command:

    $ oc create -f dgx-b200-cluster-policy.yaml

Verification

  1. Verify that the ClusterPolicy status is ready by running the following command:

    $ oc get clusterpolicy gpu-cluster-policy -o jsonpath='{.status.state}'
    ready
  2. Verify the allocatable GPU resources on the NVIDIA DGX B200 node by running the following command:

    $ oc get node <node_name> -o jsonpath='{.status.allocatable}' | jq

    The output must include nvidia.com/pgpu entries that correspond to the number of GPUs available on the node.

  3. Verify that the CC mode labels are applied to the node by running the following command:

    $ oc get node <node_name> -o json | jq '.metadata.labels | with_entries(select(.key | startswith("nvidia.com/cc")))'
    {
      "nvidia.com/cc.mode.state": "on",
      "nvidia.com/cc.ready.state": "true"
    }

4.11.2. Install Fabric Manager and NVLSM

To configure multi-GPU NVLink workloads, you must install the Fabric Manager and NVLink Switch Manager (NVLSM) RPM packages on the DGX B200 host node.

Prerequisites

  • You have SSH access to the NVIDIA DGX B200 worker node.
  • You have access to the NVIDIA CUDA repository RPM packages.

Procedure

  1. Open a debug session on the NVIDIA DGX B200 worker node by running the following command:

    $ oc debug node/<node_name>
  2. Change to the host root file system by running the following command:

    sh-5.1# chroot /host
  3. Determine the NVIDIA driver version from the kata initrd filename by running the following command:

    # ls /usr/share/kata-containers/osbuilder-images/6.12.0-*/kata*nvidia*
    kata-cc-nvidia-gpu-595.58.03.initrd

    The file name includes the driver version. In this example, the driver version is 595.58.03.

  4. Unlock Red Hat Enterprise Linux CoreOS (RHCOS) for hotfix mode by running the following command:

    # rpm-ostree usroverlay
  5. Find the Fabric Manager and NVLSM RPM packages that match your driver version in the Content from developer.download.nvidia.com is not included.NVIDIA CUDA repository for RHEL 9.

    Note

    The RPM package naming format can vary between driver versions. Search for nvidia-fabricmanager and nvidia-nvlsm packages that match the driver version identified in the previous step.

  6. Install the Fabric Manager RPM by running the following command:

    # rpm -ivh --nodeps <fabricmanager_rpm_url>

    Replace <fabricmanager_rpm_url> with the URL of the Fabric Manager RPM package from the NVIDIA CUDA repository.

  7. Install the NVLSM RPM by running the following command:

    # rpm -ivh --nodeps <nvlsm_rpm_url>

    Replace <nvlsm_rpm_url> with the URL of the NVLSM RPM package from the NVIDIA CUDA repository.

    Important

    The hotfix layer created by rpm-ostree usroverlay is non-persistent. Any RPM packages installed with this method are lost after a node reboot or an OpenShift Container Platform upgrade. You must repeat this procedure after each reboot.

    For a persistent installation, consider using a MachineConfig or rpm-ostree layering.

4.11.3. Install ibstat dependencies for Fabric Manager

Copy the ibstat binary and its required InfiniBand libraries from the container overlay directory to the host file system. Fabric Manager requires these dependencies to manage NVLink switch communication on the NVIDIA DGX B200.

Prerequisites

  • You have an active debug session on the NVIDIA DGX B200 worker node with chroot /host.
Note

Depending on the user’s permissions, you might need to run the following commands with sudo privileges.

Procedure

  1. Find the ibstat binary in the container overlay directory by running the following command:

    # find /var/lib/containers/storage/overlay -path '*/usr/sbin/ibstat' | head -1 | sed 's|/usr/sbin/ibstat||'
  2. Copy the ibstat binary to /usr/sbin/ by running the following command:

    # cp <overlay_path>/usr/sbin/ibstat /usr/sbin/

    Replace <overlay_path> with the path returned in the previous step.

  3. Copy the libibmad library by running the following command:

    # cp <overlay_path>/usr/lib64/libibmad.so.5.* /usr/lib64/
  4. Copy the libibnetdisc library by running the following command:

    # cp <overlay_path>/usr/lib64/libibnetdisc.so.5.* /usr/lib64/
  5. Copy the libibumad library by running the following command:

    # cp <overlay_path>/usr/lib64/libibumad.so.3.* /usr/lib64/
  6. Create the libibmad symlink by running the following command:

    # ln -sf /usr/lib64/libibmad.so.5.* /usr/lib64/libibmad.so.5
  7. Create the libibnetdisc symlink by running the following command:

    # ln -sf /usr/lib64/libibnetdisc.so.5.* /usr/lib64/libibnetdisc.so.5
  8. Create the libibumad symlink by running the following command:

    # ln -sf /usr/lib64/libibumad.so.3.* /usr/lib64/libibumad.so.3
  9. Update the shared library cache by running the following command:

    # ldconfig

4.11.4. Configure and start Fabric Manager

Configure the partition rail policy and start the Fabric Manager service on the NVIDIA DGX B200 host node. Fabric Manager coordinates NVLink switch communication for multi-GPU workloads.

Prerequisites

  • You have an active debug session on the NVIDIA DGX B200 worker node with chroot /host.
Note

Depending on the user’s permissions, you might need to run the following commands with sudo privileges.

Procedure

  1. Set the partition rail policy to symmetric by running the following command:

    $ sed -i 's/PARTITION_RAIL_POLICY=greedy/PARTITION_RAIL_POLICY=symmetric/' /usr/share/nvidia/nvswitch/fabricmanager.cfg
  2. Enable the Fabric Manager service by running the following command:

    # systemctl enable nvidia-fabricmanager
  3. Start the Fabric Manager service by running the following command:

    # systemctl start nvidia-fabricmanager

Verification

  • Verify that the Fabric Manager service is active by running the following command:

    # systemctl status nvidia-fabricmanager
    Successfully configured all the available GPUs fabric.

4.11.5. Verify the TDX SEAM module

Verify that the Intel® Trust Domain Extensions (TDX) Secure Encrypted Architecture Module (SEAM) is correctly initialized on the NVIDIA DGX B200 node. The TDX SEAM module provides the foundation for confidential containers workloads on the NVIDIA DGX B200.

Prerequisites

  • You have SSH access to the NVIDIA DGX B200 worker node.
  • You have configured the TDX MachineConfig.

Procedure

  1. Check the kernel messages for TDX module initialization by running the following command:

    # dmesg | grep -i tdx

    The output must confirm the TDX module is initialized.

  2. Verify that TDX is enabled in the kvm_intel kernel module parameters by running the following command:

    # cat /sys/module/kvm_intel/parameters/tdx
    Y
    Note

    If the TDX module is not initialized, the Platform Secure Encrypted Architecture Loader (P-SEAMLDR) might have silently rejected an incompatible module version. Verify that the firmware supports TDX and that the TDX kernel parameters are correctly configured in the MachineConfig.

4.11.6. Configure timeouts for multi-GPU confidential containers workloads

When you use 4 or more GPUs for a single confidential containers workload on OpenShift Container Platform 4.22, you must configure both kubelet and CRI-O timeouts. Without these adjustments, the GPU initialization process might exceed the default timeout values and cause pod creation to fail.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create a kubelet-timeout.yaml manifest file according to the following example:

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: custom-kubelet-timeout
    spec:
      machineConfigPoolSelector:
        matchLabels:
          pools.operator.machineconfiguration.openshift.io/master: ""
      kubeletConfig:
        runtimeRequestTimeout: "10m"
  2. Create the KubeletConfig CR by running the following command:

    $ oc create -f kubelet-timeout.yaml
  3. Monitor the update status of MachineConfigPool by running the following command:

    $ oc get mcp --watch

    When the UPDATED column displays True and the UPDATING column displays False for the relevant pool, the update is complete.

    Important

    After the MachineConfigPool update completes, the nodes reboot. You must reinstall the hotfix RPM packages (Fabric Manager, NVLink Switch Manager (NVLSM), and ibstat dependencies) because the hotfix layer does not persist across reboots.

  4. Add the container_create_timeout = 600 setting to the [crio.runtime.runtimes.kata-tdx-nvidia-gpu] section in the /etc/crio/crio.conf.d/50-kata-tdx-nvidia-gpu file on the NVIDIA DGX B200 worker node:

    [crio.runtime.runtimes.kata-tdx-nvidia-gpu]
      runtime_path = "/usr/bin/containerd-shim-kata-v2"
      runtime_type = "vm"
      runtime_root = "/run/vc"
      runtime_config_path = "/etc/kata-containers/kata-tdx-nvidia-gpu/configuration.toml"
      privileged_without_host_devices = true
      runtime_pull_image = true
      container_create_timeout = 600
      allowed_annotations = [
        "io.kubernetes.cri-o.Devices",
      ]
  5. Delete all GPU workload pods by running the following command:

    $ oc delete pods -n <namespace> --all

    Replace <namespace> with the namespace that contains your GPU workload pods.

  6. Restart CRI-O on the NVIDIA DGX B200 worker node by running the following command:

    # systemctl restart crio
    Important

    The CRI-O timeout configuration does not persist across node reboots. You must reapply this configuration after each reboot.

4.11.7. Adjust the security posture for DGX B200

You can switch the GPU Confidential Computing (CC) mode on or off for the NVIDIA DGX B200 by patching the ClusterPolicy custom resource (CR). Switching CC mode changes the GPU security posture and requires you to delete existing GPU workload pods before making the change.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. To disable CC mode:

    1. Delete all GPU workload pods by running the following command:

      $ oc delete pods -n <namespace> --all

      Replace <namespace> with the namespace that contains your GPU workload pods.

    2. Stop the Fabric Manager service on the NVIDIA DGX B200 worker node by running the following command:

      # systemctl stop nvidia-fabricmanager
    3. Patch the ClusterPolicy CR to disable CC mode by running the following command:

      $ oc patch clusterpolicy gpu-cluster-policy --type merge -p '{"spec":{"ccManager":{"defaultMode":"off"}}}'
    4. Verify that the CC mode labels are updated on the node by running the following command:

      $ oc get node <node_name> -o json | jq '.metadata.labels | with_entries(select(.key | startswith("nvidia.com/cc")))'
      {
        "nvidia.com/cc.mode.state": "off",
        "nvidia.com/cc.ready.state": "false"
      }
    5. Restart the Fabric Manager service by running the following command:

      # systemctl start nvidia-fabricmanager

      Fabric Manager is required for CUDA operations in non-CC mode. You must restart it after switching CC mode off.

    6. Deploy your workloads using the kata-nvidia-gpu runtime class for non-CC GPU workloads.
  2. To enable CC mode:

    1. Delete all GPU workload pods by running the following command:

      $ oc delete pods -n <namespace> --all

      Replace <namespace> with the namespace that contains your GPU workload pods.

    2. Patch the ClusterPolicy CR to enable CC mode by running the following command:

      $ oc patch clusterpolicy gpu-cluster-policy --type merge -p '{"spec":{"ccManager":{"defaultMode":"on"}}}'
    3. Verify that the CC mode labels are updated on the node by running the following command:

      $ oc get node <node_name> -o json | jq '.metadata.labels | with_entries(select(.key | startswith("nvidia.com/cc")))'
      {
        "nvidia.com/cc.mode.state": "on",
        "nvidia.com/cc.ready.state": "true"
      }
    4. Start the Fabric Manager service by running the following command:

      # systemctl start nvidia-fabricmanager
    5. Deploy your workloads using the kata-cc-nvidia-gpu runtime class for confidential containers GPU workloads.

      Note

      Fabric Manager is required for multi-GPU workloads in both CC and non-CC modes. Single-GPU workloads in CC mode do not require Fabric Manager.

Chapter 5. Upgrade

You update confidential containers by updating the OpenShift Container Platform cluster and the OpenShift sandboxed containers Operator.

You must perform the following steps:

  1. Update your OpenShift Container Platform cluster to update the Kata runtime and its dependencies.

    The RHCOS extension sandboxed containers contains the required components to run OpenShift sandboxed containers, such as the Kata containers runtime, the hypervisor Quick Emulator (QEMU), and other dependencies. You update the extension by updating the cluster to a new release of OpenShift Container Platform.

  2. Update the OpenShift sandboxed containers Operator.

5.1. Upgrade the OpenShift sandboxed containers Operator

You can upgrade the OpenShift sandboxed containers Operator by using the command-line interface (CLI).

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Create an osc-subscription.yaml manifest file:

    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: sandboxed-containers-operator
      namespace: openshift-sandboxed-containers-operator
    spec:
      channel: stable
      installPlanApproval: Automatic
      name: sandboxed-containers-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
      startingCSV: sandboxed-containers-operator.v1.13.1
  2. Create the subscription by running the following command:

    $ oc create -f osc-subscription.yaml

Verification

  1. Verify that the Operator upgrade is complete by running the following command:

    $ oc get csv -n openshift-sandboxed-containers-operator

    This command can take several minutes to complete.

  2. Watch the upgrade progress by running the following command:

    $ watch oc get csv -n openshift-sandboxed-containers-operator
    NAME                             DISPLAY                                  VERSION   REPLACES    PHASE
    openshift-sandboxed-containers   openshift-sandboxed-containers-operator  1.13.1    1.13.0      Succeeded

    The upgrade is complete when the PHASE column shows Succeeded for the new version.

Important

If you use NVIDIA DGX B200 multi-GPU workloads, you must reinstall the hotfix components after the upgrade completes. The hotfix layer created by rpm-ostree usroverlay is non-persistent and is lost during an OpenShift Container Platform upgrade. For details, see Post-upgrade reinstall procedure.

5.2. NVIDIA DGX B200 upgrade notes

Review the upgrade considerations for NVIDIA DGX B200 multi-GPU workloads.

The following components survive an OpenShift Container Platform upgrade because they are managed by Operators or stored as cluster resources:

  • NVIDIA GPU Operator and ClusterPolicy custom resource (CR)
  • OpenShift sandboxed containers Operator and KataConfig CR
  • TDX SEAM module (firmware-level)
  • KubeletConfig CR for extended timeouts
  • Node Feature Discovery Operator and NodeFeatureRule CR

The following components are removed during an OpenShift Container Platform upgrade and must be reinstalled:

  • Fabric Manager and NVLSM RPM packages
  • ibstat binary and InfiniBand libraries
  • CRI-O container_create_timeout configuration

5.2.1. Post-upgrade reinstall procedure

After an OpenShift Container Platform upgrade completes, reinstall the NVIDIA DGX B200 hotfix components by repeating the following installation procedures:

  1. Install Fabric Manager and NVLSM.
  2. Install ibstat dependencies for Fabric Manager.
  3. Configure and start Fabric Manager.
  4. Configure timeouts for multi-GPU confidential containers workloads (CRI-O timeout only; the KubeletConfig CR persists).

Chapter 6. Uninstallation

You uninstall confidential containers by deleting the workload pods, uninstalling the OpenShift sandboxed containers Operator, and deleting its resources.

You perform the following tasks:

  1. Delete pods that use the kata-cc runtime class.

    Important

    You must delete the workload pods before you delete the KataConfig CR. The pod names usually have the prefix podvm and custom tags, if provided.

  2. Delete the KataConfig custom resource (CR).
  3. Uninstall the OpenShift sandboxed containers Operator.
  4. Delete the KataConfig custom resource definition (CRD).

6.1. Delete workload pods

You must delete your workload pods. The pod names usually have the prefix podvm and custom tags, if provided.

Prerequisites

  • You have installed the jq utility.

Procedure

  1. Search for the pods by running the following command:

    $ oc get pods -A -o json | jq -r '.items[] |
      select(.spec.runtimeClassName == "kata-cc").metadata.name'
  2. Delete each pod by running the following command:

    $ oc delete pod <pod>

Verification

  1. Verify that the pods using the kata-cc runtime class are no longer running by running the following command:

    $ oc get pods -A -o json | jq -r '.items[] | select(.spec.runtimeClassName == "kata-cc").metadata.name'

    Confirm that the command returns no output.

6.2. Delete the KataConfig custom resource

You must delete the KataConfig custom resource (CR).

Deleting the KataConfig CR automatically reboots the worker nodes. Reboot can take from 10 to 60 minutes. The following factors can affect the reboot time:

  • A larger OpenShift Container Platform deployment with a greater number of worker nodes.
  • Activation of the BIOS and Diagnostics utility.
  • Deployment on a hard drive rather than an SSD.
  • Deployment on physical nodes such as bare metal, rather than on virtual nodes.
  • A slow central processing unit (CPU) and network.

Prerequisites

  • You have deleted all pods that use the kata-cc runtime class.

Procedure

  1. Delete the KataConfig CR by running the following command:

    $ oc delete kataconfig example-kataconfig

    The OpenShift sandboxed containers Operator removes all resources that were initially created to enable the runtime on your cluster.

    Important

    When you delete the KataConfig CR, the command-line interface (CLI) stops responding until all worker nodes reboot. You must wait for the deletion process to complete before performing the verification.

Verification

  1. Confirm that the KataConfig CR no longer exists by running the following command:

    $ oc get kataconfig example-kataconfig
    Error from server (NotFound): kataconfigs.kataconfiguration.openshift.io "example-kataconfig" not found

6.3. Uninstall the OpenShift sandboxed containers Operator

You uninstall the OpenShift sandboxed containers Operator by using the command line.

Prerequisites

  • You have deleted all pods with the kata-cc runtime class.

Procedure

  1. Delete the subscription by running the following command:

    $ oc delete subscription sandboxed-containers-operator -n openshift-sandboxed-containers-operator
  2. Delete the namespace by running the following command:

    $ oc delete namespace openshift-sandboxed-containers-operator

6.4. Delete the KataConfig CRD

You must delete the KataConfig custom resource definition (CRD).

Procedure

  1. Delete the KataConfig CRD by running the following command:

    $ oc delete crd kataconfigs.kataconfiguration.openshift.io

Verification

  1. Confirm that the KataConfig CRD no longer exists by running the following command:

    $ oc get crd kataconfigs.kataconfiguration.openshift.io
    Error from server (NotFound): customresourcedefinitions.apiextensions.k8s.io "kataconfigs.kataconfiguration.openshift.io" not found

Chapter 7. Observability

You can monitor the health of your confidential containers environment.

The following tools are available:

  • OpenShift Container Platform web console. Administrators can access and query raw metrics through Prometheus.
  • Logging

7.1. Metrics

You can monitor system health by querying metrics displayed in the OpenShift Container Platform web console.

You can access the following metrics:

Kata agent metrics
Kata agent metrics display information about the kata agent process running in the virtual machine (VM) embedded in your sandboxed containers. These metrics include data from /proc/<pid>/[io, stat, status].
Kata guest operating system metrics
Kata guest operating system metrics display data from the guest operating system running in your sandboxed containers. These metrics include data from /proc/[stats, diskstats, meminfo, vmstats] and /proc/net/dev.
Hypervisor metrics
Hypervisor metrics display data regarding the hypervisor running the VM embedded in your sandboxed containers. These metrics mainly include data from /proc/<pid>/[io, stat, status].
Kata monitor metrics
Kata monitor is the process that gathers metric data and makes it available to Prometheus. The kata monitor metrics display detailed information about the resource usage of the kata-monitor process itself. These metrics also include counters from Prometheus data collection.
Kata containerd shim v2 metrics
Kata containerd shim v2 metrics display detailed information about the kata shim process. These metrics include data from /proc/<pid>/[io, stat, status] and detailed resource usage metrics.

7.2. View OpenShift sandboxed containers metrics

You can access the metrics for OpenShift sandboxed containers in the Metrics page in the OpenShift Container Platform web console.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role or with view permissions for all projects.

Procedure

  1. In the OpenShift Container Platform web console, navigate to ObserveMetrics.
  2. In the input field, enter the query for the metric you want to observe.

    All kata-related metrics begin with kata. Typing kata displays a list of all available kata metrics.

    The metrics from your query are visualized on the page.

Troubleshooting

  • If no metrics are shown, verify that the query begins with kata and confirm that OpenShift sandboxed containers workloads are running. To do so, check whether any pods use a kata runtime class:

    $ oc get pods -A -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.runtimeClassName}{"\n"}{end}' | grep kata

    If no pods are using a kata runtime class, the cluster generates no OpenShift sandboxed containers metrics.

7.3. Enable debug logs for CRI-O runtime

You can enable debug logs by updating the logLevel field in the KataConfig custom resource (CR). This changes the log level in the Container Runtime Interface (CRI-O) runtime for the worker nodes running OpenShift sandboxed containers.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Change the logLevel field in your existing KataConfig CR to debug:

    $ oc patch kataconfig <kataconfig> --type merge --patch '{"spec":{"logLevel":"debug"}}'
  2. Monitor the kata-oc machine config pool until the value of UPDATED is True, indicating that all worker nodes are updated:

    $ oc get mcp kata-oc

    Example output

    NAME     CONFIG                 UPDATED  UPDATING  DEGRADED  MACHINECOUNT  READYMACHINECOUNT  UPDATEDMACHINECOUNT  DEGRADEDMACHINECOUNT  AGE
    kata-oc  rendered-kata-oc-169   False    True      False     3             1                  1                    0                     9h

Verification

  1. Start a debug session with a node in the machine config pool:

    $ oc debug node/<node_name>
  2. Change the root directory to /host:

    # chroot /host
  3. Verify the changes in the crio.conf file:

    # crio config | egrep 'log_level

    Example output

    log_level = "debug"

7.4. View debug logs for OpenShift sandboxed containers components

Cluster administrators can use the debug logs to troubleshoot issues. The logs for each node are printed to the node journal.

You can review the logs for the following OpenShift sandboxed containers components:

  • Kata agent
  • Kata runtime (containerd-shim-kata-v2)
  • virtiofsd

Quick Emulator (QEMU) only generates warning and error logs. These warnings and errors print to the node journal in both the Kata runtime logs and the Container Runtime Interface (CRI-O) logs with an extra qemuPid field.

Example of QEMU logs:

Mar 11 11:57:28 openshift-worker-0 kata[2241647]: time="2023-03-11T11:57:28.587116986Z" level=info msg="Start logging QEMU (qemuPid=2241693)" name=containerd-shim-v2 pid=2241647 sandbox=d1d4d68efc35e5ccb4331af73da459c13f46269b512774aa6bde7da34db48987 source=virtcontainers/hypervisor subsystem=qemu

Mar 11 11:57:28 openshift-worker-0 kata[2241647]: time="2023-03-11T11:57:28.607339014Z" level=error msg="qemu-kvm: -machine q35,accel=kvm,kernel_irqchip=split,foo: Expected '=' after parameter 'foo'" name=containerd-shim-v2 pid=2241647 qemuPid=2241693 sandbox=d1d4d68efc35e5ccb4331af73da459c13f46269b512774aa6bde7da34db48987 source=virtcontainers/hypervisor subsystem=qemu

Mar 11 11:57:28 openshift-worker-0 kata[2241647]: time="2023-03-11T11:57:28.60890737Z" level=info msg="Stop logging QEMU (qemuPid=2241693)" name=containerd-shim-v2 pid=2241647 sandbox=d1d4d68efc35e5ccb4331af73da459c13f46269b512774aa6bde7da34db48987 source=virtcontainers/hypervisor subsystem=qemu

The Kata runtime prints Start logging QEMU when QEMU starts, and Stop Logging QEMU when QEMU stops. The error appears in between these two log messages with the qemuPid field. The actual error message from QEMU appears in red.

The console of the QEMU guest is printed to the node journal as well. You can view the guest console logs together with the Kata agent logs.

Prerequisites

  • You have workloads running with the kata-cc runtime class.
  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  • To review the Kata agent logs and guest console logs, run the following command:

    $ oc debug node/<nodename> -- journalctl -D /host/var/log/journal -t kata -g “reading guest console”
  • To review the Kata runtime logs, run the following command:

    $ oc debug node/<nodename> -- journalctl -D /host/var/log/journal -t kata
  • To review the virtiofsd logs, run the following command:

    $ oc debug node/<nodename> -- journalctl -D /host/var/log/journal -t virtiofsd
  • To review the QEMU logs, run the following command:

    $ oc debug node/<nodename> -- journalctl -D /host/var/log/journal -t kata -g "qemuPid=\d+"
    Note

    This command uses a Perl-compatible regular expression (PCRE). If the command returns no output, confirm that QEMU is in use on the node before assuming a pattern-matching failure.

Verification

  • Verify that the output of each oc debug command in the previous steps contains timestamped log entries with a level= field. This indicates that the component is logging to the node journal.
  • If a command returns no output, verify that the node is running workloads that use the kata-cc runtime class, or that QEMU is in use on the node before assuming a pattern-matching failure.

Chapter 8. Troubleshooting

You can open a Red Hat support case and provide debugging information by using must-gather. The must-gather tool collects diagnostic information about your OpenShift Container Platform cluster, including virtual machines and other data.

8.1. Use the must-gather utility

If you must open a Red Hat support case, you must use the must-gather utility to collect diagnostic information about your OpenShift Container Platform cluster, including virtual machines and other data. The oc adm must-gather command collects the information from your cluster for debugging issues, including resource definitions and service logs. By default, the oc adm must-gather command uses the default plugin image and writes into ./must-gather.local.

  • To collect data related to one or more specific features, use the --image argument:

    $ oc adm must-gather --image=registry.redhat.io/openshift-sandboxed-containers/osc-must-gather-rhel9:1.13.1
  • To collect audit logs, use the -- /usr/bin/gather_audit_logs argument:

    $ oc adm must-gather -- /usr/bin/gather_audit_logs
    Note

    Audit logs are not collected as part of the default set of information to reduce the size of the files.

  • When you run oc adm must-gather, a new pod with a random name is created in a new project on the cluster. The data is collected on that pod and saved in a new directory that starts with must-gather.local. This directory is created in the current working directory.

    NAMESPACE                      NAME                 READY   STATUS      RESTARTS      AGE
    ...
    openshift-must-gather-5drcj    must-gather-bklx4    2/2     Running     0             72s
    openshift-must-gather-5drcj    must-gather-s8sdh    2/2     Running     0             72s
    ...

    Optionally, you can run the oc adm must-gather command in a specific namespace by using the --run-namespace option.

    $ oc adm must-gather --run-namespace <namespace> --image=registry.redhat.io/openshift-sandboxed-containers/osc-must-gather-rhel9:1.13.1

Chapter 9. KataConfig status messages

The following table displays the status messages for the KataConfig custom resource (CR) for a cluster with two worker nodes.

Table 9.1. KataConfig status messages

StatusDescription

Initial installation

When a KataConfig CR is created and starts installing kata-cc on both workers, the following status is displayed for a few seconds.

 conditions:
    message: Performing initial installation of kata-cc on cluster
    reason: Installing
    status: 'True'
    type: InProgress
 kataNodes:
   nodeCount: 0
   readyNodeCount: 0

Installing

Within a few seconds the status changes.

 kataNodes:
   nodeCount: 2
   readyNodeCount: 0
   waitingToInstall:
   - worker-0
   - worker-1

Installing (Worker-1 installation starting)

For a short period of time, the status changes, signifying that one node has initiated the installation of kata-cc, while the other is in a waiting state. This is because only one node can be unavailable at any given time. The nodeCount remains at 2 because both nodes will eventually receive kata-cc, but the readyNodeCount is currently 0 as neither of them has reached that state yet.

 kataNodes:
   installing:
   - worker-1
   nodeCount: 2
   readyNodeCount: 0
   waitingToInstall:
   - worker-0

Installing (Worker-1 installed, worker-0 installation started)

After some time, worker-1 will complete its installation, causing a change in the status. The readyNodeCount is updated to 1, indicating that worker-1 is now prepared to execute kata-cc workloads. You cannot schedule or run kata-cc workloads until the runtime class is created at the end of the installation process.

 kataNodes:
   installed:
   - worker-1
   installing:
   - worker-0
   nodeCount: 2
   readyNodeCount: 1

Installed

When installed, both workers are listed as installed, and the InProgress condition transitions to False without specifying a reason, indicating the successful installation of kata-cc on the cluster.

 conditions:
    message: ""
    reason: ""
    status: 'False'
    type: InProgress
 kataNodes:
   installed:
   - worker-0
   - worker-1
   nodeCount: 2
   readyNodeCount: 2
StatusDescription

Initial uninstall

If kata-cc is installed on both workers, and you delete the KataConfig to remove kata-cc from the cluster, both workers briefly enter a waiting state for a few seconds.

 conditions:
    message: Removing kata-cc from cluster
    reason: Uninstalling
    status: 'True'
    type: InProgress
 kataNodes:
   nodeCount: 0
   readyNodeCount: 0
   waitingToUninstall:
   - worker-0
   - worker-1

Uninstalling

After a few seconds, one of the workers starts uninstalling.

 kataNodes:
   nodeCount: 0
   readyNodeCount: 0
   uninstalling:
   - worker-1
   waitingToUninstall:
   - worker-0

Uninstalling

Worker-1 finishes and worker-0 starts uninstalling.

 kataNodes:
   nodeCount: 0
   readyNodeCount: 0
   uninstalling:
   - worker-0
Note

The reason field can also report the following causes:

  • Failed: This is reported if the node cannot finish its transition. The status reports True and the message is Node <node_name> Degraded: <error_message_from_the_node>.
  • BlockedByExistingKataPods: This is reported if there are pods running on a cluster that use the kata-cc runtime while kata-cc is being uninstalled. The status field is False and the message is Existing pods using "kata-cc" RuntimeClass found. Please delete the pods manually for KataConfig deletion to proceed. There could also be a technical error message reported like Failed to list kata pods: <error_message> if communication with the cluster control plane fails.

Legal Notice

Copyright © Red Hat.
Except as otherwise noted below, the text of and illustrations in this documentation are licensed by Red Hat under the Creative Commons Attribution–Share Alike 3.0 Unported license . If you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, the Red Hat logo, JBoss, Hibernate, and RHCE are trademarks or registered trademarks of Red Hat, LLC. or its subsidiaries in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
XFS is a trademark or registered trademark of Hewlett Packard Enterprise Development LP or its subsidiaries in the United States and other countries.
The OpenStack® Word Mark and OpenStack logo are trademarks or registered trademarks of the Linux Foundation, used under license.
All other trademarks are the property of their respective owners.