Secret Management

Vault Direct

env.store → Vault KV fetch at deploy time — image-source only

Vault Direct — 🚧 works for image env, templating planned

Wardn can fetch secret values from Vault at deploy time for image-source workloads — no ESO hop, no K8s Secret object. Git-manifest templating (annotations, x-wardn-vault) is not implemented.

What works today

env.store on an image-source workload resolves {id, path, key} against a registered vault/openbao store at render:

spec:
  source:
    type: Image
    image:
      repository: ghcr.io/acme/api
      workload:
        env:
          - name: DB_PASSWORD
            store:
              id: sts_01H8…
              path: prod/my-app/db       # KV v2 path
              key: password              # data key

At render, the operator calls the store's Fetch(ctx, "prod/my-app/db") → KV v2 read → injects password as a literal env value on the Deployment. Non-KV v2 mounts or missing keys fail the reconcile with a named error.

Configure the store

# HashiCorp Vault
curl -X POST http://localhost:8080/api/v1/secret-stores -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod-vault", "type": "vault", "provider": "vault",
    "config": {"address": "https://vault.example.com:8200", "mountPath": "secret"},
    "credentials": {"token": "hvs.…"}}'

# OpenBao — same implementation, separate provider id
curl -X POST http://localhost:8080/api/v1/secret-stores -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{"name":"dev-bao","type":"vault","provider":"openbao",
       "config":{"address":"https://bao.example.com:8200"},
       "credentials":{"token":"…"}}'

config fields per the provider schema (from GET /secret-stores/providers): address (required, https:// enforced in production), mountPath. credentials: token or AppRole roleId/secretId.

Test the store

curl -X POST http://localhost:8080/api/v1/secret-stores/sts_01H8…/test -b cookies.txt
# {"status":"connected","latency":"118ms","details":"authenticated; token ttl 1h"}

Test does lookup-self — it proves the token authenticates and reports the TTL via credentialsExpireAt.

Vault policy for the operator's reads

path "secret/data/prod/*" {
  capabilities = ["read"]
}

Fetch is a GET /v1/{mountPath}/data/{path} — KV v2 only.

What's not implemented

PieceStatus
env.store vault fetch on image sources✅
Git-manifest templating ({{ vault:key }}, x-wardn-vault)📋 no support
Kubernetes-auth login method📋 token/AppRole only
Secret rotation / TTL re-fetch📋 values baked into the rendered Deployment at apply time — re-deploy to pick up rotation
Annotations (wardn.io/vault-path)📋

Env values are rendered into the Deployment spec. env.store resolves once per sync — rotating the Vault value doesn't propagate until the next deploy/sync. For continuous-secret semantics use ESO.

Vault Direct vs ESO

Aspectenv.store vault fetchESO + Vault
Extra operatorNoYes (ESO)
ResolutionAt render — literal env valueContinuous — K8s Secret object
Source typesImage onlyAny (git manifests too)
Rotation propagationNext deployrefreshInterval
Works today✅✅

On this page