Deploy Trustee in Kubernetes
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.
It is highly recommended to refer to the Introducing Confidential Containers Trustee: Attestation Services Solution Overview and Use Cases prior to deploying it.
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.
If we don’t have a running cluster yet, we can easily bring it up with kind. For example:
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
For more information on the Operator Lifecycle Manager (OLM) and the operator installation procedure from OperatorHub.io, please consult this guide.
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
Note that the Trustee operator has been already published in the operator hub catalog. Trustee operator v0.17.0 is aligned to CoCo v.0.18.0 release.
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.
The following command shows how to edit the reference values in RVPS. Note that a sample list of reference-values is provided by default, because the sample attester doesn’t handle real measurements. According to your HW platform, you’d need to register some real trusted digests instead.
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:
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.