External Secrets

External Secrets Operator and Cloud Secret Stores

The External Secrets Operator 82,285 (github.com/external-secrets/external-secrets (https://github.com/external-secrets/external-secrets 6,885 ), Apache-2.0, v2.11.0) syncs values from a secret manager (AWS Secrets Manager 24 , Google Secret Manager, Azure 6 Key Vault 4,548 , HashiCorp Vault and many more) into Secrets on a schedule. A SecretStore says how to reach the backend, an ExternalSecret what to fetch. Here a vault namespace, read through ESO's Kubernetes 5,150 provider, stands in:

ESO syncing a Secret from a stand-in secret managerShell
helm repo add external-secrets https://charts.external-secrets.io >/dev/null
helm install eso external-secrets/external-secrets --version 2.11.0 -n external-secrets \
  --create-namespace --wait >/dev/null
kubectl create namespace vault >/dev/null
kubectl -n vault create secret generic booknest-smtp --from-literal=password=first >/dev/null
kubectl create serviceaccount eso-reader >/dev/null
kubectl -n vault create role read-secrets --verb=get,list,watch --resource=secrets >/dev/null
kubectl -n vault create rolebinding eso-reader --role=read-secrets \
  --serviceaccount=booknest:eso-reader >/dev/null
kubectl apply -f - <<'EOF'
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata: { name: vault }
spec:
  provider:
    kubernetes:
      remoteNamespace: vault
      server: { caProvider: { type: ConfigMap, name: kube-root-ca.crt, key: ca.crt } }
      auth: { serviceAccount: { name: eso-reader } }
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: smtp }
spec:
  refreshInterval: 10s
  secretStoreRef: { kind: SecretStore, name: vault }
  target: { name: smtp-credentials }
  data: [{ secretKey: password, remoteRef: { key: booknest-smtp, property: password } }]
EOF
kubectl wait --for=condition=Ready externalsecret/smtp >/dev/null
kubectl get secret smtp-credentials -o jsonpath='{.data.password}' | base64 -d; echo
kubectl -n vault create secret generic booknest-smtp --from-literal=password=rotated \
  --dry-run=client -o yaml | kubectl replace -f - >/dev/null && sleep 15
kubectl get secret smtp-credentials -o jsonpath='{.data.password}' | base64 -d; echo
Output
secretstore.external-secrets.io/vault created
externalsecret.external-secrets.io/smtp created
first
rotated

The rotated value arrived within 15 seconds, with no redeploy. On AWS 24 , the SecretStore would say provider: aws and use an IAM role for its ServiceAccount; the cost is one more controller to run and trust.