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.