Kubernetes
Vault
Vaultesosecret

📘 Vault + External Secrets Operator (ESO) + ENV Injection Demo

This documentation provides a step-by-step integration of HashiCorp Vault with External Secrets Operator (ESO) to securely inject secrets as environment variables into Kubernetes Pods. This setup ensures security best practices for managing application secrets at runtime.


📂 Project Structure

vault-eso-demo/
├── README.md
├── k8s/
│   ├── 00-namespace.yaml
│   ├── 01-serviceaccount.yaml
│   ├── 02-secretstore.yaml
│   ├── 03-externalsecret.yaml
│   ├── 04-nginx-deployment.yaml
└── vault/
    ├── policy.hcl
    └── vault-setup.sh

🔧 Prerequisites

ComponentRequired
Kubernetes Cluster
Helm CLI
HashiCorp Vault (dev mode ok)
External Secrets Operator

🚀 Setup Walkthrough

1. 📦 Install External Secrets Operator

helm repo add external-secrets https://charts.external-secrets.io
helm repo update
 
helm upgrade --install external-secrets external-secrets/external-secrets \
  --namespace external-secrets \
  --create-namespace \
  --set webhook.certManager.enabled=false \
  --set webhook.selfSigned.enabled=true

Validate installation:

kubectl get pods -n external-secrets -o wide
kubectl get crds | grep external-secrets.io
kubectl api-resources | grep -i external

2. 🔐 Vault Configuration (dev mode)

All commands assume execution inside the Vault pod or with the Vault CLI set up locally.

vault auth enable kubernetes
 
vault write auth/kubernetes/config \
  token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
  kubernetes_host="https://${KUBERNETES_PORT_443_TCP_ADDR}:443" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

Create policy: vault/policy.hcl

path "secret/data/myapp/env" {
  capabilities = ["read"]
}

Apply policy and create role:

vault policy write myapp-policy vault/policy.hcl
 
vault write auth/kubernetes/role/myapp-role \
  bound_service_account_names=external-secrets-sa \
  bound_service_account_namespaces=default \
  policies=myapp-policy \
  ttl=24h

Create test secrets:

vault kv put secret/myapp/env DEMO_API_KEY="supersecret" DEMO_ENV="production"

3. ⚙️ Kubernetes Resource Setup

Apply all manifests in sequence:

kubectl apply -f k8s/00-namespace.yaml
kubectl apply -f k8s/01-serviceaccount.yaml
kubectl apply -f k8s/02-secretstore.yaml
kubectl apply -f k8s/03-externalsecret.yaml
kubectl apply -f k8s/04-nginx-deployment.yaml

✅ Breakdown of Key Resources

00-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: default
01-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-secrets-sa
  namespace: default
02-secretstore.yaml
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
  name: vault-backend
  namespace: default
spec:
  provider:
    vault:
      server: "http://vault.vault.svc.cluster.local:8200"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "myapp-role"
          serviceAccountRef:
            name: external-secrets-sa
03-externalsecret.yaml
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: myapp-secret
  namespace: default
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: myapp-env-secret
    creationPolicy: Owner
  dataFrom:
    - extract:
        key: secret/data/myapp/env
04-nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      serviceAccountName: external-secrets-sa
      containers:
        - name: nginx
          image: nginx:alpine
          envFrom:
            - secretRef:
                name: myapp-env-secret
          command: ["/bin/sh", "-c"]
          args:
            - echo "ENV VARS:"; env | grep DEMO_ ; sleep 3600

✅ Validation

Once the pod is up and running, verify that secrets have been correctly injected as environment variables:

kubectl get pods
kubectl exec -it <nginx-demo-pod> -- env | grep DEMO_

Expected Output:

DEMO_API_KEY=supersecret
DEMO_ENV=production

📎 Notes & Recommendations

  • Security: This guide uses Vault in dev mode and HTTP—not recommended for production. Use TLS and HA mode in production environments.
  • Policy Design: Keep policies granular and service-account specific to follow the principle of least privilege.
  • Refresh Behavior: ExternalSecrets will update Kubernetes secrets every hour (as per refreshInterval), ensuring changes in Vault propagate automatically.


🧙 AI Wizard - Instant Page Insights

Click the button below to analyze this page.
Get an AI-generated summary and key insights in seconds.
Powered by Perplexity AI!