Skip to content

Delivery and login#

External Secrets delivers secrets to workloads as Kubernetes Secrets, and human SSO lets tenant members sign in to OpenBao.

Delivering secrets as Kubernetes Secrets#

Most applications should not call OpenBao at all. With the External Secrets Operator (ESO), on by default, the extension wires up delivery: ESO logs into OpenBao for the workload, fetches the secret and keeps an ordinary Kubernetes Secret in sync with it.

For each ServiceAccount you give a tier, the extension creates a SecretStore named <serviceaccount>-bao that logs in with the same role as the workload. You then request secrets with annotations on the Deployment — each produces one Kubernetes Secret, named <serviceaccount>-<name>:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: team-a-api
  annotations:
    bao.stakater.com/kv-secret.db-creds: postgres        # the whole secret
    bao.stakater.com/kv-secret.api-key: external#token   # just the "token" field
spec:
  template:
    spec:
      serviceAccountName: web
      containers:
        - name: web
          image: my/web:1.0
          envFrom:
            - secretRef:
                name: web-db-creds

The value is <leaf>[#<field>]: with #<field>, only that field is copied into the Secret; without it, every field becomes a key.

sequenceDiagram
    participant MTO as OpenBao extension
    participant ESO as External Secrets Operator
    participant Bao as OpenBao
    participant K8s as Kubernetes
    MTO->>ESO: SecretStore web-bao, ExternalSecret web-db-creds
    ESO->>Bao: log in with the workload's own role
    Bao-->>ESO: the secret at kv/data/dev/team-a-api/web/postgres
    ESO->>K8s: create or update Secret web-db-creds
    Note over ESO,Bao: repeats every refresh interval — 1h by default

The workload mounts the Secret and never learns OpenBao exists. Two more annotations cover the sharing cases: bao.stakater.com/kv-subscribe.<name> reads from a sibling namespace's shared folder, and bao.stakater.com/kv-import.<name> reads from another tenant (prefixed with the source, e.g. team-a-api/postgres, team-a/creds). Each needs the matching grant on the ServiceAccount — see Secrets and sharing.

Note

Every refresh is an OpenBao login. The default interval is one hour, and every workload logs in on it, so shortening the interval multiplies the load on OpenBao by the number of workloads.

Human login#

With sso.enabled, people sign in to OpenBao through your identity provider and their access follows their groups. For each tier, the extension creates a login role bound to an identity-provider group named <tenant>-<tier>s by default — so members of team-a-admins get the admin tier in team-a. Unlike a workload, which is confined to one namespace, a signed-in person gets that tier across the whole tenant.

sequenceDiagram
    participant MTO as OpenBao extension
    participant Bao as OpenBao
    participant IdP as OIDC provider
    participant User as Tenant member
    MTO->>Bao: create one OIDC login role per tier, bound to an IdP group
    User->>Bao: bao login -method=oidc -namespace=team-a
    Bao->>IdP: authenticate and read the group claim
    Bao-->>User: token carrying that tier's policies
    User->>Bao: read and write across the tenant
bao login -method=oidc -namespace=team-a role=sso-team-a-admin

Sessions are short — 15 minutes by default, 1 hour at most — because removing someone from a group in the identity provider does not revoke tokens already issued.


Previous: Encryption and certificates · Next: Security