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.

Note: For more information about creating a new contract, see Creating a new contract.

Contract sections

A contract file can have the following four valid high-level sections:

  • workload is a mandatory section.
  • env is a mandatory section.
  • attestationPublicKey is 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 as attestationPublicKey.
  • envWorkloadSignature contains the signature of the other sections of the contract.
  • boot is 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

Important: The volumes feature is only applicable for Bare Metal CCCO deployments.
The volumes section in the contract manages persistent block volumes for CCCO workloads. CCCO encrypts all attached block volumes to protect data from external access, including OpenShift Container Platform administrators, system administrators, and other data owners. Workload processes run in a Trusted Execution Environment, enabling you to run stateful applications with persistent block storage support.
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:

  1. Attach physical block devices (such as IBM DASD and IBM Z FCP) to your OpenShift Container Platform bare metal nodes.
  2. 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.
  3. 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-1

In this example, the block device name for the container, test, specified in the devicePath field of the volumeDevices section, matches the test label defined in both the workload and env volumes sections. CCCO uses both seeds to encrypt the volume and creates the mount point at /mnt/data with 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 - 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.

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

  1. 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.

  2. 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:

  1. Create the workload section of the contract and add the contents in the workload.yaml file.

  2. Export the complete path of the workload.yaml file and ibm-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>"
     
  3. 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)"
     
  4. 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 )"
     
  5. Use the following command to encrypt the workload.yaml file with a random password:

    $ ENCRYPTED_WORKLOAD="$(echo -n "$PASSWORD" | base64 -d | openssl enc -aes-256-cbc -pbkdf2 -pass stdin -in "$WORKLOAD" | base64 -w0)"
     
  6. Use the following command to get the encrypted section of the contract:

    $ echo "hyper-protect-basic.${ENCRYPTED_PASSWORD}.${ENCRYPTED_WORKLOAD}"
     
  7. Get the output from the earlier step and add it to the user-data.yaml file.

    $ workload: hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn..............
     
    Note: The prefix hyper-protect-basic is mandatory.

Creating encrypted env section of a contract

Complete the following steps to encrypt the env section used in a contract:

  1. Create the env section of the contract and add the contents in the env.yaml file.

  2. Export the complete path of the env.yaml file and ibm-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>"
     
  3. Use the following command to create a random password:

    PASSWORD="$(openssl rand 32 | base64 -w0)"
     
  4. 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)"
     
  5. Use the following command to encrypt env.yaml with a random password:

    $ ENCRYPTED_ENV="$(echo -n "$PASSWORD" | base64 -d | openssl enc -aes-256-cbc -pbkdf2 -pass stdin -in "$ENV" | base64 -w0)"
     
  6. Use the following command to get the encrypted section of the contract:

    $ echo "hyper-protect-basic.${ENCRYPTED_PASSWORD}.${ENCRYPTED_ENV}"
     
  7. To encrypt the workload section, see encrypt_workload.

  8. Get the output from the earlier step and add it to the user-data.yaml file.

    $ 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 the env section 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:

  1. 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.pem
     
    Note: "test1234" is the passphrase to generate keys; however, you can use your own.
  2. Utilise the following command as an example to get the signing key:

    $ key=$(awk -vRS="\n" -vORS="\\\n" '1' public.pem)
    $ echo ${key%\\n}
     
  3. If you want to pass the signing key as base64 optionally, use the following command:

    $ key=$(cat public.pem | base64 -w 0)
    $ echo $key
     
  4. 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.pem
     

    b. The command generates the certificate. Utilise the following steps to generate the certificate:

    1. Use the following command to generate private key for CA:

      $ openssl genrsa -out personal_ca.key 2048
       
    2. Generate a self-signed CA certificate using the following command:

      $ openssl req -new -x509 -key ca.key -out personal_ca.crt
       
    3. 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
     
  5. Create the env.yaml file according to the following examples:

    • If signingkey is 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 signingkey is 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 signingkey is 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!!!

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.

Note: For more information about attestation process, see Attestation.
  • If you use the plain text public RSA key for the attestationPublicKey in 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 attestationPublicKey in 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 attestationPublicKey in 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.

  1. Get the encrypted workload.yaml and encrypted env.yaml files.

  2. Add them into the user-data.yaml file:

    workload: hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn..............
    env: hyper-protect-basic.VWg/5/SWE+9jLfhr8q4i.........
     
  3. Create the contract.txt file. Add the value of workload first then add the value of env from the user-data.yaml file.

    hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn..............hyper-protect-basic.VWg/5/SWE+9jLfhr8q4i.........
     
    Note: Ensure that there is no space or new line after workload and before env. 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 the contract.txt file with tools such as hexdump. In the binary file dump, make sure that you do not see the 0a ASCII value as the last entry.
  4. 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 ' '
     
  5. Add the signature into the user-data.yaml file.

    workload: hyper-protect-basic.js7TGt77EQ5bgTIKk5C0pViFTRHqWtn..............
    env: hyper-protect-basic.VWg/5/SWE+9jLfhr8q4i.........
    envWorkloadSignature: Icbm1D/CVpLNYkWRC9e .....
     
Note: After creating a contract, you can verify the contract by deploying a sample workload. For more information, see Verifying the contract.

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 obtain sehdr information 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................