Skip to main content
Redhat Developers  Logo
  • Products

    Platforms

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat AI
      Red Hat AI
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • View All Red Hat Products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat Developer Hub
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat OpenShift Local
    • Red Hat Developer Sandbox

      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Secure Development & Architectures

      • Security
      • Secure coding
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • Product Documentation
    • API Catalog
    • Legacy Documentation
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

Integrate Red Hat build of Trustee with the External Secrets Operator

July 28, 2025
Balint Tobik
Related topics:
ContainersKubernetes
Related products:
Red Hat OpenShift

Share:

    The Red Hat build of Trustee (formerly called confidential compute attestation) operator simplifies configuring secrets and serving them to confidential container pods that execute inside trusted execution environments (TEEs). You can set up the required secrets as Red Hat OpenShift Secret objects and make them accessible through Red Hat build of Trustee. You can use the same mechanism to integrate with external secret managers. 

    For instance, you can use the Secrets Store CSI Driver or the External Secrets Operator to synchronize secrets from external sources, such as HashiCorp Vault, and make them available to confidential containers (CoCo) executing in remote TEEs. For more details on CoCo, refer to our earlier blog series.

    Figure 1 shows the connection between Red Hat build of Trustee and third-party secret store solutions.

    Diagram showing Red Hat build of Trustee connecting to external secret stores: HashiCorp Vault, Google Secret Manager, Azure Key Vault, and Amazon Web Services Secrets Manager.
    Figure 1: Overview of Red Hat build of Trustee's integration with third-party secret store solutions.

    In this blog post, we are focusing on the integration of Trustee with External Secrets Operator for secure, dynamic secret delivery to CoCo pods. We cover installing and configuring the Operator, setting up Vault authentication and policies, creating SecretStore and ExternalSecret objects, verifying the setup, and configuring Trustee to use the fetched secrets within a CoCo pod, including how to update and refresh those secrets. 

    Install External Secrets Operator

    Create and apply the subscription

    #external-secrets-subscription.yaml
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: external-secrets-operator
      namespace: openshift-operators
    spec:
      channel: stable
      installPlanApproval: Automatic
      name: external-secrets-operator
      source: community-operators
      sourceNamespace: openshift-marketplace
      startingCSV: external-secrets-operator.v0.11.0
    oc apply -f external-secrets-subscription.yaml

    Verify installation

    watch oc get csv -n openshift-operators

    Example output:

    NAME                                DISPLAY                     VERSION   REPLACES                            PHASE
    external-secrets-operator.v0.11.0   External Secrets Operator   0.11.0    external-secrets-operator.v0.10.7   Succeeded

    Create and apply OperatorConfig

    Before any other resources provided by this Operator can be deployed, it is essential to create an OperatorConfig resource.

    #external-secrets-operatorconfig.yaml
    apiVersion: operator.external-secrets.io/v1alpha1
    kind: OperatorConfig
    metadata:
      name: cluster
      namespace: openshift-operators
    spec:
      prometheus:
        enabled: true
        service:
          port: 8080
      resources:
       requests:
         cpu: 10m
         memory: 96Mi
       limits:
         cpu: 100m
         memory: 256Mi
    oc apply -f external-secrets-operatorconfig.yaml

    Verify the cluster-external-secrets pods are running

    oc get pod -n openshift-operators

    Example output:

    NAME                                                            READY   STATUS    RESTARTS   AGE
    cluster-external-secrets-776967ccff-ngh8d                       1/1     Running   0          82m
    cluster-external-secrets-cert-controller-6965b4768b-kn5ct       1/1     Running   0          82m
    cluster-external-secrets-webhook-f59f945ff-qpfbx                1/1     Running   0          82m
    external-secrets-operator-controller-manager-79c4c47579-jsdf7   1/1     Running   0          89m

    Configure External Secrets using HashiCorp Vault

    Install Vault

    In official documentation in 2.7.3.5. Mounting secrets from HashiCorp Vault section, follow steps 1-3.

    Configure Vault to use Kubernetes authentication

    Enable the Kubernetes auth method:

    oc exec vault-0 --namespace=vault -- vault auth enable kubernetes

    Example output:

    Success! Enabled kubernetes auth method at: kubernetes/
    Create a policy for external secret operator:
    oc exec -i vault-0 --namespace=vault -- vault policy write external-secret-policy -<<EOF
    path "secret/data/*" {
    capabilities = ["read"]
    }
    EOF
    

    Example output:

    Success! Uploaded policy: external-secret-policy
    Update the Kubernetes auth method:
    TOKEN_REVIEWER_JWT="$(oc exec vault-0 --namespace=vault -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
    KUBERNETES_SERVICE_IP="$(oc get svc kubernetes --namespace=default -o go-template="{{ .spec.clusterIP }}")"
    oc exec -i vault-0 --namespace=vault -- vault write auth/kubernetes/config \
    token_reviewer_jwt="${TOKEN_REVIEWER_JWT}"  \
    kubernetes_host="https://${KUBERNETES_SERVICE_IP}:443" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
    disable_issuer_verification=true
    Example output:
    Success! Data written to: auth/kubernetes/config
    Create an authentication role to access:
    oc exec -i vault-0 --namespace=vault -- vault write auth/kubernetes/role/external-secret-role \
    bound_service_account_names=default \
    bound_service_account_namespaces=trustee-operator-system \
    policies=external-secret-policy \
    ttl=20m

    Example output:

    Success! Data written to: auth/kubernetes/role/external-secret-role

    Configure SecretStore and ExternalSecret

    Create a secret to the Vault:

    oc exec vault-0 --namespace=vault -- vault kv put secret/external-secret-example1 vaultTestSecret=vaultSecretValue

    Example output:

    =========== Secret Path ============
    secret/data/external-secret-example1
    ======= Metadata =======
    Key                Value
    ---                -----
    created_time       2025-06-02T11:20:17.745227354Z
    custom_metadata    <nil>
    deletion_time      n/a
    destroyed          false
    version            1

    Create and apply SecretStore:

    #vault-secretstore.yaml
    apiVersion: external-secrets.io/v1beta1
    kind: SecretStore
    metadata:
      name: vault-secret-store
      namespace: trustee-operator-system
    spec:
      provider:
        vault:
          server: "http://vault.vault:8200"
          path: "secret"
          version: "v2"
          auth:
            kubernetes:
              mountPath: "kubernetes"
              role: "external-secret-role"
              serviceAccountRef:
                name: "default"
    oc apply -f vault-secretstore.yaml

    Verify SecretStore:

    $ oc get secretstores.external-secrets.io -n trustee-operator-system vault-secret-store
    NAME                 AGE   STATUS   CAPABILITIES   READY
    vault-secret-store   13m   Valid    ReadWrite      True

    Create and apply ExternalSecret:

    # vault-externalsecret.yaml
    apiVersion: external-secrets.io/v1beta1
    kind: ExternalSecret
    metadata:
      name: vault-test-secret
      namespace: trustee-operator-system
    spec:
      refreshInterval: 1h
      secretStoreRef:
        name: vault-secret-store
        kind: SecretStore
      target:
        name: vault-test-secret
      data:
        - secretKey: externalVaultTestSecret
          remoteRef:
            key: secret/data/external-secret-example1
            property: vaultTestSecret
    oc apply -f vault-externalsecret.yaml

    Verify ExternalSecret:

    $ oc get externalsecrets.external-secrets.io -n trustee-operator-system vault-test-secret
    NAME                STORE                REFRESH INTERVAL   STATUS         READY
    vault-test-secret   vault-secret-store   1h                 SecretSynced   True
    Verify the Kubernetes secret has been created:
    $ oc get secrets -n trustee-operator-system vault-test-secret
    NAME                TYPE     DATA   AGE
    vault-test-secret   Opaque   1      2m45s

    Configure the Red Hat build of Trustee server and verify attestation

    Create or update the KbsConfig with the newly created external secret:

    # kbsconfig.yaml
    apiVersion: confidentialcontainers.org/v1alpha1
    kind: KbsConfig
    metadata:
      labels:
        app.kubernetes.io/name: kbsconfig
        app.kubernetes.io/instance: kbsconfig
        app.kubernetes.io/part-of: trustee-operator
        app.kubernetes.io/managed-by: kustomize
        app.kubernetes.io/created-by: trustee-operator
      name: kbsconfig
      namespace: trustee-operator-system
    spec:
      kbsConfigMapName: kbs-config-cm
      kbsAuthSecretName: kbs-auth-public-key
      kbsDeploymentType: AllInOneDeployment
      kbsRvpsRefValuesConfigMapName: rvps-reference-values
      kbsSecretResources: ["vault-test-secret", "kbsres1", "security-policy"]
      kbsResourcePolicyConfigMapName: resource-policy
      kbsServiceType: NodePort
      KbsEnvVars:
        RUST_LOG: debug
    oc apply -f kbsconfig.yaml

    Verify secret is fetchable in CoCo pod

    Sample initdata.toml:

    #initdata.toml
    algorithm = "sha256"
    version = "0.1.0"
    [data]
    "aa.toml" = '''
    [token_configs]
    [token_configs.coco_as]
    url = "http://10.0.2.6:31247"
    [token_configs.kbs]
    url = "http://10.0.2.6:31247"
    #cert = """
    #"""
    '''
    "cdh.toml"  = '''
    socket = 'unix:///run/confidential-containers/cdh.sock'
    credentials = []
    [kbc]
    name = "cc_kbc"
    url = "http://10.0.2.6:31247"
    #kbs_cert = """
    #"""
    '''
    "policy.rego" = '''
    package agent_policy
    default AddARPNeighborsRequest := true
    default AddSwapRequest := true
    default CloseStdinRequest := true
    default CopyFileRequest := true
    default CreateContainerRequest := true
    default CreateSandboxRequest := true
    default DestroySandboxRequest := true
    default ExecProcessRequest := true
    default GetMetricsRequest := true
    default GetOOMEventRequest := true
    default GuestDetailsRequest := true
    default ListInterfacesRequest := true
    default ListRoutesRequest := true
    default MemHotplugByProbeRequest := true
    default OnlineCPUMemRequest := true
    default PauseContainerRequest := true
    default PullImageRequest := true
    default ReadStreamRequest := true
    default RemoveContainerRequest := true
    default RemoveStaleVirtiofsShareMountsRequest := true
    default ReseedRandomDevRequest := true
    default ResumeContainerRequest := true
    default SetGuestDateTimeRequest := true
    default SetPolicyRequest := true
    default SignalProcessRequest := true
    default StartContainerRequest := true
    default StartTracingRequest := true
    default StatsContainerRequest := true
    default StopTracingRequest := true
    default TtyWinResizeRequest := true
    default UpdateContainerRequest := true
    default UpdateEphemeralMountsRequest := true
    default UpdateInterfaceRequest := true
    default UpdateRoutesRequest := true
    default WaitProcessRequest := true
    default WriteStreamRequest := true
    '''

    Convert the initdata.toml file to a Base64-encoded string:

    cat initdata.toml | gzip | base64 -w0

    Note: For more information about initdata, refer to the OpenShift documentation.

    Create a CoCo pod:

    #ocp-cc-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: ocp-cc-pod
      labels:
        app: ocp-cc-pod
      annotations:
        io.katacontainers.config.runtime.cc_init_data: H4sIAAAAAAAAA42VwW7bMAyG734KwzvkNCfptg4o0EOXdluBZTXsdDkUQcDIjC1EljyJzpo+/aimHbahsntwYIkfqZ8U6YCqjJVUN/F5nLgaTj6cJtEerZNG+61JOk0nSRTdlUCwihKAlEyjEraNRqPojswO9VoYvZWVW/23ToURZg2831nlo9VE7dl4PJ2kk/QkPT17Nz15/9FH/9dttxl0eSPQkrcn/O5/vJooEWX9pO9JoDNihx4cdVrec6Cx7fT48aASNUlQb3lBIDXnPPbu3mMUCYtPdsfOdyvWuNuIVaShQX+sEGteJ0MqOZP1y0pbo6Q4pBYr81zMFsQOKoz50bQ+AlFU4hY6RfFFWV7k2XeUVb0x1uX4s0NH8dl5TLbDv7HiF7Qh80wZhwWVUgcJ0x4+S4VBu0UgnD0XrR8rQJcbcx+CLnnTmsMAdXWPIrNGoAtm/QVpjmSl6CNubuZXey5tEPG7l8h5qWCYb9LRtSa0W2A9fVRuOgoTc2y+GmpVV306cG6bYLlvtOIyz7Jb9ggxGXRu+EayTqnrhpsrBOQIZUF8b8GDcmzMfvikI1YQKPwhLUmzdUUNFuem0xQsSY4Oscy5F0xzifserGuGNRRIx/vkLlzIJpg0c9njpAUBWWlQA/3HuVoa1uSphQUhddXDkHtFJNMOBFrQYemn3MmHYPK3bfmaWT5iV22NDVpQ/dd4hP/MSD/WPyRLkDRQ+CX/eeHLTes/qb8BasRfON8GAAA=
    spec:
      runtimeClassName: kata-remote
      containers:
        - name: skr-openshift
          image: registry.access.redhat.com/ubi9/ubi:9.3
          command:
            - sleep
            - "36000"
          securityContext:
            privileged: false
            seccompProfile:
              type: RuntimeDefault
    oc apply -f ocp-cc-pod.yaml

    Fetch the secret from CoCo pod:

    oc exec -it ocp-cc-pod -- curl http://127.0.0.1:8006/cdh/resource/default/vault-test-secret/externalVaultTestSecret

    Example printout:

    vaultSecretValue

    Verify the updated secret value is fetchable from CoCo pod

    Update the secret value in Vault:

    oc exec vault-0 --namespace=vault -- vault kv put secret/external-secret-example1 vaultTestSecret=UpdatedVaultSecretValue

    The Kubernetes secret created by the External Secret Operator is updated when:

    • the ExternalSecret's spec.refreshInterval has passed and is not 0.
    • the ExternalSecret's labels or annotations are changed.
    • the ExternalSecret's spec has been changed.

    To trigger a secret refresh:

    oc annotate externalsecrets.external-secrets.io -n trustee-operator-system vault-test-secret force-sync=$(date +%s) --overwrite

    Fetch the same secret from CoCo pod:

    oc exec -it ocp-cc-pod -- curl http://127.0.0.1:8006/cdh/resource/default/vault-test-secret/externalVaultTestSecret

    Example printout:

    UpdatedVaultSecretValue

    Summary

    In this blog post, we demonstrated how OpenShift secrets generated and managed by the External Secrets Operator (ESO) can be made available to TEEs via Red Hat build of Trustee. ESO automatically provisions and synchronizes these secrets with external secret stores, and Red Hat build of Trustee acts as the gatekeeper to make it available to the CoCo pods. 

    While this blog focuses on using HashiCorp Vault, ESO is compatible with a wide variety of external secret store providers, such as AWS Secrets Manager, Azure Key Vault, and Google Cloud Secret Manager.

    Learn about Confidential Containers. 

    Related Posts

    • How to set up OpenShift confidential clusters on Azure

    • How to deploy confidential containers on bare metal

    • How to debug confidential containers securely

    • Protect secrets in Git with the clean/smudge filter

    • How to share secrets across Red Hat OpenShift projects

    • How the External Secrets Operator manages Quay credentials

    Recent Posts

    • Skopeo: The unsung hero of Linux container-tools

    • Automate certificate management in OpenShift

    • Customize RHEL CoreOS at scale: On-cluster image mode in OpenShift

    • How to set up KServe autoscaling for vLLM with KEDA

    • How I used Cursor AI to migrate a Bash test suite to Python

    What’s up next?

    Learn how to convert existing DeploymentConfigs into Kubernetes Deployments in Red Hat OpenShift.

    Start the activity
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue