Every Kubernetes platform eventually has the secrets conversation. Native Secret objects are only base64-encoded, they end up in etcd, and committing them to Git is a non-starter. The ecosystem has converged on three main patterns: External Secrets Operator (ESO), Vault Agent injection and SOPS-encrypted secrets in Git. Each solves a different problem well.
Pattern 1: External Secrets Operator
ESO syncs secrets from an external store — AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, Vault and others — into native Kubernetes Secrets. You commit an ExternalSecret manifest, never the value:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: payments-db
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: payments-db
data:
- secretKey: password
remoteRef:
key: prod/payments/db
property: password
Strengths: GitOps-friendly, works with any app that reads env vars or files, uses your cloud’s managed secret store and IAM (IRSA, Workload Identity).
Trade-offs: secrets still land in etcd as Kubernetes Secrets, so enable etcd encryption at rest and tight RBAC. Rotation is eventually consistent based on the refresh interval.
Pattern 2: Vault Agent injection
With the Vault Agent Injector (or the Vault CSI provider), a sidecar authenticates using the pod’s service account and renders secrets to a shared in-memory volume. Secrets never become Kubernetes objects.
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "payments"
vault.hashicorp.com/agent-inject-secret-db: "database/creds/payments"
Strengths: dynamic, short-lived credentials (database users created on demand and revoked automatically), detailed audit logs, no secrets in etcd.
Trade-offs: you must run Vault highly available — or pay for a managed offering — and every pod carries a sidecar. Vault becomes a tier-zero dependency for every deployment.
Pattern 3: SOPS in Git
SOPS encrypts values inside YAML files using KMS, age or PGP keys. Flux decrypts natively; ArgoCD can via plugins such as helm-secrets or KSOPS.
sops --encrypt --kms arn:aws:kms:eu-west-1:111122223333:key/abcd secret.yaml > secret.enc.yaml
Strengths: no extra runtime infrastructure, secrets versioned and reviewed alongside code, great for small teams and bootstrap secrets.
Trade-offs: rotation means a commit, encrypted values live forever in Git history, and access control is coarse — anyone with the key decrypts everything encrypted with it.
How to choose
- Already on a cloud with a managed secret store, many teams, GitOps: External Secrets Operator. It is the pragmatic default for most platforms.
- Strict compliance (PCI DSS, SOC 2) or a need for dynamic database credentials: Vault, via Agent or CSI.
- Small team, few secrets, or cluster bootstrap: SOPS — often used to bootstrap the credentials ESO or Vault needs.
Mixing patterns is normal. A common setup is SOPS for the bootstrap layer, ESO for application secrets, and Vault dynamic secrets only for the databases that handle regulated data.
Non-negotiables regardless of pattern
- Enable encryption at rest for etcd (KMS provider on managed clusters).
- Restrict
get/liston Secrets via RBAC —listreturns values too. - Use workload identity instead of long-lived cloud keys.
- Rotate, and test rotation: applications must reload credentials without a redeploy.
- Scan repositories for leaked secrets with gitleaks or similar in CI.
The takeaway
There is no single best secrets tool — only the right fit for your compliance needs, team size and operational appetite. Pick the simplest pattern that meets your audit requirements, make it the golden path, and make the insecure option harder than the secure one.


