HashiCorp Vault for secrets management in Kubernetes
Ryan Nakamura
Feb 2026
1 tab
# === Vault Agent Injector: Auto-inject secrets into pods ===
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
annotations:
# Vault Agent Injector annotations
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "api-server"
# Inject database credentials
vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/api-readonly"
vault.hashicorp.com/agent-inject-template-db-creds: |
{{- with secret "database/creds/api-readonly" -}}
export DATABASE_URL="postgres://{{ .Data.username }}:{{ .Data.password }}@db.internal:5432/myapp"
{{- end }}
# Inject API keys from KV store
vault.hashicorp.com/agent-inject-secret-api-keys: "secret/data/production/api-keys"
vault.hashicorp.com/agent-inject-template-api-keys: |
{{- with secret "secret/data/production/api-keys" -}}
export STRIPE_SECRET_KEY="{{ .Data.data.stripe_key }}"
export SENDGRID_API_KEY="{{ .Data.data.sendgrid_key }}"
{{- end }}
# Auto-rotate: re-read secrets every 5 minutes
vault.hashicorp.com/agent-inject-command-db-creds: "kill -HUP $(pidof api-server)"
vault.hashicorp.com/secret-volume-path: "/vault/secrets"
spec:
serviceAccountName: api-server
containers:
- name: api
image: myapp-api:latest
command:
- /bin/sh
- -c
- |
# Source the injected secrets
source /vault/secrets/db-creds
source /vault/secrets/api-keys
exec ./start-server
ports:
- containerPort: 3000
resources:
requests:
cpu: 250m
memory: 256Mi
---
# === Vault Policy ===
# Save as: vault-policy-api-server.hcl
# vault policy write api-server vault-policy-api-server.hcl
#
# path "database/creds/api-readonly" {
# capabilities = ["read"]
# }
#
# path "secret/data/production/api-keys" {
# capabilities = ["read"]
# }
#
# path "secret/metadata/production/*" {
# capabilities = ["list"]
# }
---
# === Vault Kubernetes Auth Setup (run once) ===
# vault auth enable kubernetes
#
# vault write auth/kubernetes/config \
# kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443"
#
# vault write auth/kubernetes/role/api-server \
# bound_service_account_names=api-server \
# bound_service_account_namespaces=production \
# policies=api-server \
# ttl=1h
---
# === External Secrets Operator (alternative approach) ===
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: "https://vault.internal:8200"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "api-server"
serviceAccountRef:
name: "api-server"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: api-secrets
namespace: production
spec:
refreshInterval: 5m
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: api-secrets # Creates this K8s Secret
creationPolicy: Owner
data:
- secretKey: STRIPE_KEY
remoteRef:
key: production/api-keys
property: stripe_key
- secretKey: SENDGRID_KEY
remoteRef:
key: production/api-keys
property: sendgrid_key
- secretKey: JWT_SECRET
remoteRef:
key: production/auth
property: jwt_secret
1 file · yaml
Explain with highlit
Integrate HashiCorp Vault with Kubernetes for dynamic secrets management. Use the Vault Agent sidecar injector to automatically inject secrets into pods, configure KV secret engines, and set up Kubernetes authentication. Eliminate hardcoded secrets from your manifests.