Skip to content

Delivery and login#

Two ways people and workloads reach the secrets: External Secrets delivers them to workloads as Kubernetes Secrets, and human SSO lets tenant members sign in to the Vault UI.

Delivering secrets with External Secrets#

With parent.eso enabled (the default), a workload gets its secret as an ordinary Kubernetes Secret — no Vault code in the app. Annotate the Deployment; its serviceAccountName must be a ServiceAccount already annotated for Vault access (Giving an application a secret).

Annotation Value Reads
vault.stakater.com/kv-secret.<name> <leaf>[#<key>] the app's own <leaf>
vault.stakater.com/kv-subscribe.<name> <writer-ns>/<leaf>[#<key>] a subscribed _shared/ leaf
vault.stakater.com/kv-import.<name> <peer>/<leaf>[#<key>] an imported cross-tenant leaf
apiVersion: apps/v1
kind: Deployment
metadata:
  name: checkout
  namespace: acme-shop
  annotations:
    vault.stakater.com/kv-secret.db: db-creds          # whole leaf -> Secret
    vault.stakater.com/kv-secret.token: api#token       # one key of a leaf
spec:
  template:
    spec:
      serviceAccountName: checkout

Each annotation renders an ExternalSecret and a Secret named <serviceaccount>-<name> (here checkout-db, checkout-token), which the pod consumes with envFrom/secretKeyRef as usual. A Deployment whose ServiceAccount does not grant the path gets a vault-config-<deployment>.deploy-error ConfigMap explaining why.

Tip

A rotated value in Vault flows to the Secret on the next ESO refresh. Pair it with Reloader to roll the pods automatically.

Human SSO#

parent.sso.enabled=true with parent.sso.issuerUrl gives each tenant an OIDC mount oidc/sso and one Vault role per entry of sso.roles, bound to the identity-provider group <tenant>-<role>s (configurable with sso.tenantGroupTemplate). A member logs in to the tenant's Vault namespace and gets exactly the role their group grants — the same roles as workloads (viewer, editor, admin, audit-read):

VAULT_NAMESPACE=<vco.namespace>/acme \
  vault login -method=oidc -path=oidc/sso role=sso.acme.editor

All tenants share one identity-provider client, tenantValues.sso.oidc.clientId (default vault); set it to the ID of Vault's client in your IdP. parent.sso.issuerUrl is the issuer Vault talks to (Dex's, when Keycloak sits behind Dex). The client secret is a Secret vault-oidc-client-secret (key client-secret) in configNamespace.

A login refused for the group is not a 403 — Vault answers "does not match any associated bound claim values", so a user outside the tenant's groups simply cannot sign in to that namespace.


Previous: Secrets and sharing · Next: Security