About the contract
The contract is a definition file in the YAML format that is specific to the IBM Confidential Computing Containers for Red Hat OpenShift Container Platform (CCCO) virtual machine (VM). You must create this file as a prerequisite for creating a VM, and after this file is created, it must be passed as an input when the CCCO VM is created. You cannot create a CCCO VM without a valid contract. If you create the CCCO VM without a contract, the deployment starts and then fails, and the VM goes into a shutdown state. The contract is specific to creating a CCCO VM and is an extension of the IBM Secure Execution technology.
When you create a workload by using the IBM Confidential Computing Containers for Red Hat OpenShift Container Platform image, you must add CCCO specific features to the contracts to run a workload inside the IBM Confidential Computing Containers pod.
Contract sections
A contract file can have the following four valid high-level sections:
-
workloadis a mandatory section. -
envis a mandatory section. -
attestationPublicKeyis an optional section. You can provide a public RSA key as part of the contract, which is used to encrypt the attestation document and the attribute must be named asattestationPublicKey. -
envWorkloadSignaturecontains the signature of the other sections of the contract. bootis a mandatory section. This section contains Secure Execution Header (sehdr), which is used to initialize and validate secure boot operations in IBM CCCO.
The two primary sections in a contract are the workload and env sections. These two sections are needed because the information that is added into the contract comes from two different personas, namely the Solution Provider or Data Owner.
The Data Owner persona works closely with the Environment Operator. This persona receives the workload information (preferably an encrypted workload section) from the Solution Provider persona. The Data Owner then creates the env section of the contract. The env section has information that is specific to the IBM Cloud environment. Usually, it is information that the Solution Provider persona does not have and does not need to know. An example is information about the IBM Cloud Logging instance, which the Data Owner persona creates, before they add information to the env section of the contract.
Volumes
- Overview
-
To use volumes with CCCO workloads, you must define volume parameters in both the workload and env sections of the contract. CCCO merges these parameters for each persistent block volume, using the provided seeds to encrypt the volume and create the specified mount point to the workload.
Each volume requires a unique label that matches the block device in the pod specification. This label enables CCCO to identify and encrypt the respective persistent block device.
- Prerequisites
-
Before you configure volumes in CCCO:
- Attach physical block devices (such as IBM DASD and IBM Z FCP) to your OpenShift Container Platform bare metal nodes.
- Install a storage operator to manage persistent block volumes (for example, Red Hat OpenShift
Data Foundation (ODF) or Fusion Data Foundation(FDF)).Note: Make that you have enabled the Transport Layer Security (TLS) for ODF or FDF.
- Set up volumes for contracts. For more information, see Setting up volumes for contracts.
Important: To set up ODF or FDF, follow the setup guide in the Red Hat OpenShift Data Foundation documentation or IBM Storage Fusion Data Foundation. You must complete the operator setup before you can create persistent volume claims for CCCO workloads.
- Configuration example
-
The following example shows a single volume configuration across the workload section, env section, and pod specification.
Workload section:workload: volumes: test: filesystem: "ext4" mount: "/mnt/data" seed: "workloadphrase1"Env section:env: volumes: test: seed: "envphrase123457"Pod specification:apiVersion: v1 kind: Pod metadata: name: busybox-block-storage-pod namespace: default spec: containers: - name: busybox image: busybox:latest command: ["/bin/sh"] args: ["-c", "while true; do echo 'Block device available'; sleep 30; done"] volumeDevices: - name: odf-block-volume devicePath: /dev/test volumes: - name: odf-block-volume persistentVolumeClaim: claimName: odf-internal-rbd-pvc-1In this example, the block device name for the container,
test, specified in thedevicePathfield of thevolumeDevicessection, matches thetestlabel defined in both theworkloadandenvvolumes sections. CCCO uses both seeds to encrypt the volume and creates the mount point at/mnt/datawith an ext4 filesystem. The encrypted storage persists across pod restarts when you use the same contract.
The workload section
One of the most important sections of the contract, the workload section can have multiple subsections and the purpose of the subsections is to provide information that is required for bringing up the workload.
This section is created by the Solution Provider persona.
The workload section is the parent section that can have the following subsections:
type: workload. Declares that this YAML defines a workload configuration. This subsection is mandatory.confidential-containers. This subsection is mandatory.auths. This subsection is optional.volumes. This subsection is optional.
The following snippet shows a high-level sample of the workload section of the contract. The minimum that a workload section needs is the confidential-containers section. The other sections can be added based on the requirement.
type: workload
confidential-containers:
regoValidator:
policy: ${encoded_policy}
The workload - confidential-containers subsection
This confidential-containers section varies for different contracts.
-
For basic contract
type: workload confidential-containers: regoValidator: policy: ${encoded_policy}-
regoValidator: Allows you to configure the policy enforcement using Rego, which is the policy language of Open Policy Agent (OPA).Note: For more information about Rego policies and the associated restrictive rules, see Rego policy rules and snippets. -
policy: ${encoded_policy}: Contains a placeholder for a base64-encoded Rego policy that defines rules the workload must comply with before it is allowed to run. This allows you to have a control over the workloads that are allowed and enforce security policies such as image source restrictions, label requirements, and so on.
-
-
For the contract with the sealed secret
type: workload confidential-containers: regoValidator: policy: ${encoded_policy} secret: verificationKey: "${SECRET_VERIFICATION_KEY}" decryptionKey: "${SECRET_DECRYPTION_KEY}"-
secret: Allows you to configure the use of sealed secrets within the confidential container. -
verificationKey: Contains an environment variable placeholder that holds a public key used to verify the authenticity of the sealed secret. -
decryptionKey: Contains an environment variable placeholder that holds a key to decrypt the sealed secret so it can be used securely at runtime.
-
-
For the contract with cosign verified container images
type: workload confidential-containers: config: cosign: quay.io/<username>/busybox: publicKey: ${cosign-pub-base64}-
cosign: Allows you to configure image signature verification using Cosign. -
quay.io/<username>/busybox: Specifies the container image to be verified. Replace<username>with the actual registry username. -
publicKey: ${cosign-pub-base64}: Contains a placeholder for a base64-encoded public key used to verify the image's digital signature. This ensures that the image is signed by a trusted source.
-
The workload - auths subsection
If you want to use the workload image from the private registry, you must include the auths section. The auths section consists of information about the container's registry. This subsection does not have any image information, as shown in the following sample. This subsection needs to contain the name of the image registry and the credentials such as username-password for the same. The key must be the hostname of the container registry or the string 'https://index.docker.io/v1/' for the default docker registry.
The following snippet shows an example for IBM Cloud Registry. For more information about using the API key, see Using client software to authenticate in automation.
auths:
<PRIVATE_REGISTRY_URL>:
username: <USER_NAME>
password: <API_KEY_OR_PASSWORD>
-
<PRIVATE_REGISTRY_URL>: The URL of your private container registry.-
username: The username used to log in to the registry. -
password: The password or token used for authentication.
Example:
auths: icr.io: username: jyoti.sharma password: s3cr3t-api-key-123456 -
The workload - volumes subsection
Include the volumes subsection in the workload section only when you attach a persistent block volume to the workload. This subsection defines the mount path and provides the workload seed for encryption. CCCO uses seeds from both the workload and env sections to automatically encrypt the persistent block volume.
Parameters:
- filesystem: The filesystem type. Supported values:
ext4,xfs - mount: The mount path for the volume (for example, /mnt/data)
- seed: The workload encryption seed (minimum 15 characters)
- previousSeed: (Optional) The previous seed used when rotating the workload seed.
Encryption seeds:
CCCO encrypts volumes using two seeds: one from the workload section (provided by the workload owner) and one from the env section (provided by the data owner). The system converts both seeds to UTF-8 sequences, concatenates them, and computes a SHA256 hash. This hash serves as the LUKS passphrase for volume encryption.
Seed requirements:
- Minimum 15 characters
- No spaces
- Allowed characters: a-z, A-Z, 0-9, and special characters
!@#$%^&*(),.?":{}|<>_-
Seed rotation:
You can rotate encryption seeds to enhance security or respond to compromised credentials. To rotate a seed, specify the current seed in the previousSeed parameter and the new seed in the seed parameter.
volumes:
test:
filesystem: "ext4"
mount: "/mnt/data"
seed: "newworkloadphrase1"
previousSeed: "oldworkloadphrase2"
Multiple volumes:
You can attach multiple volumes to a single container or across multiple containers in a pod. Ensure that each volume label in the contract matches the corresponding devicePath in the pod specification.
volumes:
test1:
filesystem: "ext4"
mount: "/mnt/data"
seed: "workloadphrase1"
test2:
filesystem: "xfs"
mount: "/mnt/test"
seed: "workloadphrase2"
Corresponding pod specification:
apiVersion: v1
kind: Pod
metadata:
name: busybox-block-storage-pod
namespace: default
spec:
containers:
- name: busybox
image: busybox:latest
command: ["/bin/sh"]
args: ["-c", "while true; do echo 'Block devices available'; sleep 30; done"]
volumeDevices:
- name: odf-block-volume-1
devicePath: /dev/test1
- name: odf-block-volume-2
devicePath: /dev/test2
volumes:
- name: odf-block-volume-1
persistentVolumeClaim:
claimName: odf-internal-rbd-pvc-1
- name: odf-block-volume-2
persistentVolumeClaim:
claimName: odf-internal-rbd-pvc-2
The env section
The env section is also one of the most important sections in a contract. The env section of a contract deals with information that is specific to the cloud environment and is not known to the Solution Provider persona. This section is created by the Data Owner persona.
The subsections for the env section are:
type: env. This subsection is mandatory.logging. This subsection is mandatory.confidential-containers. This subsection must be used only when you are creating the contract with sealed secret.signingKey. This subsection is used to provide a key to verify the contract signature.host-attestation. This subsection is used to specify one or more host key documents required for attestation. This subsection is mandatory for Bare Metal deployments and optional for Peer Pod deployments.volumes. This subsection is optional.
The minimum that a env section needs is the logging section. The other sections can be added based on the requirement. The following snippet shows a high-level sample of the env section of the contract with logrouter.
type: env
logging:
logRouter:
hostname: ${PUBLIC_INGRESS_ENDPOINT}
iamApiKey: ${IAMAPIKEY}
port: 443
host-attestation:
${HKDNAME}:
description: KEY-1
host-key-doc: ${HKDVALUE}
signingKey: "${SIGNING_KEY}"
The env - logging subsection
The minimum subsection that is required for this section is logRouter. This section allows you to configure the logging behavior. You can configure either logRouter or syslog for logging, but not both simultaneously. For more information, see Logging for IBM Confidential Computing Containers for Red Hat OpenShift Container Platform.
LogRouter
The following snippet is an example of the logging subsection with logRouter:
type: env
logging:
logRouter:
hostname: ${PUBLIC_INGRESS_ENDPOINT}
iamApiKey: ${IAMAPIKEY}
port: <PORT_NUMBER>
-
hostname: Contains an environment variable that holds a public endpoint of the logging service. -
iamApiKey: Contains an environment variable that holds an Identity and Access Management (IAM) API key used to authenticate the logging service. -
port: Specify the network port used to send logs. For example, 443.
Syslog
The following snippet is an example of the logging subsection with syslog:
type: env
logging:
syslog:
hostname: ${HOSTNAME}
port: <PORT_NUMBER>
server: ${CA}
cert: ${CLIENT_CERTIFICATE}
key: ${CLIENT_PRIVATE_KEY}
-
hostname: Contains the address of the syslog server.. -
port: Specify the network port used to send logs. For example, 514. -
server: Contains the Certificate Authority (CA) used to validate the server. -
cert: Contains the Client certificate for mutual TLS authentication. -
key: Contains the private key corresponding to the client certificate.
The env - confidential-containers subsection
confidential-containers:
secret:
decryptionKey: ${SECRET_DECRYPTION_KEY}
verificationKey: ${SECRET_VERIFICATION_KEY}
-
confidential-containers: Allows you to configure secret when you are creating the contract with sealed secret.-
secret: Allows you to configure the use of sealed secrets within the confidential container. -
verificationKey: Contains an environment variable placeholder that holds a public key used to verify the authenticity of the sealed secret. -
decryptionKey: Contains an environment variable placeholder that holds a key to decrypt the sealed secret so it can be used securely at runtime.
-
The env - signingKey subsection
For information about how to use the signingKey, see Contract signature.
The env - volumes subsection
The env volumes subsection provides the Data Owner's encryption seed for each volume. You must provide a seed in both the workload and env sections for each volume.
Example:
volumes:
test:
seed: "envphrase123456"
Example with seed rotation:
volumes:
test1:
seed: "newenvphrase123457"
previousSeed: "oldenvphrase123456"
test2:
seed: "newenv2phrase123457"
previousSeed: "oldenv2phrase123456"
Both the Workload Owner and Data Owner can rotate their respective seeds independently.
The env - host-attestation subsection
For information about how to use the host-attestation, see Host attestation.
Contract encryption
You can encrypt the contents of a contract. Although you can use the contract without encryption, it is recommended that you encrypt the contract. It is also recommended that you initially try to use a non-encrypted contract for testing purposes, and after it works as expected, you can use an encrypted contract for your production environment.
You can decide which sections of the contract need encryption. For example, you can choose to encrypt only the workload section, or encrypt only the env section.
When the IBM CCCO VM boots, the bootloader decrypts the contract. It takes the value of each of the sections in the contract and decrypts it if it is encrypted. If it finds that a section is not encrypted, it considers it as it is without any decryption. You must use the IBM CCCO contract encryption key to encrypt the contract before you pass it as an input.
The encryption and attestation certificates are signed by the IBM intermediate certificate and this is signed by the IBM Digicert intermediate cert (which in turn is signed by DigiCert Trusted Root G4). For more information about the certificates, see DigiCert Trusted Root Authority Certificates.
Downloading the encryption certificate and extracting the public key
-
Get the certificate
ibm-hyper-protect-confidential-container-26.3.1-encrypt.crt, which is used to encrypt the contract from the image TAR file. -
Validate the encryption certificate by following the instructions from Validating the certificates.
Creating the encrypted workload section of a contract
The value of any section in a contract can be in plain text or encrypted. Complete the following steps to encrypt the workload section used in a contract:
-
Create the
workloadsection of the contract and add the contents in theworkload.yamlfile. -
Export the complete path of the
workload.yamlfile andibm-hyper-protect-confidential-container-26.3.1-encrypt.crt:$ WORKLOAD="<PATH to workload.yaml>" $ CONTRACT_KEY="<PATH to ibm-hyper-protect-confidential-container-26.3.1-encrypt.crt>" -
Use the following command to create a random password (the contract is encrypted via symmetric AES with a random PASSWORD):
PASSWORD="$(openssl rand 32 | base64 -w0)" -
Use the following command to encrypt password with
ibm-hyper-protect-confidential-container-26.3.1-encrypt.crt:$ ENCRYPTED_PASSWORD="$(echo -n "$PASSWORD" | base64 -d | openssl rsautl -encrypt -inkey $CONTRACT_KEY -certin | base64 -w0 )" -
Use the following command to encrypt the
workload.yamlfile with a random password:$ ENCRYPTED_WORKLOAD="$(echo -n "$PASSWORD" | base64 -d | openssl enc -aes-256-cbc -pbkdf2 -pass stdin -in "$WORKLOAD" | base64 -w0)" -
Use the following command to get the encrypted section of the contract:
$ echo "hyper-protect-basic.${ENCRYPTED_PASSWORD}.${ENCRYPTED_WORKLOAD}" -
Get the output from the earlier step and add it to the
user-data.yamlfile.$ workload: hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn..............Note: The prefixhyper-protect-basicis mandatory.
Creating encrypted env section of a contract
Complete the following steps to encrypt the env section used in a contract:
-
Create the
envsection of the contract and add the contents in theenv.yamlfile. -
Export the complete path of the
env.yamlfile andibm-hyper-protect-confidential-container-26.3.1-encrypt.crt:$ ENV="<PATH to env.yaml>" $ CONTRACT_KEY="<PATH to ibm-hyper-protect-confidential-container-26.3.1-encrypt.crt>" -
Use the following command to create a random password:
PASSWORD="$(openssl rand 32 | base64 -w0)" -
Use the following command to encrypt password with
ibm-hyper-protect-confidential-container-26.3.1-encrypt.crt:$ ENCRYPTED_PASSWORD="$(echo -n "$PASSWORD" | base64 -d | openssl rsautl -encrypt -inkey $CONTRACT_KEY -certin | base64 -w0)" -
Use the following command to encrypt
env.yamlwith a random password:$ ENCRYPTED_ENV="$(echo -n "$PASSWORD" | base64 -d | openssl enc -aes-256-cbc -pbkdf2 -pass stdin -in "$ENV" | base64 -w0)" -
Use the following command to get the encrypted section of the contract:
$ echo "hyper-protect-basic.${ENCRYPTED_PASSWORD}.${ENCRYPTED_ENV}" -
To encrypt the workload section, see encrypt_workload.
-
Get the output from the earlier step and add it to the
user-data.yamlfile.$ env: hyper-protect-basic.VWg/5/SWE+9jLfhr8q4i.........
Contract signature
Contract signature is essential to ensure a confidential environment for the workload. You can choose to sign a contract before it is passed as input. Contracts that are in plain text or encrypted can be signed. Validation of the contract signature is done by the IBM Confidential Computing Containers for Red Hat OpenShift Container Platform image.
The purpose of this signature feature is to ensure that the workload and
env sections are always used together and are not tampered with by a third party.
Another optional feature in contract signature is setting expiry of contract using signing
certificate. Using this feature, if a IBM CCCO VM is booted after the
certificate has expired, the VM will fail to boot. The signature of the workload
and the env sections are added as the value to the
envWorkloadSignature section.
Following are the two sections in a contract that are relevant while creating and adding a contract signature:
-
envWorkloadSignature: This is section where the signature of the other sections of the contract is added. This section is not required for a contract that is not signed. -
signingKey: This is a subsection that must be added to theenvsection of the contract. This holds the value to the user-generated public key or certificate, whose corresponding private key was used to create the contract signature. Public key or certificate can also be parsed as base64 string.
Complete the following steps to create the contract signature:
-
Use the following command to generate key pair to sign the contract:
$ openssl genrsa -aes128 -passout pass:test1234 -out private.pem 4096 $ openssl rsa -in private.pem -passin pass:test1234 -pubout -out public.pemNote: "test1234" is the passphrase to generate keys; however, you can use your own. -
Utilise the following command as an example to get the signing key:
$ key=$(awk -vRS="\n" -vORS="\\\n" '1' public.pem) $ echo ${key%\\n} -
If you want to pass the signing key as base64 optionally, use the following command:
$ key=$(cat public.pem | base64 -w 0) $ echo $key -
If you want to enable contract expiry optionally, refer to the steps mentioned in the following:
a. Use the following command to generate a certificate request:
$ openssl req -new -key private.pem -passin pass:test1234 -out csr.pemb. The command generates the certificate. Utilise the following steps to generate the certificate:
-
Use the following command to generate private key for CA:
$ openssl genrsa -out personal_ca.key 2048 -
Generate a self-signed CA certificate using the following command:
$ openssl req -new -x509 -key ca.key -out personal_ca.crt -
Use the following command to sign CSR with self signed CA certificate along with number of days for the certificate to be valid.
Note: The end date of the generated certificate is the contract expiry date.$ openssl x509 -req -in csr.pem -CA personal_ca.crt -CAkey personal_ca.key -CAcreateserial -out certificate.pem -days 365
c. Use the following command as an example to get the certificate:
$ certificate=$(awk -vRS="\n" -vORS="\\\n" '1' certificate.pem) $ echo ${certificate%\\n}d. Use the following command as an example to optionally get the certificate in base64 format:
$ certificate=$(cat certificate.pem | base64 -w 0) $ echo $certificate -
-
Create the
env.yamlfile according to the following examples:-
If
signingkeyis a public key:type: env logging: logRouter: hostname: ${PUBLIC_INGRESS_ENDPOINT} iamApiKey: ${IAMAPIKEY} port: 443 signingKey: "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvLaeSA8Nc3p99HNUMwon\n5lMMALAsIxRRpWUaEZ5IcUky2sgCi/rSmxU2sm6FK/BmCftk33f5W2BsYHdY9R/0\nELZ9A4POQcJsPF3ronU2QHwnRjcqYuUFXmf1VqfPPLpELriFNoCb2FN2zCa+VUmu\n+fGhroZ3Fr9kBPwJhGr917E5jeCQ+MzsGkulcTvr0SfvThiZQQ/KlU0R35ThamF3\n8C0F5IQBpqDUwDFmWvD5lF2SmprpluDBFEj8LLfLxvW9M2Qwku6nGUnnFReg3vNH\n7IF0SRr1K1AdO5hEmevCdyG9hgTdUY6dXcjntiN/kbqXErILknvzDnb4jyPZZRdK\ndrOzVt8hjbdmkS396SrMFtA++QrV3GNZl5zCscpn6d8S7BEA8mDzroo2UAbrypVP\n9l9AmzUnmnPCpZQySUUHoY0xG2vgMSA50CWH7Uwjmpixr02Td4/LU8fE7NWCO6ci\nx4++ANSaxu+uuZ2Pe1OjjgV98r06ZUs38eaxptLZqLpn3N6w8WAJxGwSLapZwNtP\ng2spUXu2Eh/TN5t4/ly5iXOsyIy8IPtTrUPX7rpaaqFZ72P6BJLj3WLEvOG/eF/8\nBTjrsZAjb8YjkO1uGk10IPa63sniZWe5vlm9w9UKy2uGuy6RhWxwoVHRRbfhboQF\nsO20dsVwgTZn8c46HMD2PoMCAwEAAQ==\n-----END PUBLIC KEY----" -
If
signingkeyis a certificate:type: env logging: logDNA: hostname: syslog-a.eu-gb.logging.cloud.ibm.com ingestionKey: cfae1522876e860e58f5844a33bdcaa8 port: 6514 signingKey: "-----BEGIN CERTIFICATE-----\nMIIFETCCAvkCFBAMxyO6Cl7BNKBGxtlAzHpI2oiNMA0GCSqGSIb3DQEBCwUAMEUx\nCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl\ncm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjQwMTMwMDM1ODMzWhcNMjQwNTA5MDM1\nODMzWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE\nCgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOC\nAg8AMIICCgKCAgEAv5h6i7Fn1DMUM+3AnPPZUNMe1ss3KL/AmUmptwlAPErVoH1k\naiqTUsSNjXctj+nk95I+e2nugw/HlaVT1eRgEtvjssheXKboFn+zW/i31Nq9USgQ\nZA325VtchYlgJLXMPaH/ukBUr0UI4LnjC/dNdAQzKwWPNF2Jlv5wKX8OBVOQO9Df\nExVmcEkKDoh0nZk5eOA8vzJGhfr8TvQx9FQFsP4OXTwQgcdZV26mLm0bMkqEt3o5\n8OSpisqNGY1XnMHjOWNqSbErkpbIKEFAQSnWmzEvJdHsQX+7eTF7CisHJREseT4s\nUSuIFBZKXbS3qq6EL/EYviu0EGnY/rkJJcIRb8hycqHRgoITT2bWT7PSMUyXoX3G\nVKfp/xKFhkYzoRDSb5S0lh8sugmoRkioAkw6G56CP2hablPZRUMmUKceFfOG/k4L\nei8qJtbfQJ9BlCNRPpjqY3sGSdeXI4zefyQ8xxcus9Sl5wXZV86lz2lO/fz3Cvpd\n0eKvfv5uXyvF3O36lrlEERmSukaZYaEJECjxOUeafc7E1DVyIaMpc2SOum1crwMG\nRKhnU1JShDON0yClnKOlACfjFIpdpEMpE4lLps1x+PXV+x21zGBMUvXYa4xpbyWR\nK1gfMWmuvGOivl9y0mPSIeyJ9R/7bSRAbcYJR4N99TrtWxZU1yQi7HSRV5cCAwEA\nATANBgkqhkiG9w0BAQsFAAOCAgEAg006zJ4ZKwT8moOOl3PdThFUcf8rrIlec9Iy\nqPcWSqt5UTeYLIe58oGhhQmcaIRUOQaib5JqH2ukzqpo+gsJ3zZb3eIn4FB7cKef\nLqaiemOveEe1/qSwAGqMZyZELssiOflhnJdzuYSRWO8DO6Q6JMqQthDcw20budjO\nzP4nhXQqT+s8ljzqSJW77hDbrNAezTz/0SJFDtaMBs5UweX//7/4sXtJ8kBIBSxd\n7y4w8tuuxUaXOtYMjNrJAYLwFVeeO8CFURpbEuv7ABT0k8U4E8C6j4U4Jysx4XVP\nZj36rIAtvctchh0yAhHz8whXe1tvaFw9wzRDATnThFAuJG4Z07K2/rlDP9kO9wmn\ng8hHxKeqQMJDp29e0sGkz8oDi6Mz24k9CqFJJ0CUz1ntz7rrDkA3QwQbFRzk938y\n3rSfePO5qXlUQ9mm05hYr1EKKceTLEowc4XOouNLlUWGiRshRR1szMw5C29prFJ2\nyYuV9tBaFYkq7dnh8JnmrreEvAnsKyyECxMmtV/W701OSUYBcThwgAo+hkEeOJ+/\nwrOS7yoJqDF1y+5LLQJmUlrLCPXem3ZTa4UMe1p2g7ge7Dg6Zud9NDBcMigdHByt\nJP/i9PcJSEWrccWJ1ajToUCZ0wqfJ3Z4KqoEd0fadQhb32AuDUbu7E12EUFNPGIH\n8rQKbDU=\n-----END CERTIFICATE-----" -
If
signingkeyis a base64 encoded signing key or certificate:type: env logging: logDNA: hostname: syslog-a.eu-gb.logging.cloud.ibm.com ingestionKey: cfae1522876e860e58f5844a33bdcaa8 port: 6514 signingKey: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXG5NSUlGRVRDQ0F2a0NGQkFNeHlPNkNsN0JOS0JHeHRsQXpIcEkyb2lOTUEwR0NTcUdTSWIzRFFFQkN3VUFNRVV4XG5DekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJREFwVGIyMWxMVk4wWVhSbE1TRXdId1lEVlFRS0RCaEpiblJsXG5jbTVsZENCWGFXUm5hWFJ6SUZCMGVTQk1kR1F3SGhjTk1qUXdNVE13TURNMU9ETXpXaGNOTWpRd05UQTVNRE0xXG5PRE16V2pCRk1Rc3dDUVlEVlFRR0V3SkJWVEVUTUJFR0ExVUVDQXdLVTI5dFpTMVRkR0YwWlRFaE1COEdBMVVFXG5DZ3dZU1c1MFpYSnVaWFFnVjJsa1oybDBjeUJRZEhrZ1RIUmtNSUlDSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DXG5BZzhBTUlJQ0NnS0NBZ0VBdjVoNmk3Rm4xRE1VTSszQW5QUFpVTk1lMXNzM0tML0FtVW1wdHdsQVBFclZvSDFrXG5haXFUVXNTTmpYY3RqK25rOTVJK2UybnVndy9IbGFWVDFlUmdFdHZqc3NoZVhLYm9Gbit6Vy9pMzFOcTlVU2dRXG5aQTMyNVZ0Y2hZbGdKTFhNUGFIL3VrQlVyMFVJNExuakMvZE5kQVF6S3dXUE5GMkpsdjV3S1g4T0JWT1FPOURmXG5FeFZtY0VrS0RvaDBuWms1ZU9BOHZ6SkdoZnI4VHZReDlGUUZzUDRPWFR3UWdjZFpWMjZtTG0wYk1rcUV0M281XG44T1NwaXNxTkdZMVhuTUhqT1dOcVNiRXJrcGJJS0VGQVFTbldtekV2SmRIc1FYKzdlVEY3Q2lzSEpSRXNlVDRzXG5VU3VJRkJaS1hiUzNxcTZFTC9FWXZpdTBFR25ZL3JrSkpjSVJiOGh5Y3FIUmdvSVRUMmJXVDdQU01VeVhvWDNHXG5WS2ZwL3hLRmhrWXpvUkRTYjVTMGxoOHN1Z21vUmtpb0FrdzZHNTZDUDJoYWJsUFpSVU1tVUtjZUZmT0cvazRMXG5laThxSnRiZlFKOUJsQ05SUHBqcVkzc0dTZGVYSTR6ZWZ5UTh4eGN1czlTbDV3WFpWODZsejJsTy9mejNDdnBkXG4wZUt2ZnY1dVh5dkYzTzM2bHJsRUVSbVN1a2FaWWFFSkVDanhPVWVhZmM3RTFEVnlJYU1wYzJTT3VtMWNyd01HXG5SS2huVTFKU2hET04weUNsbktPbEFDZmpGSXBkcEVNcEU0bExwczF4K1BYVit4MjF6R0JNVXZYWWE0eHBieVdSXG5LMWdmTVdtdXZHT2l2bDl5MG1QU0lleUo5Ui83YlNSQWJjWUpSNE45OVRydFd4WlUxeVFpN0hTUlY1Y0NBd0VBXG5BVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBZ0VBZzAwNnpKNFpLd1Q4bW9PT2wzUGRUaEZVY2Y4cnJJbGVjOUl5XG5xUGNXU3F0NVVUZVlMSWU1OG9HaGhRbWNhSVJVT1FhaWI1SnFIMnVrenFwbytnc0ozelpiM2VJbjRGQjdjS2VmXG5McWFpZW1PdmVFZTEvcVN3QUdxTVp5WkVMc3NpT2ZsaG5KZHp1WVNSV084RE82UTZKTXFRdGhEY3cyMGJ1ZGpPXG56UDRuaFhRcVQrczhsanpxU0pXNzdoRGJyTkFlelR6LzBTSkZEdGFNQnM1VXdlWC8vNy80c1h0SjhrQklCU3hkXG43eTR3OHR1dXhVYVhPdFlNak5ySkFZTHdGVmVlTzhDRlVScGJFdXY3QUJUMGs4VTRFOEM2ajRVNEp5c3g0WFZQXG5aajM2cklBdHZjdGNoaDB5QWhIejh3aFhlMXR2YUZ3OXd6UkRBVG5UaEZBdUpHNFowN0syL3JsRFA5a085d21uXG5nOGhIeEtlcVFNSkRwMjllMHNHa3o4b0RpNk16MjRrOUNxRkpKMENVejFudHo3cnJEa0EzUXdRYkZSems5Mzh5XG4zclNmZVBPNXFYbFVROW1tMDVoWXIxRUtLY2VUTEVvd2M0WE9vdU5MbFVXR2lSc2hSUjFzek13NUMyOXByRkoyXG55WXVWOXRCYUZZa3E3ZG5oOEpubXJyZUV2QW5zS3l5RUN4TW10Vi9XNzAxT1NVWUJjVGh3Z0FvK2hrRWVPSisvXG53ck9TN3lvSnFERjF5KzVMTFFKbVVsckxDUFhlbTNaVGE0VU1lMXAyZzdnZTdEZzZadWQ5TkRCY01pZ2RIQnl0XG5KUC9pOVBjSlNFV3JjY1dKMWFqVG9VQ1owd3FmSjNaNEtxb0VkMGZhZFFoYjMyQXVEVWJ1N0UxMkVVRk5QR0lIXG44clFLYkRVPVxuLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLVxu
-
A notification about the expiry of the contract will be sent to your logging service.
Timelines for the notification are as follows:
- On the first of every month
- Everyday for 30 days before the expiry
- Once in every 4 hours if the contract is about to expire in 7 days
- Each and every hour if the contract has already expired or is about to expire in a day
- Encryption and Attestation certificate expiry warning logs
- CCCO continuously
monitors the validity of encryption and attestation certificates and generates warning logs through
the configured logging service when certificates are approaching expiry or have already expired.
These logs inform users about certificate status so they can upgrade the instance to the latest
image level. Following is the notification schedule:
- 30 days before expiry: CCCO generates a warning once
every 24 hours, indicating that the certificate will expire in one month.
Example:
HPL12011W: The Encryption certificate is going to expire -> Warning: The encryption certificate will expire on 12 February 2026 at 16:17:41 UTC, over 20 days. Upgrade to the latest image to unlock the latest features and avoid potential security vulnerabilities!!!
- 7 days before expiry: As the expiry date nears, CCCO increases log frequency
and issues warnings every 12 hours, emphasizing the need for prompt
renewal.
Example:
HPL12011W: The Encryption certificate is going to expire -> Warning: The encryption certificate will expire on 27 January 2026 at 16:17:41 UTC, over 4 days. Upgrade to the latest image to unlock the latest features and avoid potential security vulnerabilities!!!
- After certificate expiry: Once a certificate has expired, CCCO continues to log warnings
every 4 hours until the CCCO image is upgraded with a
valid
certificate.
Example:
HPL12013W: The Encryption certificate has expired -> Urgent: The encryption certificate expired on 15 June 2025 at 17:15:59 UTC, over 7 months. Immediate upgrade to the latest image is required to unlock the latest features and prevent serious security breaches!!!
- 30 days before expiry: CCCO generates a warning once
every 24 hours, indicating that the certificate will expire in one month.
Preparing the Attestation section
Encrypting the attestation document is the optional feature that can be used with contract. The attestationPublicKey is the user provided public key used to encrypt the attestation document. This can be provided as a public RSA key or base64 encoded of the public RSA key as a part of the contract.
-
If you use the plain text public RSA key for the
attestationPublicKeyin the yaml file, use the following example:attestationPublicKey: "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvLaeSA8Nc3p99HNUMwon\n5lMMALAsIxRRpWUaEZ5IcUky2sgCi/rSmxU2sm6FK/BmCftk33f5W2BsYHdY9R/0\nELZ9A4POQcJsPF3ronU2QHwnRjcqYuUFXmf1VqfPPLpELriFNoCb2FN2zCa+VUmu\n+fGhroZ3Fr9kBPwJhGr917E5jeCQ+MzsGkulcTvr0SfvThiZQQ/KlU0R35ThamF3\n8C0F5IQBpqDUwDFmWvD5lF2SmprpluDBFEj8LLfLxvW9M2Qwku6nGUnnFReg3vNH\n7IF0SRr1K1AdO5hEmevCdyG9hgTdUY6dXcjntiN/kbqXErILknvzDnb4jyPZZRdK\ndrOzVt8hjbdmkS396SrMFtA++QrV3GNZl5zCscpn6d8S7BEA8mDzroo2UAbrypVP\n9l9AmzUnmnPCpZQySUUHoY0xG2vgMSA50CWH7Uwjmpixr02Td4/LU8fE7NWCO6ci\nx4++ANSaxu+uuZ2Pe1OjjgV98r06ZUs38eaxptLZqLpn3N6w8WAJxGwSLapZwNtP\ng2spUXu2Eh/TN5t4/ly5iXOsyIy8IPtTrUPX7rpaaqFZ72P6BJLj3WLEvOG/eF/8\nBTjrsZAjb8YjkO1uGk10IPa63sniZWe5vlm9w9UKy2uGuy6RhWxwoVHRRbfhboQF\nsO20dsVwgTZn8c46HMD2PoMCAwEAAQ==\n-----END PUBLIC KEY----" -
If you use the base64 encoded signing key for the
attestationPublicKeyin the yaml file, use the following command and example.$ base64 -w0 <public RSA key file>-
Replace
<public RSA key file>with the path to your actual public RSA key file.attestationPublicKey: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpRENDQVM2Z0F3SUJBZ0lSQUxCMXBPYlpEQlRRc09GSFlxazMzaWd3Q2dZSUtvWkl6ajBFQXdJd0tqRW8KTUNZR0ExVUVBeE1mZFhNdWFXTnlMbWx2TDNCeVlXSm9ZWFF4TWpNdmJYa3RhR0Z3Y205NGVUQWVGdzB5TWpBMApNVE14TURFd01ETmFGdzB6TWpBME1UQXhNREV3TUROYU1Db3hLREFtQmdOVkJBTVRIM1Z6TG1samNpNXBieTl3CmNtRmlhR0YwTVRJekwyMTVMV2hoY0hKdmVIa3dXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBU1AKWGsrelE2MlFZNjI3MWQ1cTBMZHY3SGc3QzZkMGZOUlRsQmJXekhOWWFDZzlpU0piYnVNdjVBY0JmMjlqQi83eApqYzhzVitxMksyemtkTHV4QWxGWm96VXdNekFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJCkt3WUJCUVVIQXdNd0RBWURWUjBUQVFIL0JBSXdBREFLQmdncWhrak9QUVFEQWdOSUFEQkZBaUIzd0JTa0IxaXAKZHZZYlBMbFBmS3RZT0hsYnZzUllKa0FZM2hnY0xuNWhwQUloQUt6cmhsU3p4K1I5bmdtMTBlZVkyaFNCRmgrawpMWHp6SFkwaktTVzhyM1FhCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
-
-
If you encrypt the
attestationPublicKeyin the yaml file, you must follow the same steps as mentioned in the Contract encryption.
To decrypt the attestation document, follow the instructions in the Decrypting the attestation document.
Preparing the signature
Complete the following steps to prepare the signature:
If you have got the encrypted user-data.yaml from the Creating the encrypted workload section of a contract, and Creating encrypted env section of a contract sections, skip to step 3.
-
Get the encrypted
workload.yamland encryptedenv.yamlfiles. -
Add them into the
user-data.yamlfile:workload: hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn.............. env: hyper-protect-basic.VWg/5/SWE+9jLfhr8q4i......... -
Create the
contract.txtfile. Add the value ofworkloadfirst then add the value ofenvfrom theuser-data.yamlfile.hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn..............hyper-protect-basic.VWg/5/SWE+9jLfhr8q4i.........Note: Ensure that there is no space or new line afterworkloadand beforeenv. Also, ensure that there is no new line or space at the end of the file. It is recommended to cross-check the binary content of thecontract.txtfile with tools such ashexdump. In the binary file dump, make sure that you do not see the0aASCII value as the last entry. -
Use the following command to generate the signature:
$ echo $( cat contract.txt | tr -d "\n\r" | openssl dgst -sha256 -sign private.pem | openssl enc -base64) | tr -d ' ' -
Add the signature into the
user-data.yamlfile.workload: hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn.............. env: hyper-protect-basic.VWg/5/SWE+9jLfhr8q4i......... envWorkloadSignature: Icbm1D/CVpLNYkWRC9e .....
The boot section
The boot is a mandatory section, which is required to securely initialize
the workload within the IBM CCCO environment. This section
is critical for establishing a trusted execution environment and ensuring the integrity of the
secure boot process. This section enables secure execution by leveraging IBM Secure Execution
technology.
This section is created by the Data Owner persona.
The boot section contains the following subsections:
-
sehdr. This subsection is mandatory, which contains the Secure Execution Header, a base64-encoded string that includes the necessary details to run a workload securely in a Logical Partition (LPAR). It ensures the workload operates in a protected environment. You can obtainsehdrinformation from the IBM CCCO installation directory.
The following snippet shows a high-level sample of the boots section of the contract.
boot: |
sehdr: SUJNU2VjRXgAAAEAAAAEELNhItLSxFZd/T9JIgAAAAAAAAAAAAAA................