Deploy Trustee in Kubernetes

Introduction to the trustee-operator for deploying Trustee in a Kubernetes cluster.

Introduction

In this blog, we’ll be going through the deployment of Trustee, the Key Broker Service that provides keys/secrets to clients that want to execute workloads confidentially. Trustee provides a built-in attestation service that complies to the RATS specification.

In this document, we’ll be focusing on how to deploy Trustee in Kubernetes using the Trustee operator.

Definitions

First of all, let’s introduce some definitions.

In confidential computing environments, Attestation is crucial in verifying the trustworthiness of the location where you plan to run your workload.

The Attester provides Evidence, which is evaluated and appraised to decide its trustworthiness.

The Endorser is the HW manufacturer who provides an endorsement, which the verifier uses to validate the evidence received from the attester.

The reference value provider service (RVPS) is a component in the Attestation Service (AS) responsible for storing and providing reference values.

Kubernetes deployment

The following instructions are assuming a Kubernetes cluster is set up with the Operator Lifecycle Manager (OLM) running. OLM helps users install, update, and manage the lifecycle of Kubernetes native applications (Operators) and their associated services.

kind create cluster -n trustee
# install the olm operator
curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.31.0/install.sh | bash -s v0.31.0

Subscription

A subscription, defined by a Subscription object, represents an intention to install an Operator. It is the custom resource that relates an Operator to a catalog source:

kubectl apply -f - << EOF
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata: 
  name: my-trustee-operator 
  namespace: operators
spec: 
  channel: alpha
  name: trustee-operator
  source: operatorhubio-catalog
  sourceNamespace: olm
EOF

Check Trustee Operator installation

Now it is time to check if the Trustee operator has been installed properly, by running the command:

kubectl get csv -n operators

We should expect something like:

NAME                       DISPLAY            VERSION   REPLACES                  PHASE
trustee-operator.v0.17.0   Trustee Operator   0.17.0    trustee-operator.v0.5.0   Succeeded

Configuration

The Trustee Operator configuration requires a few steps. Some of the steps are provided as an example, but you may want to customize the examples for your real requirements.

There are 2 different profile modes, permissive (for development) and restrictive (for production).

Restrictive Mode First of all the required TLS certificates need to be created.

For a production environment, customers are typically required to provide their own certificates signed by a valid Certificate Authority (CA).

The following instructions, however, are specifically targeted for a development environment, utilizing self-signed certificates generated by the cert-manager Operator.

helm install   cert-manager jetstack/cert-manager   --namespace cert-manager   --create-namespace   --version v1.19.1   --set crds.enabled=true

Create the certificate issuer and https/token-verification certificates:

kubectl apply -f - << EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: kbs-https
  namespace: operators
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: kbs-https
  namespace: operators
spec:
  dnsNames:
    - kbs-service
  secretName: trustee-tls-cert
  issuerRef:
    name: kbs-https
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: kbs-token
  namespace: operators
spec:
  dnsNames:
    - kbs-service
  secretName: trustee-token-cert
  issuerRef:
    name: kbs-token
  privateKey:
    algorithm: ECDSA
    encoding: PKCS8
    size: 256
EOF

TrusteeConfig CR creation:

kubectl apply -f - << EOF
apiVersion: confidentialcontainers.org/v1alpha1
kind: TrusteeConfig
metadata:
  labels:
    app.kubernetes.io/name: trusteeconfig
    app.kubernetes.io/instance: trusteeconfig
    app.kubernetes.io/part-of: trustee-operator
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: trustee-operator
  name: trusteeconfig
  namespace: operators
spec:
  profileType: Restricted
  kbsServiceType: ClusterIP
  httpsSpec:
    tlsSecretName: trustee-tls-cert
  attestationTokenVerificationSpec:
    tlsSecretName: trustee-token-cert
EOF
Permissive Mode TrusteeConfig CR creation:
apiVersion: confidentialcontainers.org/v1alpha1
kind: TrusteeConfig
metadata:
  labels:
    app.kubernetes.io/name: trusteeconfig
    app.kubernetes.io/instance: trusteeconfig
    app.kubernetes.io/part-of: trustee-operator
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: trustee-operator
  name: trusteeconfig
  namespace: operators
spec:
  profileType: Permissive
  kbsServiceType: ClusterIP
EOF

When the user creates a TrusteeConfig CR, the following objects are created automatically in the operator namespace:

trusteeconfig-kbs-config

This ConfigMap mounts the main KBS configuration file onto the trustee container filesystem. It’s boiler-plate configuration and it works out-of-the-box.

trusteeconfig-resource-policy

This ConfigMap mounts the resource-policy onto the trustee container filesystem. It can be permissive or restrictive depending on the TrusteeConfig profileType. Typically there is no need to edit the ConfigMap content, unless required for specific use cases.

trusteeconfig-attestation-policy

This ConfigMap mounts the attestation-policy onto the trustee container filesystem. Typically there is no need to edit the ConfigMap content, it works out-of-the-box.

trusteeconfig-rvps-reference-values

This ConfigMap mounts the RVPS reference values onto the trustee container filesystem. A sample list of reference values is set by default, so in production it is recommended to edit the ConfigMap and insert some measured PCR values.

trusteeconfig-tdx-config

This ConfigMap is specific for the Intel TDX platform and mounts the PCCS configuration file onto the trustee container filesystem. It’s boiler-plate configuration and it works out-of-the-box.

trusteeconfig-auth-secret

This Secret resource automatically mounts a private/public key pair onto the trustee container’s filesystem. An administrator possessing the corresponding private key can then invoke the trustee’s admin API to add new secrets or modify policies.

kbsres1

This is a sample Secret for testing purposes. The secret can be retrieved by any attested client.

trusteeconfig-kbs-config

This is the auto-generated KbsConfig custom resource (CR). No need to change it, it works out-of-the-box.

Reference Values

The reference values are an important part of the attestation process. The client collects the measurements (from the running software, the TEE hardware and its firmware) and submits a quote with the claims to the attestation server. These measurements, in order for the attestation protocol to succeed, have to match one of potentially multiple configured valid values that had been registered to Trustee previously. You could also apply flexible rules like “firmware of secure processor > v1.30”, etc. This process guarantees the cVM (confidential VM) is running the expected software stack and that it hasn’t been tampered with.

kubectl edit cm -n operators trusteeconfig-rvps-reference-values

Create secrets

How to create secrets to be shared with the attested clients? In this example we create a secret test with two entries. These resources (key1, key2) can be retrieved by the Trustee clients. You can add more secrets as per your requirements.

kubectl create secret generic test --from-literal key1=res1val1 --from-literal key2=res1val2 -n operators

export CR_NAME=$(kubectl get kbsconfig -n operators -o=jsonpath='{.items[0].metadata.name}') && kubectl patch KbsConfig -n operators $CR_NAME --type=json -p='[{"op":"add", "path":"/spec/kbsSecretResources/-", "value":"test"}]'

Resource policy

A resource policy that works out-of-the-box is created by default by TrusteeConfig CR. The policy content depends on the TrusteeConfig profile chosen (permissive or restrictive). Type the following command should you need to customize the default policy.

kubectl edit cm -n operators trusteeconfig-resource-policy

Attestation policy

An attestation policy that works out-of-the-box is created by default by TrusteeConfig CR. It will accept any workload that passes attestation and meets baseline trust claims. Type the following command should you need to customize the default policy.

kubectl edit cm -n operators trusteeconfig-attestation-policy

KbsConfig CR

The KbsConfig custom resource (CR) is automatically generated by the operator. It can be fetched with this command:

KBS_CONFIG=$(kubectl get trusteeconfig trusteeconfig -n operators -o jsonpath='{.status.kbsConfigRef.name}')

Edit the KbsConfig with the following command should you need to provide some optional configuration:

oc edit KbsConfig -n operators $KBS_CONFIG

For example:

  # Specify this attribute for enabling DEBUG log in trustee pods
  KbsEnvVars:
    RUST_LOG: debug
  # Number of desired trustee pods. The default is 1, increase the number of replicas to enable High Availability
  KbsDeploymentSpec:
    replicas: 1

Set Namespace for the context entry

kubectl config set-context --current --namespace=operators

Check if the PODs are running

kubectl get pods -n operators
NAME                                                   READY   STATUS    RESTARTS   AGE
trustee-deployment-7bdc6858d7-bdncx                    1/1     Running   0          69s
trustee-operator-controller-manager-6c584fc969-8dz2d   1/1     Running   0          4h7m

Also, the log should report something like:

POD_NAME=$(kubectl get pods -l app=kbs -o jsonpath='{.items[0].metadata.name}' -n operators)
kubectl logs -n operators $POD_NAME
[2026-02-10T15:21:47Z INFO  kbs] Using config file /etc/kbs-config/kbs-config.toml
[2026-02-10T15:21:47Z INFO  tracing::span] Initialize RVPS;
[2026-02-10T15:21:47Z INFO  attestation_service::rvps] launch a built-in RVPS.
[2026-02-10T15:21:47Z WARN  reference_value_provider_service::extractors] No configuration for SWID extractor provided. Default will be used.
[2026-02-10T15:21:47Z WARN  attestation_service::ear_token::broker] Simple Token has been deprecated in v0.16.0. Note that the `attestation_token_broker` config field `type` is now ignored and the token will always be an EAR token.
[2026-02-10T15:21:47Z WARN  attestation_service::policy_engine::opa] Policy default_cpu already exists, so the default policy will not be written.
[2026-02-10T15:21:47Z INFO  kbs::api_server] Starting HTTPS server at [0.0.0.0:8080]
[2026-02-10T15:21:47Z INFO  actix_server::builder] starting 4 workers
[2026-02-10T15:21:47Z INFO  actix_server::server] Actix runtime found; starting in Actix runtime
[2026-02-10T15:21:47Z INFO  actix_server::server] starting service: "actix-web-service-0.0.0.0:8080", workers: 4, listening on: 0.0.0.0:8080

End-to-End Attestation

We create a pod using an already existing image where the kbs-client is deployed:

kubectl apply -f - << EOF
apiVersion: v1
kind: Pod
metadata:
  name: kbs-client
  namespace: operators
spec:
  containers:
  - name: kbs-client
    image: quay.io/confidential-containers/kbs-client:v0.17.0
    imagePullPolicy: IfNotPresent
    command:
      - sleep
      - "360000"
    env:
      - name: RUST_LOG
        value:  none
EOF

Finally we are able to test the entire attestation protocol, when fetching one of the aforementioned secret (HTTPS enabled).

Note: Make sure the resource-policy is permissive for testing purposes. For example:

packagepolicydefaultallow=true package policy default allow = true
kubectl get secret trustee-tls-cert -n operators -o json | jq -r '.data."tls.crt"' | base64 --decode > https.crt
kubectl cp -n operators https.crt kbs-client:/
kubectl exec -it -n operators kbs-client -- kbs-client --cert-file https.crt --url https://kbs-service:8080 get-resource --path default/kbsres1/key1
cmVzMXZhbDE=

If we type the command:

echo cmVzMXZhbDE= | base64 -d

We’ll get res1val1, the secret we created before.

Summary

In this blog we have shown how to use the Trustee operator for deploying Trustee and run the attestation workflow with a sample attester.