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 keyAt 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
| Piece | Status |
|---|---|
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
| Aspect | env.store vault fetch | ESO + Vault |
|---|---|---|
| Extra operator | No | Yes (ESO) |
| Resolution | At render — literal env value | Continuous — K8s Secret object |
| Source types | Image only | Any (git manifests too) |
| Rotation propagation | Next deploy | refreshInterval |
| Works today | ✅ | ✅ |
Related
- Secret Management Overview — compare the three layers
- External Secrets Operator —
env.store→ExternalSecret - Secret Stores API — vault provider schema + test endpoint
- Configuration —
workload.env[].storereference