Creating the workload section of the contract

This step must be performed by the Solution Provider.

Prerequisites

  • You have the encryption certificate files downloaded from the installation package.
  • You have the sealed secret client binary files downloaded from the installation package.

Procedure

  1. Create a directory ContractDirectory by running the following command:
    mkdir ContractDirectory
  2. Copy encryption certificate to the working directory by running the following command:

    For Peerpod

    cp ibm-confidential-computing-container-26.3.1-encrypt.crt ContractDirectory

    For Bare Metal

    cp ibm-confidential-computing-container-2.0.6-encrypt.crt ContractDirectory
  3. Change the directory to ContractDirectory by running the following command:
    cd ContractDirectory
  4. If you are creating the contract with the cosign verified images, you must perform the Additional steps for the cosign contract.

    OR

    If you are creating the contract with the workload sealed secret you must perform the Additional steps for the sealed secret contract.

  5. Create SamplePolicyPermissiveRules.rego according to the following example:
    Note: For more information about Rego policies and the associated restrictive rules, see Rego policy rules and snippets.
    package policy
    
    default AddARPNeighborsRequest := false
    default AddSwapRequest := false
    default CheckRequest := true
    default CloseStdinRequest := false
    default CopyFileRequest := false
    CopyFileRequest {
        allow_path(input.path)
        dir_mode := bits.lsh(1, 31)
        allowed_dir_permission := bits.or(dir_mode, 488)
        input.dir_mode == allowed_dir_permission
    }
    allow_path(path) {
        regex.match("/run/kata-containers/shared/containers/[[:xdigit:]]+", path)
    }
    default CreateContainerRequest := false
    CreateContainerRequest {
      allow_image(input.OCI.Annotations["io.kubernetes.cri-o.ImageName"])
    }
    allow_image(image_name) {
      regex.match("quay\\.io/openshift-release-dev/ocp-v4\\.0-art-dev@sha256:[a-f0-9]{64}", image_name)
    }
    allow_image(image_name) {
        image_name == "<WorkloadImage>"
    }
    default CreateSandboxRequest := true
    default DestroySandboxRequest := true
    default GetMetricsRequest := false
    default GetOOMEventRequest := true
    default GuestDetailsRequest := false
    default ListInterfacesRequest := false
    default ListRoutesRequest := false
    default MemHotplugByProbeRequest := false
    default OnlineCPUMemRequest := true
    default PauseContainerRequest := false
    default PullImageRequest := false
    default ReadStreamRequest := false
    default RemoveContainerRequest := false
    RemoveContainerRequest {
        allow_startcontainer(input.container_id)
    }
    allow_startcontainer(container_id) {
        regex.match("^[a-f0-9]{64}$", container_id)
    }
    default RemoveStaleVirtiofsShareMountsRequest := false
    default ReseedRandomDevRequest := false
    default ResumeContainerRequest := false
    default SetGuestDateTimeRequest := false
    default SetPolicyRequest := false
    default SignalProcessRequest := true
    default StartContainerRequest := false
    StartContainerRequest {
        allow_startcontainer(input.container_id)
    }
    allow_startcontainer(container_id) {
        regex.match("^[a-f0-9]{64}$", container_id)
    }
    default StartTracingRequest := false
    default StatsContainerRequest := false
    default StopTracingRequest := false
    default TtyWinResizeRequest := false
    default UpdateContainerRequest := false
    default UpdateEphemeralMountsRequest := true
    default UpdateInterfaceRequest := true
    default UpdateRoutesRequest := true
    default WaitProcessRequest := false
    default WriteStreamRequest := false
    default WriteStdinRequest := false
    default ReadStdoutRequest := true
    default ReadStderrRequest := true
    default GetIPTablesRequest := false
    default SetIPTablesRequest := false
    default GetGuestDetailsRequest := false
    GetGuestDetailsRequest {
        input.mem_block_size == true
        input.mem_hotplug_probe == true
    }
    default GetVolumeStatsRequest := false
    default ResizeVolumeRequest := false
    default VersionRequest := false
    default ExecProcessRequest := false  
    Important:

    In the Rego policy, for IBM CCCO Bare Metal deployments, make sure the following requests are always set to true. If any of them are set to false, important guest-side functions do not work correctly:

    1. OnlineCPUMemRequest: If this is false, the CPUs and/or memory for the pod do not activate inside the guest.
    2. UpdateInterfaceRequest: If this is false, the guest does not create or attach pod network interfaces.
    3. UpdateRoutesRequest: If this is false, the guest has incomplete routing tables, which can break network connectivity.
    4. UpdateEphemeralMountsRequest: If this is false, the guest does not reconcile ephemeral and projected volumes.
    5. SignalProcessRequest: If this is false, containers do not receive process signals, including important ones like SIGTERM.
    6. GetOOMEventRequest: If this is false, the kubelet cannot see Out-Of-Memory (OOM) events in the guest.
    Note:

    Enabling exec capabilities for interactive shell access in CCCO Bare Metal deployments

    Important: It is not recommended to enable exec processes on CCCO VMs. Enable only for debugging purposes.

    The sample policy above has restrictive settings suitable for most workloads. However, if you require interactive shell access or exec operations for debugging purposes (for example, using kubectl exec or oc exec), you must enable additional policy rules.

    To enable exec support, set the following related rules to true in your SamplePolicyPermissiveRules.rego file:

    • ExecProcessRequest := true - Allows execution of processes inside the container
    • TtyWinResizeRequest := true - Enables terminal window resizing for interactive shells
    • WaitProcessRequest := true - Allows waiting for process completion to capture exit codes
    • WriteStdinRequest := true - Enables writing to process stdin for interactive input
    • ReadStdoutRequest := true - Allows reading process stdout to capture command output (already set to true in the sample policy)
    • CloseStdinRequest := true - Enables proper stdin closure for process termination

    These rules are interdependent and must be enabled together for exec operations to function properly. Enabling only ExecProcessRequest without the supporting I/O and terminal management rules results in non-functional exec operations.

    Note: If you are using persistent block volumes, make sure that RemoveContainerRequest is set to true.
  6. Replace the <WorkloadImage> in SamplePolicyPermissiveRules.rego with your workload image according the format shown in the below example:
    image_name == "quay.io/prometheus/busybox:latest"
    Important: In the SamplePolicyPermissiveRules.rego, make sure to include the container image in the above mentioned format to enable image pulling and ensure proper functionality for all workloads. For more information, see CreateContainerRequest policy.
  7. Set the encoded policy with the SamplePolicyPermissiveRules.rego by running the following commands:
    1. For macOS:
      export encoded_policy=$(cat SamplePolicyPermissiveRules.rego | gbase64 -w 0)
    2. For linux:
      export encoded_policy=$(cat SamplePolicyPermissiveRules.rego | base64 -w 0)
  8. Create a workload.yaml according to the following example:
    • For basic contract/contract with attestation encryption/contract with env sealed secret:
      cat << EOF > workload.yaml
      type: workload
      confidential-containers:
        regoValidator:
          policy: <BASE64-ENCODED-REGO-POLICY>
      EOF

      If you want to use the workload image from the private registry, include the following auths section in the workload.yaml file with the necessary information:

      auths:
        <PRIVATE_REGISTRY_URL>:
          username: <USER_NAME>
          password: <API_KEY_OR_PASSWORD>
      Note: If you want to add encrypted persistent volumes to your contract, see Configuring volumes in the workload section for detailed instructions on adding volume configurations.
    • For the contract with cosign verified container images:
      cat << EOF > workload.yaml
      workload:
      type: workload
      confidential-containers:
        regoValidator:
          policy: <BASE64-ENCODED-REGO-POLICY>
        config:
          cosign:
            quay.io/<username>/busybox:
              publicKey: ${cosign_pub_base64}
      EOF
    • For the contract with workload sealed secret:
      cat << EOF > workload.yaml
      type: workload
      confidential-containers:
        regoValidator:
          policy: ${encoded_policy}
        secret:
          verificationKey: "${SECRET_VERIFICATION_KEY}"
          decryptionKey: "${SECRET_DECRYPTION_KEY}"
      EOF
  9. Create the encryption-workload.sh script with the following content:
    export CONTRACT_KEY="ibm-confidential-computing-container-encrypt.crt"
    export WORKLOAD="workload.yaml"
    export PASSWORD="$(openssl rand 32 | base64 -w0)"
    export ENCRYPTED_PASSWORD="$(echo -n "$PASSWORD" | base64 -d | openssl pkeyutl -encrypt -inkey $CONTRACT_KEY -certin | base64 -w0 )"
    export ENCRYPTED_WORKLOAD="$(echo -n "$PASSWORD" | base64 -d | openssl enc -aes-256-cbc -pbkdf2 -pass stdin -in "$WORKLOAD" | base64 -w0)"
    echo "workload: hyper-protect-basic.${ENCRYPTED_PASSWORD}.${ENCRYPTED_WORKLOAD}" > encrypted-workload.yaml
  10. Make the encryption-workload.sh script executable by running the following command:
    chmod +x encryption-workload.sh
  11. Run the following script to create encrypted-workload.yaml:
    ./encryption-workload.sh
  12. Run the following command to view encrypted-workload.yaml:
    cat encrypted-workload.yaml

    Example output:

    workload: hyper-protect-basic.d458ARMC89mB0ymq3we6LDHFaF8oWVB6Nn5fvbFhJvMm2xFDnF
    MTHEL3KR/+KsazFxTRpBab/M+R8ocT9mfenYyRj6L6n8T/FWgjnaT..............
  13. Share the encrypted-workload.yaml with the Data Owner
  14. Generate the contract signing key pair.