Reference¶
Scope
Look-up facts for External Secrets Operator (ESO): release and support matrix, API versions, CRD field values, provider stability, generators, controller flags, Helm values, metrics, ports, template functions, security advisories, and a hardening checklist. For why things work this way, see Explanation. For task recipes, see How-to Guides.
Release and Support Matrix¶
ESO supports only the current minor version; the previous minor is end-of-life the day a new minor ships. Since v2.0 a new minor has shipped roughly every three weeks, although the release docs describe releases as "as-needed". The Helm chart and the operator have separate release lifecycles, but chart version and appVersion currently move together (chart 2.11.0 / app v2.11.0).
| ESO version | Tested Kubernetes | Release date | End of life | Notable change |
|---|---|---|---|---|
| 2.11 | 1.36 | 2026-09-18 | Release of 2.12 | Barbican application credentials, Infisical duplicate-key option, global imageRegistry in chart |
| 2.10 | 1.36 | 2026-08-28 | 2026-09-18 | Conjur PushSecret, OpenBao Kubernetes auth, GitHub Dependabot secrets |
| 2.9 | 1.36 | 2026-08-07 | 2026-08-28 | 1Password environments |
| 2.8 | 1.35-1.36 | 2026-07-18 | 2026-08-07 | CreateOrMerge creation policy, AWS Certificate Manager provider, GitLab deploy-token generator |
| 2.7 | 1.35 | 2026-06-26 | 2026-07-18 | Dedicated OpenBao provider, BeyondTrust Workload Credentials, syncWindows |
| 2.3 | 1.34-1.35 | 2026-04-10 | 2026-04-24 | First release line after the CVE-2026-34984 fix |
| 2.0 | 1.34-1.35 | 2026-02-06 | 2026-03-06 | Removed unmaintained Alibaba and Device42 providers |
| 1.2 | 1.34 | 2025-12-19 | 2026-01-23 | Fix for CVE-2026-22822 (getSecretKey removed) |
| 1.0 | 1.34 | 2025-11-07 | 2025-11-21 | GA release, Go multi-module split (/apis, /runtime, /providers/v1/*, /generators/v1/*) |
| 0.20 | 1.34 | 2025-09-22 | 2025-11-07 | First release after the 2025 release pause |
| 0.17 | 1.33 | 2025-05-14 | 2025-07-17 | Stopped serving v1beta1 |
| 0.16 | 1.32 | 2025-04-14 | 2025-05-14 | Promoted v1 APIs, removed v1alpha1 and conversion webhooks, removed v1 template engine |
Intermediate minors (2.1, 2.2, 2.4-2.6, 1.1, 1.3, 0.18, 0.19) are listed on the upstream Stability and Support page. Upstream recommends upgrading one minor version at a time and reading each release note.
API Versions¶
| Kind | API group/version | Scope | Status |
|---|---|---|---|
ExternalSecret |
external-secrets.io/v1 |
Namespace | Stable (GA) |
ClusterExternalSecret |
external-secrets.io/v1 |
Cluster | Stable (GA) |
SecretStore |
external-secrets.io/v1 |
Namespace | Stable (GA) |
ClusterSecretStore |
external-secrets.io/v1 |
Cluster | Stable (GA) |
PushSecret |
external-secrets.io/v1alpha1 |
Namespace | Alpha API |
ClusterPushSecret |
external-secrets.io/v1alpha1 |
Cluster | Alpha API |
Generators (Password, ECRAuthorizationToken, ...) |
generators.external-secrets.io/v1alpha1 |
Namespace | Alpha API |
ClusterGenerator |
generators.external-secrets.io/v1alpha1 |
Cluster | Alpha API |
GeneratorState |
generators.external-secrets.io/v1alpha1 |
Namespace | Alpha API (tracks generated values for cleanup) |
v1beta1 is gone
external-secrets.io/v1beta1 stopped being served in v0.17.0 (2025-05-14). Manifests must use external-secrets.io/v1 (only the version string changes). v1alpha1 versions of ExternalSecret/SecretStore were removed in v0.16.0.
The Helm value crds.unsafeServeV1Beta1 (default false) re-enables v1beta1 serving for backward compatibility; the chart comment says it would be removed on 2026-05-01, but it is still present in chart 2.11.0.
ExternalSecret Fields¶
| Field | Default | Purpose |
|---|---|---|
spec.secretStoreRef |
kind: SecretStore |
Default store (SecretStore or ClusterSecretStore) |
spec.refreshPolicy |
Periodic |
Periodic, OnChange, or CreatedOnce |
spec.refreshInterval |
1h0m0s |
Re-sync period; 0s fetches and creates once |
spec.syncWindows |
none | Cron-based allow/deny windows (UTC) for periodic refresh (since 2.7) |
spec.target.name |
metadata.name |
Target Secret name (immutable) |
spec.target.creationPolicy |
Owner |
Ownership of the target Secret (see below) |
spec.target.deletionPolicy |
Retain |
What happens when provider data disappears (see below) |
spec.target.immutable |
false |
Create the Secret as immutable |
spec.target.template |
none | Secret type, metadata, and Go-template data/templateFrom |
spec.data[] |
none | Per-key mapping secretKey <- remoteRef (key, property, version, decodingStrategy) |
spec.data[].sourceRef |
none | Per-entry storeRef or generatorRef override |
spec.dataFrom[] |
none | Bulk: extract, find (by name.regexp or tags), or sourceRef.generatorRef; supports rewrite |
Manual refresh: kubectl annotate es <name> force-sync=$(date +%s) --overwrite.
Creation, Deletion and Refresh Policies¶
| Policy | Value | Behavior |
|---|---|---|
creationPolicy |
Owner (default) |
Creates the Secret and sets ownerReferences; deleting the ExternalSecret deletes the Secret |
creationPolicy |
Orphan |
Creates/updates the Secret without ownerReferences; it survives ExternalSecret deletion |
creationPolicy |
Merge |
Does not create; merges keys into an existing Secret (expects it to exist) |
creationPolicy |
CreateOrMerge |
Creates the Secret if missing, otherwise merges (since 2.8) |
creationPolicy |
None |
Does not create or update a Secret |
deletionPolicy |
Retain (default) |
Keeps the Secret when all provider keys are deleted |
deletionPolicy |
Delete |
Deletes the Secret when all provider keys are deleted |
deletionPolicy |
Merge |
Removes vanished keys but keeps the Secret |
refreshPolicy |
Periodic (default) |
Syncs every refreshInterval and on spec change |
refreshPolicy |
OnChange |
Syncs only when ExternalSecret metadata or spec changes |
refreshPolicy |
CreatedOnce |
Syncs once per ExternalSecret; combine with target.immutable: true for write-once credentials |
Status Conditions¶
| Condition type | Reason | Meaning |
|---|---|---|
Ready |
SecretSynced |
Last sync succeeded |
Ready |
SecretSyncedError |
Fetch, template or write failed |
Ready |
SecretMissing |
Target Secret is missing |
Ready |
SecretOwnedByOther |
Target Secret is owned by another ExternalSecret |
Ready |
SecretImmutable |
Target Secret is immutable and cannot be updated |
Deleted |
SecretDeleted |
Target Secret was deleted per deletionPolicy |
PushSecret Fields¶
| Field | Default | Values |
|---|---|---|
spec.secretStoreRefs[] |
kind: SecretStore |
One or more stores to write to (by name or labelSelector) |
spec.selector |
none | Exactly one of secret.name or generatorRef |
spec.refreshInterval |
1h0m0s |
Re-push period |
spec.updatePolicy |
Replace |
Replace or IfNotExists |
spec.deletionPolicy |
None |
None (keep in provider) or Delete (remove from provider when PushSecret is deleted) |
spec.data[].match |
none | secretKey -> remoteRef.remoteKey / property |
spec.data[].conversionStrategy |
None |
None or ReverseUnicode |
spec.template |
none | Same template engine as ExternalSecret |
ClusterSecretStore Conditions¶
A ClusterSecretStore without spec.conditions can be referenced from every namespace. Each condition entry can match on:
| Field | Type | Example |
|---|---|---|
namespaces |
list of names | ["team-a", "team-b"] |
namespaceSelector |
label selector | matchLabels: {app: frontend} |
namespaceRegexes |
list of regular expressions | ["^team-.*$"] |
Annotation external-secrets.io/ignore-maintenance-checks: "true" on a store silences controller warning events for providers without an explicit maintainer (the admission warning cannot be disabled).
Provider Stability¶
Upstream lists roughly 40 providers. Only these carry stable or beta status; everything else is alpha and community-maintained.
| Provider | Stability | Maintainer | PushSecret |
|---|---|---|---|
| AWS Secrets Manager | stable | external-secrets | Yes |
| AWS Parameter Store | stable | external-secrets | Yes |
| Azure Key Vault | stable | external-secrets | Yes |
| GCP Secret Manager | stable | external-secrets | Yes |
| HashiCorp Vault | stable | external-secrets | Yes |
| Akeyless | stable | external-secrets | Yes |
| CyberArk Secrets Manager (Conjur) | stable | CyberArk contributors | Since 2.10 (feature table not yet updated) |
| IBM Cloud Secrets Manager | stable | @IdanAdar | No |
| Oracle Vault | stable | @anders-swanson | Yes |
| Previder | stable | @previder | No |
| Kubernetes (remote cluster) | beta | external-secrets | Yes |
| SecretServer (Delinea Secret Server) | beta | @gmurugezan | Yes |
Alpha providers (2026-09): AWS Certificate Manager, Barbican, BeyondTrust, BeyondTrust Workload Credentials, Bitwarden Secrets Manager, Chef, Cloud.ru, Delinea, Devolutions Server, Doppler, Fortanix, Generic Webhook, GitHub Actions/Dependabot secrets, GitLab Variables, Infisical, Keeper Security, Nebius MysteryBox, Ngrok, Onboardbase, OpenBao, OVHcloud, Passbolt, Password Depot, Pulumi ESC, Scaleway, Senhasegura DSM, Volcengine, Yandex Certificate Manager, Yandex Lockbox, 1Password (Connect), 1Password SDK.
Removed: Alibaba Cloud and Device42 (v2.0.0, unmaintained).
Generators¶
All generators live in generators.external-secrets.io/v1alpha1 and are referenced from dataFrom[].sourceRef.generatorRef (or PushSecret.spec.selector.generatorRef). Every invocation produces new values.
| Generator kind | Produces |
|---|---|
ACRAccessToken |
Azure Container Registry token |
ECRAuthorizationToken |
AWS ECR registry credentials |
STSSessionToken |
AWS STS session credentials |
GCRAccessToken |
Google Container/Artifact Registry token |
QuayAccessToken |
Short-lived Quay token via a federated robot account |
CloudsmithAccessToken |
Cloudsmith registry token |
GithubAccessToken |
GitHub App installation token |
GitlabDeployToken |
GitLab deploy token (since 2.8) |
Grafana |
Grafana service-account token |
VaultDynamicSecret |
Any Vault dynamic secret (database, AWS, PKI, ...) |
BeyondtrustWorkloadCredentialsDynamicSecret |
BeyondTrust dynamic credential |
Password |
Random password (length, digits, symbols) |
SSHKey |
SSH key pair |
UUID |
Random UUID |
MFA |
TOTP code from a seed secret |
Webhook |
Result of an arbitrary HTTP call |
Fake |
Static values for testing |
ClusterGenerator |
Cluster-scoped wrapper around any generator spec |
Controller Flags¶
| Flag | Default | Notes |
|---|---|---|
--concurrent |
1 |
Concurrent reconciles (Helm: concurrent) |
--controller-class |
default |
Match spec.controller on stores (Helm: controllerClass) |
--namespace |
all | Watch one namespace only (Helm: scopedNamespace) |
--enable-leader-election |
false |
Required when replicaCount > 1 (Helm: leaderElect) |
--enable-flood-gate |
true |
Skip ExternalSecrets whose store is unhealthy |
--enable-managed-secrets-caching |
true |
Cache only ESO-managed Secrets |
--enable-secrets-caching |
false |
Cache all cluster Secrets (memory cost) |
--enable-vault-token-cache |
false |
Reuse Vault tokens across requests |
--store-requeue-interval |
5m0s |
Store health re-check period |
--client-qps / --client-burst |
50 / 100 |
Kubernetes API client limits |
--enable-*-reconciler |
true |
Per-CRD switches: cluster-external-secret, cluster-store, secret-store, push-secret, cluster-push-secret |
--loglevel |
info |
debug logs Secret deletions and key diffs (never values) |
Helm Values¶
| Value | Default | Purpose |
|---|---|---|
installCRDs |
true |
Chart installs and upgrades CRDs |
crds.conversion.enabled |
false |
Conversion webhook (unused since v1alpha1 removal) |
crds.unsafeServeV1Beta1 |
false |
Temporarily serve deprecated v1beta1 |
crds.create* |
true |
Per-CRD install switches (must match process*) |
replicaCount |
1 |
Core controller replicas |
leaderElect |
false |
Leader election for the controller |
concurrent |
1 |
Concurrent reconciles |
processClusterExternalSecret, processClusterStore, processSecretStore, processPushSecret, processClusterPushSecret, processClusterGenerator |
true |
Reconciler switches |
scopedNamespace / scopedRBAC |
"" / false |
Namespace-scoped install (disables cluster kinds) |
genericTargets.enabled |
false |
Allow writing ConfigMaps/custom resources instead of Secrets |
webhook.create |
true |
Admission/conversion webhook Deployment |
certController.create |
true |
Cert controller Deployment |
serviceMonitor.enabled |
false |
Prometheus Operator ServiceMonitor |
grafanaDashboard.enabled |
false |
Bundled Grafana dashboard |
bitwarden-sdk-server.enabled |
false |
Sidecar service required by the Bitwarden provider |
Chart repository: https://charts.external-secrets.io (chart external-secrets/external-secrets). CRDs exceed the 256 KB client-side apply limit, so manual CRD installs need kubectl apply --server-side.
Ports and Network Flows¶
| Component | Inbound | Outbound |
|---|---|---|
| Core controller | 8080 metrics (from monitoring), 8082 liveness |
kube-apiserver, secret provider endpoints |
| Webhook | 10250 from kube-apiserver, 8080 metrics, 8081 health |
kube-apiserver |
| Cert controller | 8080 metrics, 8081 health |
kube-apiserver |
Metrics¶
| Metric | Type | Meaning |
|---|---|---|
externalsecret_sync_calls_total |
Counter | ExternalSecret sync calls |
externalsecret_sync_calls_error |
Counter | ExternalSecret sync errors |
externalsecret_status_condition |
Gauge | Condition per ExternalSecret |
externalsecret_reconcile_duration |
Gauge | Reconcile duration |
externalsecret_provider_api_calls_count |
Counter | Provider API calls (provider, call, status labels) |
clusterexternalsecret_status_condition |
Gauge | Condition per ClusterExternalSecret |
secretstore_status_condition / clustersecretstore_status_condition |
Gauge | Store health |
secretstore_reconcile_duration / clustersecretstore_reconcile_duration |
Gauge | Store reconcile duration |
Plus the standard controller-runtime metrics (workqueue depth, reconcile latency and errors, webhook latency).
Template Functions¶
Template engine v2 (the only engine since v0.16) exposes Go templates, 200+ Sprig functions (minus env and expandenv), and these ESO helpers:
| Function | Purpose |
|---|---|
pkcs12key, pkcs12keyPass, pkcs12cert, pkcs12certPass |
Extract keys/certs from PKCS#12 as PEM |
pemToPkcs12, pemToPkcs12Pass, fullPemToPkcs12, fullPemToPkcs12Pass, pemTruststoreToPKCS12, pemTruststoreToPKCS12Pass |
Build PKCS#12 archives |
filterPEM, filterCertChain, certSANs |
Select PEM blocks, leaf/intermediate/root certs, SANs |
jwkPublicKeyPem, jwkPrivateKeyPem |
Convert JWK to PEM |
rsaDecrypt |
Decrypt RSA ciphertext (None or RSA-OAEP, SHA1/SHA256) |
toYaml, fromYaml, hexdec |
Encoding helpers |
Renamed from the removed v1 engine: base64encode -> b64enc, base64decode -> b64dec, fromJSON -> fromJson, toJSON -> toJson. Removed: toBytes, pemPrivateKey, pemCertificate, getSecretKey (security fix in 1.2.0). Since the CVE-2026-34984 fix, getHostByName is also unavailable in user templates.
Security Advisories¶
| ID | Published | Affected | Fixed | Summary |
|---|---|---|---|---|
| CVE-2024-45041 (GHSA-qwgc-rr35-h4x9) | 2024-09-09 | < 0.10.2 | 0.10.2 | Cert-controller ClusterRole could read all Secrets and patch webhook configs (CVSS 3.1: 8.3) |
| CVE-2025-55196 (GHSA-fcxq-v2r3-cc8h) | 2025-08-13 | 0.15.0 - 0.19.1 | 0.19.2 | PushSecret controller listed Secrets/stores without a namespace selector (CVSS 7.1) |
| CVE-2026-22822 (GHSA-77v3-r3jw-j2v2) | 2026-01-20 | 0.20.2 - < 1.2.0 | 1.2.0 | getSecretKey template function read Secrets cross-namespace (GHSA: 9.3 critical, NVD: 8.8 high) |
| CVE-2026-34984 (GHSA-r2pg-r6h7-crf3) | 2026-04-11 | 2.0.0 - 2.2.0 and earlier | fix merged 2026-03-31; first 2.x minor after is 2.3.0 | getHostByName in templates allowed DNS-based exfiltration (CVSS 7.1) |
Report vulnerabilities to [email protected], not GitHub issues.
Hardening Checklist¶
- Run the current minor (only it receives fixes) and upgrade one minor at a time.
- Verify images with Cosign keyless signatures (
ghcr.io/external-secrets/external-secrets); SBOM and provenance ship with each release. - Use workload identity (IRSA, EKS Pod Identity, GKE/Azure Workload Identity, Vault Kubernetes auth) instead of static keys.
- Restrict
SecretStore,PushSecretandClusterPushSecretcreation to platform teams via RBAC. - Add
conditionsto everyClusterSecretStore. - Disable unused kinds (
process*: false,crds.create*: false) or install namespace-scoped (scopedRBAC,scopedNamespace). - Set
rbac.serviceAccountTokenCreate: falseand grant token creation per ServiceAccount. - Apply NetworkPolicies per the port table; use private provider endpoints.
- Restrict webhook TLS ciphers (
webhook.extraArgs.tls-ciphers); webhook minimum is TLS 1.2 by default. - Enable Kubernetes Secret encryption at rest (ESO writes plain Kubernetes Secrets).
- Enforce policy with Kyverno or OPA Gatekeeper (allowed providers, no cross-namespace refs, template restrictions).
- Alert on
externalsecret_sync_calls_errorandReady=Falseconditions.
Benchmarks¶
Unsourced performance data
Upstream publishes no controlled benchmarks. The figures below were estimated from vendor documentation, community reports, and engineering judgment; hardware, versions and methodology were not recorded. Treat them as rough guidance and run your own load test. See Explanation for what actually drives load.
| Provider | Secret fetch time (estimate) | Default refresh | Notes |
|---|---|---|---|
| AWS Secrets Manager | 50-200 ms | 1h | Account-level API quotas apply |
| HashiCorp Vault | 10-50 ms | 1h | Network-dependent |
| Azure Key Vault | 50-200 ms | 1h | Regional latency |
| GCP Secret Manager | 30-100 ms | 1h | Fast in-region |
| ExternalSecrets | Controller CPU (estimate) | Controller memory (estimate) |
|---|---|---|
| 50 | 50-100m | 128Mi |
| 200 | 100-300m | 256Mi |
| 1,000 | 500m-1 | 512Mi-1Gi |
| Dimension | Limit (estimate) | Notes |
|---|---|---|
| ExternalSecrets per cluster | 10,000+ | Controller memory and provider quotas are the bottleneck |
| Stores per cluster | 50+ | Each store is health-checked every --store-requeue-interval |
| Refresh rate | Provider API limits | AWS Secrets Manager GetSecretValue quota is documented at 10,000 requests/s per account and Region; Vault has no default limit but operators can set rate-limit quotas |
Sources¶
- Stability and Support (source:
docs/introduction/stability-support.md, retrieved 2026-09-25) - API specification and ExternalSecret
- Controller options and Metrics
- Advanced Templating v2
- Security Best Practices
- Helm chart values
- Releases (v0.16.0, v0.17.0, v1.0.0, v2.0.0, v2.7.0-v2.11.0 notes)
- Advisories: GHSA-qwgc-rr35-h4x9, GHSA-fcxq-v2r3-cc8h, GHSA-77v3-r3jw-j2v2, GHSA-r2pg-r6h7-crf3