Chapter 7. Deploying Confidential Containers on Azure
You can deploy Confidential Containers on Microsoft Azure Cloud Computing Services after you deploy OpenShift sandboxed containers.
Confidential Containers on Azure is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
Cluster requirements
- You have configured outbound connectivity for the pod VM subnet.
- You have installed Red Hat OpenShift Container Platform 4.15 or later on the cluster where you are installing the Confidential compute attestation Operator.
You deploy Confidential Containers by performing the following steps:
- Install the Confidential compute attestation Operator.
- Create the route for Trustee.
- Enable the Confidential Containers feature gate.
- Create initdata.
- Update the peer pods config map.
- Optional: Customize the Kata agent policy.
-
Delete the
KataConfigcustom resource (CR). -
Re-create the
KataConfigCR. - Create the Trustee authentication secret.
- Create the Trustee config map.
- Configure Trustee values, policies, and secrets.
-
Create the
KbsConfigCR. - Verify the Trustee configuration.
- Verify the attestation process.
7.1. Installing the Confidential compute attestation Operator Copy linkLink copied to clipboard!
You can install the Confidential compute attestation Operator on Azure by using the CLI.
Prerequisites
-
You have installed the OpenShift CLI (
oc). -
You have access to the cluster as a user with the
cluster-adminrole.
Procedure
Create a
trustee-namespace.yamlmanifest file:apiVersion: v1 kind: Namespace metadata: name: trustee-operator-systemCreate the
trustee-operator-systemnamespace by running the following command:$ oc apply -f trustee-namespace.yamlCreate a
trustee-operatorgroup.yamlmanifest file:apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: trustee-operator-group namespace: trustee-operator-system spec: targetNamespaces: - trustee-operator-systemCreate the operator group by running the following command:
$ oc apply -f trustee-operatorgroup.yamlCreate a
trustee-subscription.yamlmanifest file:apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: trustee-operator-system namespace: trustee-operator-system spec: channel: stable installPlanApproval: Automatic name: trustee-operator source: redhat-operators sourceNamespace: openshift-marketplaceCreate the subscription by running the following command:
$ oc apply -f trustee-subscription.yamlVerify that the Operator is correctly installed by running the following command:
$ oc get csv -n trustee-operator-systemThis command can take several minutes to complete.
Watch the process by running the following command:
$ watch oc get csv -n trustee-operator-systemExample output
NAME DISPLAY PHASE trustee-operator.v0.3.0 Trustee Operator 0.3.0 Succeeded
7.2. Enabling the Confidential Containers feature gate Copy linkLink copied to clipboard!
You must enable the Confidential Containers feature gate.
Prerequisites
- You have subscribed to the OpenShift sandboxed containers Operator.
Procedure
Create a
cc-feature-gate.yamlmanifest file:apiVersion: v1 kind: ConfigMap metadata: name: osc-feature-gates namespace: openshift-sandboxed-containers-operator data: confidential: "true"Create the config map by running the following command:
$ oc apply -f cc-feature-gate.yaml
7.3. Creating the route for Trustee Copy linkLink copied to clipboard!
You can create a secure route with edge TLS termination for Trustee. External ingress traffic reaches the router pods as HTTPS and passes on to the Trustee pods as HTTP.
Prerequisites
- You have installed the Confidential compute attestation Operator.
Procedure
Create an edge route by running the following command:
$ oc create route edge --service=kbs-service --port kbs-port \ -n trustee-operator-systemNoteNote: Currently, only a route with a valid CA-signed certificate is supported. You cannot use a route with self-signed certificate.
Set the
TRUSTEE_HOSTvariable by running the following command:$ TRUSTEE_HOST=$(oc get route -n trustee-operator-system kbs-service \ -o jsonpath={.spec.host})Verify the route by running the following command:
$ echo $TRUSTEE_HOSTExample output
kbs-service-trustee-operator-system.apps.memvjias.eastus.aroapp.ioRecord this value for the peer pods config map.
7.4. About initdata Copy linkLink copied to clipboard!
The initdata specification provides a flexible way to initialize a peer pod with sensitive or workload-specific data at runtime, avoiding the need to embed such data in the virtual machine (VM) image. This enhances security by reducing 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.regofile to enforce runtime behavior when overriding the default Kata Agent policy.
You can apply an initdata configuration by using one of the following methods:
- Globally by including it in the peer pods config map, setting a cluster-wide default for all pods.
For a specific pod when configuring a pod workload object, allowing customization for individual workloads.
The
io.katacontainers.config.runtime.cc_init_dataannotation you specify when configuring a pod workload object overrides the globalINITDATAsetting in the peer pods config map for that specific pod. The Kata runtime handles this precedence automatically at pod creation time.
The initdata content configures the following components:
- Attestation Agent (AA), which verifies the trustworthiness of the peer pod by sending evidence to the Trustee for attestation.
- Confidential Data Hub (CDH), which manages secrets and secure data access within the peer pod VM.
- Kata Agent, which enforces runtime policies and manages the lifecycle of the containers inside the pod VM.
7.5. Creating initdata Copy linkLink copied to clipboard!
Create a TOML file with initdata and convert it to a Base64-encoded string. Use this string to specify the value in the peer pods config map, in the peer pod manifest, or in the verification-pod.yaml file.
You must delete the kbs_cert setting if you configure insecure_http = true in the Trustee config map.
Procedure
Create the
initdata.tomlconfiguration file:```toml algorithm = "sha384" version = "0.1.0" [data] "aa.toml" = ''' [token_configs] [token_configs.coco_as] url = '<url>:<port>'1 [token_configs.kbs] url = '<url>:<port>' cert = """ -----BEGIN CERTIFICATE----- <kbs_certificate>2 -----END CERTIFICATE----- """ ''' "cdh.toml" = ''' socket = 'unix:///run/confidential-containers/cdh.sock' credentials = [] [kbc] name = 'cc_kbc' url = '<url>:<port>' kbs_cert = """3 -----BEGIN CERTIFICATE----- <kbs_certificate>4 -----END CERTIFICATE----- """ ''' "policy.rego" = '''5 package agent_policy default AddARPNeighborsRequest := true default AddSwapRequest := true default CloseStdinRequest := true default CopyFileRequest := true default CreateContainerRequest := true default CreateSandboxRequest := true default DestroySandboxRequest := true default ExecProcessRequest := 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 ReadStreamRequest := true default RemoveContainerRequest := true default RemoveStaleVirtiofsShareMountsRequest := true default ReseedRandomDevRequest := true default ResumeContainerRequest := true default SetGuestDateTimeRequest := true default SetPolicyRequest := 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 ''' ```- 1
- Specify the URL and port of the Trustee instance. If you configure the Trustee with
insecure_httpfor testing purposes, use HTTP. Otherwise, use HTTPS. For production systems, avoid usinginsecure_httpunless you configure your environment to handle TLS externally, for example, with a proxy. - 2
- Specify the Base64-encoded TLS certificate for the attestation agent. This is not required for testing purposes, but it is recommended for production systems.
- 3
- Delete the
kbs_certsetting if you configureinsecure_http = truein the Trustee config map. - 4
- Specify the Base64-encoded TLS certificate for the Trustee instance.
- 5
- Optional: You can specify a custom Kata Agent policy.
Convert the
initdata.tomlfile to a Base64-encoded string in a text file by running the following command:$ base64 -w0 initdata.toml > initdata.txt
7.6. Updating the peer pods config map Copy linkLink copied to clipboard!
You must update the peer pods config map for Confidential Containers.
Set Secure Boot to true to enable it by default. The default value is false, which presents a security risk.
Procedure
Obtain the following values from your Azure instance:
Retrieve and record the Azure resource group:
$ AZURE_RESOURCE_GROUP=$(oc get infrastructure/cluster -o jsonpath='{.status.platformStatus.azure.resourceGroupName}') && echo "AZURE_RESOURCE_GROUP: \"$AZURE_RESOURCE_GROUP\""Retrieve and record the Azure VNet name:
$ AZURE_VNET_NAME=$(az network vnet list --resource-group ${AZURE_RESOURCE_GROUP} --query "[].{Name:name}" --output tsv)This value is used to retrieve the Azure subnet ID.
Retrieve and record the Azure subnet ID:
$ AZURE_SUBNET_ID=$(az network vnet subnet list --resource-group ${AZURE_RESOURCE_GROUP} --vnet-name $AZURE_VNET_NAME --query "[].{Id:id} | [? contains(Id, 'worker')]" --output tsv) && echo "AZURE_SUBNET_ID: \"$AZURE_SUBNET_ID\""Retrieve and record the Azure network security group (NSG) ID:
$ AZURE_NSG_ID=$(az network nsg list --resource-group ${AZURE_RESOURCE_GROUP} --query "[].{Id:id}" --output tsv) && echo "AZURE_NSG_ID: \"$AZURE_NSG_ID\""Retrieve and record the Azure region:
$ AZURE_REGION=$(az group show --resource-group ${AZURE_RESOURCE_GROUP} --query "{Location:location}" --output tsv) && echo "AZURE_REGION: \"$AZURE_REGION\""
Create a
peer-pods-cm.yamlmanifest file according to the following example:apiVersion: v1 kind: ConfigMap metadata: name: peer-pods-cm namespace: openshift-sandboxed-containers-operator data: CLOUD_PROVIDER: "azure" VXLAN_PORT: "9000" AZURE_INSTANCE_SIZE: "Standard_DC2as_v5"1 AZURE_INSTANCE_SIZES: "Standard_DC2as_v5,Standard_DC4as_v5,Standard_DC8as_v5"2 AZURE_SUBNET_ID: "<azure_subnet_id>"3 AZURE_NSG_ID: "<azure_nsg_id>"4 PROXY_TIMEOUT: "5m" AZURE_IMAGE_ID: "<azure_image_id>"5 AZURE_REGION: "<azure_region>"6 AZURE_RESOURCE_GROUP: "<azure_resource_group>"7 PEERPODS_LIMIT_PER_NODE: "10"8 TAGS: "key1=value1,key2=value2"9 INITDATA: "<base64_encoded_initdata>"10 ENABLE_SECURE_BOOT: "true"11 DISABLECVM: "false"- 1
- The
"Standard_DC2as_v5"value is the default if an instance size is not defined in the workload. Ensure the instance type supports the trusted environment. The default"Standard_DC2as_v5"value is for AMD SEV-SNP. If your TEE is Intel TDX, specifyStandard_EC4eds_v5. - 2
- Specify the instance sizes, without spaces, for creating the pod. This allows you to define smaller instance sizes for workloads that need less memory and fewer CPUs or larger instance sizes for larger workloads. For Intel TDX, specify
"Standard_EC4eds_v5,Standard_EC8eds_v5,Standard_EC16eds_v5". - 3
- Specify the
AZURE_SUBNET_IDvalue that you retrieved. - 4
- Specify the
AZURE_NSG_IDvalue that you retrieved. - 5
- Optional: By default, this value is populated when you run the
KataConfigCR, using an Azure image ID based on your cluster credentials. If you create your own Azure image, specify the correct image ID. - 6
- Specify the
AZURE_REGIONvalue you retrieved. - 7
- Specify the
AZURE_RESOURCE_GROUPvalue you retrieved. - 8
- Specify the maximum number of peer pods that can be created per node. The default value is
10. - 9
- You can configure custom tags as
key:valuepairs for pod VM instances to track peer pod costs or to identify peer pods in different clusters. - 10
- Specify the Base64-encoded string you created in the
initdata.txtfile. - 11
- Specify
trueto enable Secure Boot by default.
Create the config map by running the following command:
$ oc apply -f peer-pods-cm.yamlRestart the
ds/osc-caa-dsdaemon set by running the following command:$ oc set env ds/osc-caa-ds \ -n openshift-sandboxed-containers-operator REBOOT="$(date)"
7.7. Customizing the Kata agent policy Copy linkLink copied to clipboard!
The Kata agent policy is a security mechanism that controls agent API requests for pods running with the Kata runtime. Written in Rego and enforced by the Kata agent within the pod virtual machine (VM), this policy determines which operations are allowed or denied.
By default, the Kata agent policy disables the exec and log APIs, as they might transmit or receive unencrypted data through the control plane, which is insecure.
You can override the default policy with a custom one for specific use cases, such as development and testing where security is not a concern. For example, you might run in an environment where the control plane can be trusted. You can apply a custom policy in several ways:
- Embedding it in the pod VM image.
- Patching the peer pods config map.
- Adding an annotation to the workload pod YAML.
For production systems, the preferred method is to use initdata to override the Kata agent policy. The following procedure applies a custom policy to an individual pod using the io.katacontainers.config.agent.policy annotation. The policy is provided in Base64-encoded Rego format. This approach overrides the default policy at pod creation without modifying the pod VM image.
Enabling the exec or log APIs in Confidential Containers workloads might expose sensitive information. Do not enable these APIs in production environments.
A custom policy replaces the default policy entirely. To modify only specific APIs, include the full policy and adjust the relevant rules.
Procedure
Create a
policy.regofile with your custom policy. The following example shows all configurable APIs, withexecandlogenabled for demonstration:package agent_policy import future.keywords.in import input default CopyFileRequest := false default CreateContainerRequest := false default CreateSandboxRequest := true default DestroySandboxRequest := true default ExecProcessRequest := true # Enabled to allow exec API default GetOOMEventRequest := true default GuestDetailsRequest := true default OnlineCPUMemRequest := true default PullImageRequest := true default ReadStreamRequest := true # Enabled to allow log API default RemoveContainerRequest := true default RemoveStaleVirtiofsShareMountsRequest := true default SignalProcessRequest := true default StartContainerRequest := true default StatsContainerRequest := true default TtyWinResizeRequest := true default UpdateEphemeralMountsRequest := true default UpdateInterfaceRequest := true default UpdateRoutesRequest := true default WaitProcessRequest := true default WriteStreamRequest := falseThis policy enables the
exec(ExecProcessRequest) andlog(ReadStreamRequest) APIs. Adjust thetrueorfalsevalues to customize the policy further based on your needs.Convert the
policy.regofile to a Base64-encoded string by running the following command:$ base64 -w0 policy.regoSave the output for use in the yaml file.
Add the Base64-encoded policy to a
my-pod.yamlpod specification file:apiVersion: v1 kind: Pod metadata: name: <pod_name> annotations: io.katacontainers.config.agent.policy: <base64_encoded_policy> spec: runtimeClassName: kata-remote containers: - name: <container_name> image: registry.access.redhat.com/ubi9/ubi:latest command: - sleep - "36000" securityContext: privileged: false seccompProfile: type: RuntimeDefaultApply the pod manifest by running the following command:
$ oc apply -f my-pod.yaml
7.8. Deleting the KataConfig custom resource Copy linkLink copied to clipboard!
You can delete the KataConfig custom resource (CR) by using the command line.
Deleting the KataConfig CR removes the runtime and its related resources from your cluster.
Deleting the KataConfig CR automatically reboots the worker nodes. The reboot can take from 10 to more than 60 minutes. Factors that impede reboot time are as follows:
- 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 CPU and network.
Prerequisites
-
You have installed the OpenShift CLI (
oc). -
You have access to the cluster as a user with the
cluster-adminrole.
Procedure
Delete the
KataConfigCR by running the following command:$ oc delete kataconfig example-kataconfigThe OpenShift sandboxed containers Operator removes all resources that were initially created to enable the runtime on your cluster.
ImportantWhen you delete the
KataConfigCR, the CLI stops responding until all worker nodes reboot. You must wait for the deletion process to complete before performing the verification.Verify that the custom resource was deleted by running the following command:
$ oc get kataconfig example-kataconfigExample output
No example-kataconfig instances exist
When uninstalling OpenShift sandboxed containers deployed using a cloud provider, you must delete all of the pods. Any remaining pod resources might result in an unexpected bill from your cloud provider.
7.9. Selecting a custom peer pod VM image Copy linkLink copied to clipboard!
You can select a custom peer pod virtual machine (VM) image, tailored to your workload requirements by adding an annotation to the pod manifest. The custom image overrides the default image specified in the peer pods config map.
Prerequisites
- The ID of the custom pod VM image to use, compatible with the cloud provider or hypervisor, is available.
Procedure
Edit the pod manifest by adding the
io.katacontainers.config.hypervisor.imageannotation and save it in apod-manifest.yamlfile:apiVersion: v1 kind: Pod metadata: name: pod-manifest annotations: io.katacontainers.config.hypervisor.image: "<custom_image_id>"1 spec: runtimeClassName: kata-remote2 containers: - name: <example_container>3 image: registry.access.redhat.com/ubi9/ubi:9.3 command: ["sleep", "36000"]Create the pod by running the following command:
$ oc apply -f pod-manifest.yaml
7.10. Re-creating the KataConfig custom resource Copy linkLink copied to clipboard!
You must re-create the KataConfig custom resource (CR) for Confidential Containers.
Creating the KataConfig CR automatically reboots the worker nodes. The reboot can take from 10 to more than 60 minutes. Factors that impede reboot time are as follows:
- A larger OpenShift Container Platform deployment with a greater number of worker nodes.
- Activation of the BIOS and Diagnostics utility.
- Deployment on a hard disk drive rather than an SSD.
- Deployment on physical nodes such as bare metal, rather than on virtual nodes.
- A slow CPU and network.
Prerequisites
-
You have access to the cluster as a user with the
cluster-adminrole.
Procedure
Create an
example-kataconfig.yamlmanifest file according to the following example:apiVersion: kataconfiguration.openshift.io/v1 kind: KataConfig metadata: name: example-kataconfig spec: enablePeerPods: true logLevel: info # kataConfigPoolSelector: # matchLabels: # <label_key>: '<label_value>'1 - 1
- Optional: If you have applied node labels to install
kata-remoteon specific nodes, specify the key and value, for example,cc: 'true'.
Create the
KataConfigCR by running the following command:$ oc apply -f example-kataconfig.yamlThe new
KataConfigCR is created and installskata-remoteas a runtime class on the worker nodes.Wait for the
kata-remoteinstallation to complete and the worker nodes to reboot before verifying the installation.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
kataNodesisinstalledand the conditionInProgressisFalsewithout specifying a reason, thekata-remoteis installed on the cluster.Verify the daemon set by running the following command:
$ oc get -n openshift-sandboxed-containers-operator ds/osc-caa-dsVerify the runtime classes by running the following command:
$ oc get runtimeclassExample output
NAME HANDLER AGE kata kata 152m kata-remote kata-remote 152m
7.11. Creating the Trustee authentication secret Copy linkLink copied to clipboard!
You must create the authentication secret for Trustee.
Prerequisites
-
You have installed the OpenShift CLI (
oc). -
You have access to the cluster as a user with the
cluster-adminrole.
Procedure
Create a private key by running the following command:
$ openssl genpkey -algorithm ed25519 > privateKeyCreate a public key by running the following command:
$ openssl pkey -in privateKey -pubout -out publicKeyCreate a secret by running the following command:
$ oc create secret generic kbs-auth-public-key --from-file=publicKey -n trustee-operator-systemVerify the secret by running the following command:
$ oc get secret -n trustee-operator-system
7.12. Creating the Trustee config map Copy linkLink copied to clipboard!
You must create the config map to configure the Trustee server.
The following configuration example turns off security features to enable demonstration of Technology Preview features. It is not meant for a production environment.
Prerequisites
- You have created a route for Trustee.
Procedure
Create a
kbs-config-cm.yamlmanifest file:apiVersion: v1 kind: ConfigMap metadata: name: kbs-config-cm namespace: trustee-operator-system data: kbs-config.toml: | [http_server] sockets = ["0.0.0.0:8080"] insecure_http = true [admin] insecure_api = true auth_public_key = "/etc/auth-secret/publicKey" [attestation_token] insecure_key = true attestation_token_type = "CoCo" [attestation_service] type = "coco_as_builtin" work_dir = "/opt/confidential-containers/attestation-service" policy_engine = "opa" [attestation_service.attestation_token_broker] type = "Ear" policy_dir = "/opt/confidential-containers/attestation-service/policies" [attestation_service.attestation_token_config] duration_min = 5 [attestation_service.rvps_config] type = "BuiltIn" [attestation_service.rvps_config.storage] type = "LocalJson" file_path = "/opt/confidential-containers/rvps/reference-values/reference-values.json" [[plugins]] name = "resource" type = "LocalFs" dir_path = "/opt/confidential-containers/kbs/repository" [policy_engine] policy_path = "/opt/confidential-containers/opa/policy.rego"Create the config map by running the following command:
$ oc apply -f kbs-config-cm.yaml
7.13. Configuring Trustee values, policies, and secrets Copy linkLink copied to clipboard!
You can configure the following values, policies, and secrets for Trustee:
- Optional: Reference values for the Reference Value Provider Service.
- Optional: Attestation policy.
- Provisioning Certificate Caching Service for Intel Trust Domain Extensions (TDX).
- Optional: Secret for custom keys for Trustee clients.
- Optional: Secret for container image signature verification.
- Container image signature verification policy. This policy is mandatory. If you do not use container image signature verification, you must create a policy that does not verify signatures.
- Resource access policy.
7.13.1. Configuring reference values Copy linkLink copied to clipboard!
You can configure reference values for the Reference Value Provider Service (RVPS) by specifying the trusted digests of your hardware platform.
The client collects measurements from the running software, the Trusted Execution Environment (TEE) hardware and firmware and it submits a quote with the claims to the Attestation Server. These measurements must match the trusted digests registered to the Trustee. This process ensures that the confidential VM (CVM) is running the expected software stack and has not been tampered with.
Procedure
Create an
rvps-configmap.yamlmanifest file:apiVersion: v1 kind: ConfigMap metadata: name: rvps-reference-values namespace: trustee-operator-system data: reference-values.json: | [1 ]- 1
- Specify the trusted digests for your hardware platform if required. Otherwise, leave it empty.
Create the RVPS config map by running the following command:
$ oc apply -f rvps-configmap.yaml
7.13.2. Creating an attestation policy Copy linkLink copied to clipboard!
You can create an attestation policy that overrides the default attestation policy.
Procedure
Create an
attestation-policy.yamlmanifest file according to the following example:# attestation-policy.yaml apiVersion: v1 kind: ConfigMap metadata: name: attestation-policy namespace: trustee-operator-system data: default.rego: | package policy import rego.v1 # This policy validates multiple TEE platforms # The policy is meant to capture the TCB requirements # for confidential containers. # This policy is used to generate an EAR Appraisal. # More information can be found at # <https://datatracker.ietf.org/doc/draft-ietf-rats-ar4si/> default executables := 33 default hardware := 97 default configuration := 36 executables := 3 if { input.sample.launch_digest in data.reference.launch_digest } hardware := 2 if { input.sample.svn in data.reference.svn } executables := 3 if { input.snp.measurement in data.reference.snp_launch_measurement } hardware := 2 if { input.snp.reported_tcb_bootloader in data.reference.snp_bootloader input.snp.reported_tcb_microcode in data.reference.snp_microcode input.snp.reported_tcb_snp in data.reference.snp_snp_svn input.snp.reported_tcb_tee in data.reference.snp_tee_svn } configuration := 2 if { input.snp.policy_debug_allowed == "0" input.snp.policy_migrate_ma == "0" input.snp.platform_smt_enabled in data.reference.snp_smt_enabled input.snp.platform_tsme_enabled in data.reference.snp_tsme_enabled input.snp.policy_abi_major in data.reference.snp_guest_abi_major input.snp.policy_abi_minor in data.reference.snp_guest_abi_minor input.snp.policy_single_socket in data.reference.snp_single_socket input.snp.policy_smt_allowed in data.reference.snp_smt_allowed } else := 3 if { input.snp.policy_debug_allowed == "0" input.snp.policy_migrate_ma == "0" } executables := 3 if { input.tdx.quote.body.rtmr_1 in data.reference.rtmr_1 input.tdx.quote.body.rtmr_2 in data.reference.rtmr_2 } hardware := 2 if { # Check that this is a TDX quote signed by the Intel SGX Quoting Enclave. input.tdx.quote.header.tee_type == "81000000" input.tdx.quote.header.vendor_id == "939a7233f79c4ca9940a0db3957f0607" # Check TDX Module version and its hash. Also check OVMF code hash. input.tdx.quote.body.mr_seam in data.reference.mr_seam input.tdx.quote.body.tcb_svn in data.reference.tcb_svn input.tdx.quote.body.mr_td in data.reference.mr_td # Check TCB status # input.tdx.tcb_status == "OK" # Check collateral expiration status # input.tdx.collateral_expiration_status == "0" # Check against allowed advisory ids # allowed_advisory_ids := {"INTEL-SA-00837"} # attester_advisory_ids := {id | id := input.attester_advisory_ids[_]} # object.subset(allowed_advisory_ids, attester_advisory_ids) # Check against disallowed advisory ids # disallowed_advisory_ids := {"INTEL-SA-00837"} # attester_advisory_ids := {id | id := input.tdx.advisory_ids[_]} # convert array to set # intersection := attester_advisory_ids & disallowed_advisory_ids # count(intersection) == 0 } configuration := 2 if { input.tdx.td_attributes.debug == false input.tdx.quote.body.xfam in data.reference.xfam } executables := 3 if { input.azsnpvtpm.measurement in data.reference.measurement input.azsnpvtpm.tpm.pcr11 in data.reference.snp_pcr11 } hardware := 2 if { input.azsnpvtpm.reported_tcb_bootloader in data.reference.tcb_bootloader input.azsnpvtpm.reported_tcb_microcode in data.reference.tcb_microcode input.azsnpvtpm.reported_tcb_snp in data.reference.tcb_snp input.azsnpvtpm.reported_tcb_tee in data.reference.tcb_tee } configuration := 2 if { input.azsnpvtpm.platform_smt_enabled in data.reference.smt_enabled input.azsnpvtpm.platform_tsme_enabled in data.reference.tsme_enabled input.azsnpvtpm.policy_abi_major in data.reference.abi_major input.azsnpvtpm.policy_abi_minor in data.reference.abi_minor input.azsnpvtpm.policy_single_socket in data.reference.single_socket input.azsnpvtpm.policy_smt_allowed in data.reference.smt_allowed } ##### Azure vTPM TDX executables := 3 if { input.aztdxvtpm.tpm.pcr11 in data.reference.tdx_pcr11 } hardware := 2 if { # Check that the quote is a TDX quote signed by the Intel SGX Quoting Enclave. input.aztdxvtpm.quote.header.tee_type == "81000000" input.aztdxvtpm.quote.header.vendor_id == "939a7233f79c4ca9940a0db3957f0607" # Check TDX Module version and its hash. Also check OVMF code hash. input.aztdxvtpm.quote.body.mr_seam in data.reference.mr_seam input.aztdxvtpm.quote.body.tcb_svn in data.reference.tcb_svn input.aztdxvtpm.quote.body.mr_td in data.reference.mr_td } configuration := 2 if { input.aztdxvtpm.quote.body.xfam in data.reference.xfam }The attestation policy follows the Open Policy Agent specification. In this example, the attestation policy compares the claims provided in the attestation report to the reference values registered in the RVPS database. The attestation process is successful only if all the values match.
Create the attestation policy config map by running the following command:
$ oc apply -f attestation-policy.yaml
7.13.3. Configuring PCCS for TDX Copy linkLink copied to clipboard!
If you use Intel Trust Domain Extensions (TDX), you must configure Trustee to use the Provisioning Certificate Caching Service (PCCS).
The PCCS retrieves the Provisioning Certification Key (PCK) certificates and caches them in a local database.
Do not use the public Intel PCCS service. Use a local caching service on-premise or on the public cloud.
Procedure
Create a
tdx-config.yamlmanifest file according to the following example:apiVersion: v1 kind: ConfigMap metadata: name: tdx-config namespace: trustee-operator-system data: sgx_default_qcnl.conf: | \ { "collateral_service": "https://api.trustedservices.intel.com/sgx/certification/v4/", "pccs_url": "<pccs_url>"1 }- 1
- Specify the PCCS URL, for example,
https://localhost:8081/sgx/certification/v4/.
Create the TDX config map by running the following command:
$ oc apply -f tdx-config.yaml
7.13.4. Creating a secret with custom keys for clients Copy linkLink copied to clipboard!
You can create a secret that contains one or more custom keys for Trustee clients.
In this example, the kbsres1 secret has two entries (key1, key2), which the clients retrieve. You can add additional secrets according to your requirements by using the same format.
Prerequisites
- You have created one or more custom keys.
Procedure
Create a secret for the custom keys according to the following example:
$ oc apply secret generic kbsres1 \ --from-literal key1=<custom_key1> \1 --from-literal key2=<custom_key2> \ -n trustee-operator-system- 1
- Specify a custom key.
The
kbsres1secret is specified in thespec.kbsSecretResourceskey of theKbsConfigcustom resource.
7.13.5. Creating a secret for container image signature verification Copy linkLink copied to clipboard!
If you use container image signature verification, you must create a secret that contains the public container image signing key.
The Confidential compute attestation Operator uses the secret to verify the signature, ensuring that only trusted and authenticated container images are deployed in your environment.
You can use Red Hat Trusted Artifact Signer or other tools to sign container images.
Procedure
Create a secret for container image signature verification by running the following command:
$ oc apply secret generic <type> \1 --from-file=<tag>=./<public_key_file> \2 -n trustee-operator-system-
Record the
<type>value. You must add this value to thespec.kbsSecretResourceskey when you create theKbsConfigcustom resource.
7.13.6. Creating the container image signature verification policy Copy linkLink copied to clipboard!
You create the container image signature verification policy because signature verification is always enabled. If this policy is missing, the pods will not start.
If you are not using container image signature verification, you create the policy without signature verification.
For more information, see containers-policy.json 5.
Procedure
Create a
security-policy-config.jsonfile according to the following examples:Without signature verification:
{ "default": [ { "type": "insecureAcceptAnything" }], "transports": {} }With signature verification:
{ "default": [ { "type": "insecureAcceptAnything" } ], "transports": { "<transport>": {1 "<registry>/<image>":2 [ { "type": "sigstoreSigned", "keyPath": "kbs:///default/<type>/<tag>"3 } ] } } }- 1
- Specify the image repository for
transport, for example,"docker":. For more information, see containers-transports 5. - 2
- Specify the container registry and image, for example, "quay.io/my-image".
- 3
- Specify the type and tag of the container image signature verification secret that you created, for example,
img-sig/pub-key.
Create the security policy by running the following command:
$ oc apply secret generic security-policy \ --from-file=osc=./<security-policy-config.json> \ -n trustee-operator-systemDo not alter the secret type,
security-policy, or the key,osc.The
security-policysecret is specified in thespec.kbsSecretResourceskey of theKbsConfigcustom resource.
7.13.7. Creating the resource access policy Copy linkLink copied to clipboard!
You configure the resource access policy for the Trustee policy engine. This policy determines which resources Trustee can access.
The Trustee policy engine is different from the Attestation Service policy engine, which determines the validity of TEE evidence.
Procedure
Create a
resourcepolicy-configmap.yamlmanifest file:apiVersion: v1 kind: ConfigMap metadata: name: resource-policy namespace: trustee-operator-system data: policy.rego: package policy default allow = true allow { input["tee"] != "sample" }- policy.rego
-
The name of the resource policy,
policy.rego, must match the resource policy defined in the Trustee config map. - package policy
- The resource policy follows the Open Policy Agent specification.
Create the resource policy config map by running the following command:
$ oc apply -f resourcepolicy-configmap.yaml
7.14. Creating the KbsConfig custom resource Copy linkLink copied to clipboard!
You create the KbsConfig custom resource (CR) to launch Trustee.
Then, you check the Trustee pods and pod logs to verify the configuration.
Procedure
Create a
kbsconfig-cr.yamlmanifest file:apiVersion: confidentialcontainers.org/v1alpha1 kind: KbsConfig metadata: labels: app.kubernetes.io/name: kbsconfig app.kubernetes.io/instance: kbsconfig app.kubernetes.io/part-of: trustee-operator app.kubernetes.io/managed-by: kustomize app.kubernetes.io/created-by: trustee-operator name: kbsconfig namespace: trustee-operator-system spec: kbsConfigMapName: kbs-config-cm kbsAuthSecretName: kbs-auth-public-key kbsDeploymentType: AllInOneDeployment kbsRvpsRefValuesConfigMapName: rvps-reference-values kbsSecretResources: ["kbsres1", "security-policy", "<type>"]1 kbsResourcePolicyConfigMapName: resource-policy # tdxConfigSpec: # kbsTdxConfigMapName: tdx-config2 # kbsAttestationPolicyConfigMapName: attestation-policy3 # kbsServiceType: <service_type>4 - 1
- Optional: Specify the
typevalue of the container image signature verification secret if you created the secret, for example,img-sig. If you did not create the secret, set thekbsSecretResourcesvalue to["kbsres1", "security-policy"]. - 2
- Uncomment
tdxConfigSpec.kbsTdxConfigMapName: tdx-configfor Intel Trust Domain Extensions. - 3
- Uncomment
kbsAttestationPolicyConfigMapName: attestation-policyif you create a customized attestation policy. - 4
- Uncomment
kbsServiceType: <service_type>if you create a service type, other than the defaultClusterIPservice, to expose applications within the cluster external traffic. You can specifyNodePort,LoadBalancer, orExternalName.
Create the
KbsConfigCR by running the following command:$ oc apply -f kbsconfig-cr.yaml
7.15. Verifying the Trustee configuration Copy linkLink copied to clipboard!
You verify the Trustee configuration by checking the Trustee pods and logs.
Procedure
Set the default project by running the following command:
$ oc project trustee-operator-systemCheck the Trustee pods by running the following command:
$ oc get pods -n trustee-operator-systemExample output
NAME READY STATUS RESTARTS AGE trustee-deployment-8585f98449-9bbgl 1/1 Running 0 22m trustee-operator-controller-manager-5fbd44cd97-55dlh 2/2 Running 0 59mSet the
POD_NAMEenvironmental variable by running the following command:$ POD_NAME=$(oc get pods -l app=kbs -o jsonpath='{.items[0].metadata.name}' -n trustee-operator-system)Check the pod logs by running the following command:
$ oc logs -n trustee-operator-system $POD_NAMEExample output
[2024-05-30T13:44:24Z INFO kbs] Using config file /etc/kbs-config/kbs-config.json [2024-05-30T13:44:24Z WARN attestation_service::rvps] No RVPS address provided and will launch a built-in rvps [2024-05-30T13:44:24Z INFO attestation_service::token::simple] No Token Signer key in config file, create an ephemeral key and without CA pubkey cert [2024-05-30T13:44:24Z INFO api_server] Starting HTTPS server at [0.0.0.0:8080] [2024-05-30T13:44:24Z INFO actix_server::builder] starting 12 workers [2024-05-30T13:44:24Z INFO actix_server::server] Tokio runtime found; starting in existing Tokio runtime
7.16. Verifying the attestation process Copy linkLink copied to clipboard!
You can verify the attestation process by creating a test pod and retrieving its secret.
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.
By default, the Kata agent policy, embedded in the pod virtual machine (VM) image, disables the exec and log APIs for a Confidential Containers pod. This policy prevents the cluster admin from executing processes inside the pod to exfiltrate sensitive data while also blocking accidental writes of sensitive data to standard I/O.
In a test scenario, you can override the restriction at runtime by adding a policy annotation to the pod. For Technology Preview, runtime policy annotations are not verified by remote attestation.
Prerequisites
- You have created a route if the Trustee server and the test pod are not running in the same cluster.
Procedure
Create a
verification-pod.yamlmanifest file:apiVersion: v1 kind: Pod metadata: name: ocp-cc-pod labels: app: ocp-cc-pod annotations: io.katacontainers.config.agent.policy: <base64_encoded_policy>1 io.katacontainers.config.runtime.cc_init_data: <base64_initdata>2 spec: runtimeClassName: kata-remote containers: - name: skr-openshift image: registry.access.redhat.com/ubi9/ubi:9.3 command: - sleep - "36000" securityContext: privileged: false seccompProfile: type: RuntimeDefaultIf you specify both the
io.katacontainers.config.agent.policyannotation and theio.katacontainers.config.runtime.cc_init_dataannotation with an agent policy, the initdata annotation takes precedence over the agent policy annotation.Create the pod by running the following command:
$ oc create -f verification-pod.yamlConnect to the Bash shell of the
ocp-cc-podby running the following command:$ oc exec -it ocp-cc-pod -- bashFetch the pod secret by running the following command:
$ curl http://127.0.0.1:8006/cdh/resource/default/kbsres1/key1Example output
res1val1The Trustee server returns the secret only if the attestation is successful.