Secrets for AI Agents: Vault vs Doppler vs Infisical + ESO (2026)
Compare Vault, Doppler, Infisical for AI agent secrets. Wire ExternalSecrets Operator on k3s, rotate OpenAI keys without restarts, and keep CI keyless via OIDC.
TL;DR — In 2026, dynamic short-lived credentials are the standard. Vault for enterprise dynamic secrets, Doppler for fastest team onboarding, Infisical for open-source control. All three integrate with External Secrets Operator on Kubernetes — pick on team fit.
What you'll set up
A k3s cluster running an AI voice agent that pulls its OpenAI key, Postgres password, and LiveKit API secret from a chosen secrets backend via External Secrets Operator. Rotation triggers a rolling restart automatically.
Architecture
flowchart LR
CHOICE{Backend} --> VAULT[Vault]
CHOICE --> DOP[Doppler]
CHOICE --> INF[Infisical]
VAULT --> ESO[ExternalSecretsOperator]
DOP --> ESO
INF --> ESO
ESO --> SEC[K8s Secret]
SEC --> POD[Voice Agent Pod]
ESO -->|refresh 60s| ESO
Step 1 — Install External Secrets Operator
```bash helm repo add external-secrets https://charts.external-secrets.io helm install external-secrets external-secrets/external-secrets \ -n external-secrets --create-namespace ```
ESO is the universal adapter. You write ExternalSecret CRDs; it syncs from any backend into native Secret objects.
Step 2a — Vault path: SecretStore + role
```yaml apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: { name: vault-backend, namespace: voice } spec: provider: vault: server: https://vault.example.com path: secret version: v2 auth: kubernetes: mountPath: kubernetes role: voice-agent ```
Set up the Kubernetes auth method in Vault once: vault write auth/kubernetes/role/voice-agent bound_service_account_names=voice-agent bound_service_account_namespaces=voice policies=voice ttl=1h. Pods authenticate via their projected SA token — no static credentials anywhere.
Step 2b — Doppler path: ClusterSecretStore
```yaml apiVersion: external-secrets.io/v1beta1 kind: ClusterSecretStore metadata: { name: doppler } spec: provider: doppler: auth: { secretRef: { dopplerToken: { name: doppler-token, key: token, namespace: external-secrets }}} project: voice-agent config: prd ```
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
Doppler is the simplest of the three: a single service token, point at project+config, done. Minutes to first sync.
Step 2c — Infisical path
```yaml apiVersion: external-secrets.io/v1beta1 kind: ClusterSecretStore metadata: { name: infisical } spec: provider: infisical: hostAPI: https://app.infisical.com/api auth: universalAuthCredentials: clientId: { name: inf-client, key: id, namespace: external-secrets } clientSecret: { name: inf-client, key: secret, namespace: external-secrets } secretsScope: projectSlug: voice-agent environmentSlug: prod ```
Self-hosted Infisical on the same cluster gives you the cheapest dollar-per-secret cost; SaaS for hands-off.
Step 3 — Define the ExternalSecret
```yaml apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: { name: voice-secrets, namespace: voice } spec: refreshInterval: 60s secretStoreRef: { name: vault-backend, kind: SecretStore } target: name: voice-secrets template: type: Opaque data: OPENAI_API_KEY: "{{ .openai }}" DATABASE_URL: "postgres://voice:{{ .pg }}@db:5432/voice" LIVEKIT_API_SECRET: "{{ .livekit }}" data: - secretKey: openai remoteRef: { key: secret/data/voice, property: openai_key } - secretKey: pg remoteRef: { key: secret/data/voice, property: postgres_password } - secretKey: livekit remoteRef: { key: secret/data/voice, property: livekit_secret } ```
refreshInterval: 60s keeps the K8s Secret close to live. Rotation in Vault propagates within a minute.
Step 4 — Wire the agent to roll on Secret change
Add a checksum annotation to the Deployment via Reloader or a Helm sha256sum template:
```yaml spec: template: metadata: annotations: reloader.stakater.com/auto: "true" ```
Install Stakater Reloader: now any Secret change triggers a rolling restart, and the agent picks up the rotated OpenAI key with zero ops.
Step 5 — Vault dynamic Postgres credentials
```bash vault write database/config/voice-pg \ plugin_name=postgresql-database-plugin \ connection_url="postgresql://{{ user }}:{{ password }}@db:5432/voice" \ allowed_roles=voice-agent username=vault password=...
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
vault write database/roles/voice-agent \ db_name=voice-pg default_ttl=1h max_ttl=24h \ creation_statements="CREATE ROLE "{{ name }}" WITH LOGIN PASSWORD '{{ password }}'; GRANT voice_app TO "{{ name }}";" ```
Now every pod gets a 1h Postgres credential. A leaked credential dies in an hour. ESO refreshes it in time.
Step 6 — Audit and rotation drill
Quarterly: rotate every static key (OpenAI, LiveKit) in the backend, watch ESO sync, watch Reloader roll, verify smoke test passes, archive audit log. Document the runbook.
Step 7 — CI without backend tokens (OIDC)
Vault, Doppler, and Infisical all support GitHub OIDC trust now. CI never holds a backend token; it exchanges its OIDC JWT for a short-lived backend session.
Pitfalls
- HCP Vault Secrets discontinued — if you were on the simpler tier, plan migration to HCP Dedicated, self-managed Vault, or move to Doppler/Infisical. End-of-life is July 2026.
- ESO refresh < TTL of the secret — if your Vault TTL is 5 min and refresh is 60 s, you'll occasionally read an expired secret. Keep TTL >> refreshInterval.
- K8s Secrets are base64, not encrypted at rest by default — enable etcd encryption or use SealedSecrets/Sops for an extra layer.
- Rate limits on backend — Doppler's API has request budgets; with 100+ ExternalSecrets at refreshInterval 30s you can hit them. Aggregate into one ExternalSecret.
- Reloader pod permissions — give it
get,watchon Secrets cluster-wide, not justlist, or it'll silently miss updates.
How CallSphere does this in production
CallSphere uses Infisical (self-hosted) for the primary stack and Vault for HIPAA-segregated tenants. ESO syncs OpenAI keys, LiveKit secrets, Postgres passwords, and 90+ tool API keys into per-namespace Secrets. Reloader rolls 37 agents on rotation. Postgres at 72.62.162.83 uses dynamic Vault-issued credentials with 1-hour TTL. $149/$499/$1499, 14-day trial, 22% affiliate.
FAQ
Q: Vault, Doppler, or Infisical? Vault for enterprise + dynamic credentials at scale. Doppler for fastest team start. Infisical for open-source-first teams that want to self-host.
Q: How do I rotate the OpenAI key without dropping calls? Stakater Reloader does a rolling restart with PDB. Active calls drain on the old pod; new calls hit pods with the new key. Drop-rate ~0.
Q: Sealed Secrets vs ESO? Sealed Secrets is git-native (encrypted in repo). ESO pulls from a live backend. Use ESO if your secrets rotate; Sealed Secrets if they don't.
Q: Can I keep model API keys in cloud KMS instead? Yes — ESO supports AWS Secrets Manager, GCP Secret Manager, Azure Key Vault. Same CRD pattern.
Sources
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.