External Secrets Operator (ESO)¶
Summary
External Secrets Operator is a CNCF Sandbox Kubernetes operator that syncs secrets from external stores (HashiCorp Vault, AWS Secrets Manager and Parameter Store, Azure Key Vault, GCP Secret Manager, and about 40 other providers) into native Kubernetes Secrets, and can push Secrets back out with PushSecret. Its core APIs have been GA at external-secrets.io/v1 since 2025, v1.0 shipped in November 2025, and the 2.x line releases a new minor about every three weeks. The latest version is 2.11.0 (2026-09-18). Only the newest minor is supported.
Overview¶
ESO is the de facto Kubernetes bridge for external secret stores. It watches ExternalSecret resources, fetches values through a SecretStore or ClusterSecretStore, renders optional Go templates, and creates or updates ordinary Kubernetes Secrets. Applications need no SDK, sidecar, or CSI driver. PushSecret reverses the flow, and generators mint values such as ECR tokens, Vault dynamic credentials, or random passwords. The trade-off is that secret values end up in etcd, and updates arrive by polling.
Key Facts¶
| Attribute | Detail |
|---|---|
| Website | external-secrets.io |
| Repository | external-secrets/external-secrets |
| Stars | ~5k+ |
| Latest Version | 2.11.0 (2026-09-18), Helm chart 2.11.0 |
| Release cadence | New minor about every 3 weeks since 2.0; only the latest minor is supported |
| Tested Kubernetes | 1.36 (for 2.11) |
| Stable APIs | external-secrets.io/v1: ExternalSecret, ClusterExternalSecret, SecretStore, ClusterSecretStore |
| Alpha APIs | external-secrets.io/v1alpha1: PushSecret, ClusterPushSecret; generators.external-secrets.io/v1alpha1: generators |
| Removed APIs | v1alpha1 stores and ExternalSecrets (v0.16.0), v1beta1 no longer served (v0.17.0, 2025-05-14) |
| Language | Go (multi-module since v1.0) |
| License | Apache-2.0 |
| Governance | CNCF Sandbox (accepted 2022-07-26); five maintainers from different organizations |
| Install | Helm chart external-secrets/external-secrets from https://charts.external-secrets.io |
Evaluation¶
| Pros | Cons |
|---|---|
About 40 providers behind one API; ten are stable |
Poll-based sync with lag (default refreshInterval 1h) |
| Native Kubernetes Secrets, so no application changes | Secret values stored in etcd; needs encryption at rest |
| PushSecret for reverse sync (Vault, AWS, GCP, Azure, and more) | Most providers are alpha and community-maintained |
| Generators for short-lived tokens and passwords | PushSecret and generators are still v1alpha1 APIs |
| Go templating with Sprig and PKI helpers | Only the latest minor is supported, so you must upgrade every few weeks |
| ClusterSecretStore with namespace conditions for multi-tenancy | Controller holds cluster-wide Secret access; four notable CVEs in 2024-2026 |
| Apache-2.0, CNCF, broad adoption (Red Hat ships a supported build) | Maintainer shortage paused releases in mid-2025; bus factor still modest |
Fits well when workloads run on Kubernetes, a central store already exists (a cloud secret manager or Vault), and GitOps should carry only references, never secret values. Fits poorly when you need secrets never to touch etcd (use the Secrets Store CSI Driver or Vault Agent injection), you have no external store (SOPS or Sealed Secrets are simpler), or you need sub-second propagation.
Architecture¶
The core controller reconciles ESO resources, calls provider APIs, and writes Kubernetes Secrets; a webhook and a cert controller support admission validation. Details are in Explanation.
flowchart LR
subgraph K8s["Kubernetes cluster"]
ES["ExternalSecret"]
SS["SecretStore / ClusterSecretStore"]
PS["PushSecret"]
CTRL["ESO core controller"]
WH["ESO webhook + cert controller"]
SEC["Kubernetes Secret"]
POD["Pods (env, envFrom, volume)"]
end
subgraph External["External providers"]
VLT["HashiCorp Vault / OpenBao"]
AWS["AWS Secrets Manager / Parameter Store"]
GCP["GCP Secret Manager"]
AZ["Azure Key Vault"]
end
ES -->|"what to fetch"| CTRL
SS -->|"how to authenticate"| CTRL
WH -.->|"validates"| SS
CTRL -->|"fetch"| External
CTRL -->|"create / update"| SEC
SEC --> POD
PS -->|"push"| CTRL
CTRL -->|"write back"| VLT
style CTRL fill:#1565c0,color:#fff
Core Resources¶
| Resource | API version | Scope | Purpose |
|---|---|---|---|
| SecretStore | v1 |
Namespace | Provider connection and auth config |
| ClusterSecretStore | v1 |
Cluster | Shared provider config, restrictable by namespace conditions |
| ExternalSecret | v1 |
Namespace | Defines which secrets to sync and how to shape them |
| ClusterExternalSecret | v1 |
Cluster | Stamps an ExternalSecret into selected namespaces |
| PushSecret | v1alpha1 |
Namespace | Pushes a Kubernetes Secret or generator output to a provider |
| ClusterPushSecret | v1alpha1 |
Cluster | Stamps a PushSecret into selected namespaces |
Generators (Password, ECRAuthorizationToken, VaultDynamicSecret, ...) |
generators.external-secrets.io/v1alpha1 |
Namespace or cluster (ClusterGenerator) |
Produce values instead of fetching them |
Recent Developments¶
- 2.x cadence (2026): 2.0 (2026-02-06) removed the unmaintained Alibaba and Device42 providers; later minors added a dedicated OpenBao provider and
syncWindows(2.7),CreateOrMergeand an AWS Certificate Manager provider (2.8), Conjur PushSecret and GitHub Dependabot secrets (2.10), and Barbican application credentials (2.11). - v1.0 GA (2025-11-07): stable APIs and a Go multi-module layout (
/apis,/runtime, per-provider and per-generator modules). - Release pause and recovery (2025): maintainers paused releases on 2025-07-30 over burnout, and the CNCF TOC opened a health review. New maintainers joined and releases resumed with v0.20.0 on 2025-09-22. See Explanation.
- API migration (2025): v0.16.0 promoted
v1, and v0.17.0 stopped servingv1beta1. The upgrade path is in How-to Guides. - Security: CVE-2026-22822 (cross-namespace
getSecretKey, fixed in 1.2.0) and CVE-2026-34984 (DNS exfiltration viagetHostByName, fixed after 2.2.0) both came from template functions. See Reference.
Alternatives¶
| Alternative | How it differs |
|---|---|
| SOPS | Encrypts secrets in Git and decrypts at deploy; needs no external store |
| Sealed Secrets | Controller-held key pair decrypts SealedSecret into a Secret; no external store |
| Vault Secrets Operator | HashiCorp's Vault-specific operator with similar CRD-to-Secret sync |
| Secrets Store CSI Driver | Mounts secrets as files directly from the provider; can avoid etcd entirely |
| Vault Agent injector | Sidecar renders secrets into the pod; Vault only |
Topic Map¶
- How-to Guides: install, upgrade and
v1beta1migration, provider setup (AWS, Vault, GCP), templates, generators, PushSecret, hardening, troubleshooting - Reference: release and support matrix, API versions, field and policy values, provider stability, generators, flags, Helm values, metrics, ports, CVEs, hardening checklist
- Explanation: components, reconciliation loop, provider interface, template engine, history and governance, scaling, threat model
Related Topics¶
- Domain: Secrets overview and Secrets Management Comparison: Vault vs ESO vs SOPS
- HashiCorp Vault, the most common ESO backend and a source of dynamic secrets via the
VaultDynamicSecretgenerator - SOPS, which complements ESO for encrypting bootstrap secrets in Git
- Kubernetes, for the Secret, RBAC, and admission primitives ESO builds on
- Argo CD and Flux, GitOps tools that deploy
ExternalSecretmanifests - Pulumi, whose Pulumi ESC is an ESO provider
Sources¶
- ESO documentation
- Stability and Support (versions, EOL, provider stability)
- GitHub repository and releases
- v0.17.0 release (v1beta1 no longer served) and v2.0.0 release
- Health of External Secrets project, issue #5084
- CNCF TOC health issue #1819
- CNCF project page and CNCF Landscape entry
- External Secrets Operator is now GA with v1.0.0 (Hacker News)
- Introducing the external secrets operator for OpenShift (Red Hat Developer)
- HashiCorp Vault provider
Questions¶
Answered¶
-
Q: Can ESO push secrets to providers? Yes. The PushSecret CRD (
v1alpha1) reverses the normal flow and pushes data from Kubernetes Secrets or generators to providers such as AWS Secrets Manager, HashiCorp Vault, or GCP Secret Manager.updatePolicy(ReplaceorIfNotExists) anddeletionPolicy(NoneorDelete) control provider-side behavior. Only providers that implement the write path support it. -
Q: How does ESO differ from Sealed Secrets? Sealed Secrets encrypts secrets client-side and decrypts them in-cluster using a controller-managed key pair. ESO does not encrypt secrets itself. It synchronizes secrets from external management systems (Vault, AWS SM, and more) into native Kubernetes Secrets, so it delegates trust to the external provider rather than managing its own encryption.
-
Q: What happens if the external provider is unavailable? ESO leaves the last successfully synced Kubernetes Secret in place. The ExternalSecret's
Readycondition switches toSecretSyncedError, and with the flood gate enabled (the default), ExternalSecrets whose store is unhealthy are skipped until the store's health check passes. Once the provider recovers, the next reconcile updates the Secret.retrySettings(maxRetries,retryInterval) on the store tunes HTTP retries to the provider. -
Q: Can ESO manage secrets across multiple clusters? Yes. Each cluster runs its own ESO; point every cluster's stores at the same provider, or use the Kubernetes provider (
beta) to read Secrets from a remote cluster's API server. PushSecret with a shared provider can publish a Secret from one cluster for others to consume. ClusterExternalSecret only distributes across namespaces within one cluster. -
Q: How does the template engine work? ESO renders Go templates in
spec.target.templatewith engine v2, the only engine since v0.16. Templates can use Sprig functions (b64enc,b64dec,fromJson,toJson,upper, and 200+ more, minusenvandexpandenv) and ESO helpers for PKCS#12, PEM and JWK. The old v1 names such asbase64encodeno longer exist. The template context holds all fetched values. -
Q: What is the difference between SecretStore and ClusterSecretStore? SecretStore is namespaced and can only be referenced by ExternalSecrets in the same namespace. ClusterSecretStore is cluster-scoped and can be referenced from any namespace unless
conditions(namespaces,namespaceSelector,namespaceRegexes) restrict it. -
Q: Is the project still maintained after the 2025 pause? Yes. Releases resumed on 2025-09-22, v1.0 shipped on 2025-11-07, and twelve 2.x minors followed through 2026-09-18.
-
Q: How does ESO handle secret rotation notifications to workloads? ESO updates the Kubernetes Secret when the external value changes. Environment variables in running pods never change, and volume-mounted Secrets update only after the kubelet sync delay, so the application must re-read the file. Use a restart controller such as Stakater Reloader or
kubectl rollout restart. See How-to Guides. -
Q: Will out-of-tree (gRPC) providers land? Not on any current plan. PR #3634 (a gRPC-endpoint provider proposal) was closed unmerged as stale on 2024-12-27, and the follow-up tracking issue #5218 ("Out of Tree Providers", opened 2025-08-28) was closed as not planned (checked 2026-09-28).
Open¶
- Q: What is the performance impact of running many ExternalSecrets? Each ExternalSecret reconciles at its
refreshInterval, so thousands of them can exhaust provider API quotas before ESO itself runs out of resources. Upstream publishes no benchmarks (the estimates in Reference are unsourced). No public controlled test at 1k, 5k, and 10k ExternalSecrets was found (checked 2026-09-28). - Q: Will ESO apply for CNCF incubation, and when? A user asked in issue #4232 (2024-12-20), which is now closed without a stated plan. As of 2026-09-28 the project is still Sandbox, the TOC's tracked item is the health issue #1819 (opened 2025-08-13), and no incubation application issue was found.
- Q: Will PushSecret and generators graduate from
v1alpha1? No timeline is published: the roadmap lists only the four core CRDs as stablev1(checked 2026-09-28).