Join our Newsletter — 33% off our NHI Course
Home› Guides› External Secrets Operator security guide: Lock down stores,…
Guide Secrets Management

External Secrets Operator security guide: Lock down stores, RBAC and sync behaviour

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 28 October 2026 13 min read
On this page

External Secrets Operator (ESO) holds credentials to your secrets manager and can write Kubernetes Secrets in every namespace, so a weak install turns one cluster foothold into access to the whole vault. ESO is the common way to keep secret values out of Git: manifests carry an ExternalSecret reference and the controller fetches the value from AWS Secrets Manager, Vault, Azure Key Vault, Google Secret Manager or another provider. That convenience concentrates privilege in three places: the controller's Kubernetes permissions, the provider credential behind each store, and the people who can create ESO custom resources. This guide covers the ESO threat model, store design for multi-tenant clusters, RBAC and Helm settings, sync behaviour that affects rotation, detection and a phased rollout. It is written for platform and Kubernetes security engineers. For the wider picture read the Kubernetes Secrets Security Guide and the GitOps Security Guide first.

Key takeaways

  • The controller is a cluster-wide secret writer. ESO's own threat model lists cluster-level access to secrets and secret provider access as its top assets, so protect the external-secrets namespace like a control plane component.
  • Store design is your real access boundary. A shared ClusterSecretStore lets any namespace that can reference it read every key behind it; a SecretStore per namespace with its own provider role moves enforcement into the secrets manager.
  • Turn off what you do not use. Cluster stores, cluster external secrets and PushSecret can each be disabled by controller flag and Helm value, which removes whole attack paths.
  • Webhook validation is not a security control. The project says so explicitly; tenant restrictions belong in RBAC, store conditions and an admission policy engine such as Kyverno or OPA Gatekeeper.
  • Sync settings decide rotation and blast radius. refreshPolicy, creationPolicy, deletionPolicy and immutable control whether a rotated value reaches pods, and whether a deleted resource takes the Secret with it.

How ESO works and where the trust sits

ESO runs three components. The core controller reconciles ExternalSecret, SecretStore, ClusterSecretStore, ClusterExternalSecret and PushSecret resources, calls the provider and writes Kubernetes Secrets. The webhook validates and converts ESO resources. The cert controller manages the caBundle on the webhook configuration and CRDs. The resulting Kubernetes Secret is still only base64 encoded in etcd, so ESO does not remove the need for encryption at rest and tight get/list on Secrets.

ESO's published threat model names the assets and threats directly. It assumes a Helm install with defaults on a public cloud and notes that provider credentials may be broad enough to give full cloud access.

ESO threat (project ID)What it means in practicePrimary controls
T01 Tampering through MITMTraffic between the API server and webhook can be altered; the project notes mutual authentication is not enforced thereNetworkPolicy, restricted webhook TLS ciphers
T02 Webhook denial of serviceA flooded webhook blocks changes to ESO resourcesIngress only from the API server on 10250
T03 Unauthorised access to cluster secretsAnyone who can exec into or impersonate the controller reads every SecretRBAC on pods/exec, scoped install
T04 Access to provider credentialsStatic keys in a store secretRef or a broad IAM role unlock the vaultWorkload identity, per-store roles, provider policy
T05 Exfiltration through malicious resourcesA tenant writes an ExternalSecret or PushSecret that moves data where they can read itAdmission policy, disabled CRDs, egress limits
T06 Supply chain attacksA tampered image or chart runs with the controller's privilegesCosign verification, SLSA provenance, SBOM
T07 Malicious workloads in the ESO namespaceAny pod there can borrow the controller's identity and tokensDedicated namespace, Pod Security Admission, no other workloads

The controls the project names are C01 NetworkPolicy, C02 least privilege RBAC, C03 policy enforcement, C04 provider access policy (for example VPC endpoint or Private Link policies) and C05 disabling unneeded CRDs. ESO ships no NetworkPolicies and no admission policies; both are your job.

Choosing a store model for tenants

ESO's multi-tenancy guide describes two patterns. Most real clusters mix them, but the choice of default matters more than any other setting.

AspectShared ClusterSecretStoreSecretStore per namespace
Who creates storesCluster administratorsCluster or secret administrators, per namespace
Access boundaryStore conditions plus admission policy; ESO cannot restrict keys per namespace itselfProvider role behind each store (IAM policy, Vault policy, Key Vault RBAC)
Blast radius of one tenantEvery key the store's credential can readOnly that namespace's keys
Operational loadLowHigher: one provider role per store
Choose whenSingle team cluster, or a store that serves only non-sensitive shared configMulti-team or regulated clusters; a separate secret owner manages access
  • Restrict every ClusterSecretStore: use spec.conditions with namespaceSelector, namespaces or namespaceRegexes. Conditions are OR-ed, so a store is usable in a namespace that meets any one of them; one loose regex or a label tenants can set themselves widens access. Pair label-based conditions with a policy that stops tenants editing namespace labels.
  • No cross-namespace references: the security guide says SecretStore and ExternalSecret must not carry cross-namespace references to Secret or SecretStore kinds. Enforce it with admission policy.
  • One provider role per store: the AWS provider docs recommend a separate role per SecretStore and a name prefix (for example team-a/*) in the resource ARN.
  • Use the controller field for isolation: the controller field on stores selects which ESO instance reconciles them, similar to an ingress class, so a high-trust store can be served by a separate, scoped deployment.

Hardening the install: RBAC, Helm values and network

SettingWhereEffect
rbac.serviceAccountTokenCreate: falseHelmRemoves the broad serviceaccounts/token: create grant; add a per-service-account Role with resourceNames for stores that use Kubernetes service account auth
scopedRBAC: true, scopedNamespaceHelmRuns ESO against one namespace; implicitly disables cluster stores and cluster external secrets
--enable-cluster-store-reconciler=false / processClusterStore: falseFlag / HelmStops reconciling ClusterSecretStores
--enable-cluster-external-secret-reconciler=false / processClusterExternalSecret: falseFlag / HelmStops ClusterExternalSecrets fanning secrets out across namespaces
--enable-push-secret-reconciler=false / processPushSecret: falseFlag / HelmStops writing back to the provider
crds.createClusterSecretStore, crds.createPushSecret (and peers) falseHelmRemoves the CRD; disable the matching reconciler too, or the controller logs errors
webhook.extraArgs.tls-ciphersHelmRestricts webhook TLS suites
  • Kubernetes RBAC for people: limit create and update on ClusterSecretStore and ClusterExternalSecret to the platform team, keep SecretStore creation with whoever owns provider roles, deny pods/exec in the ESO namespace, and review what the aggregated view, edit and admin ClusterRoles grant on ESO kinds. See the Kubernetes RBAC Guide.
  • NetworkPolicy: default deny in the ESO namespace. The core controller needs egress to the API server and the provider (private endpoints preferred) and ingress on 8080 from monitoring. The webhook needs ingress on 10250 from the API server, 8080 from monitoring and 8081 from the kubelet. The cert controller needs ingress on 8080 and 8081.
  • Pod security: ESO pods meet the restricted Pod Security Standards profile by default since v0.8.2; label the namespace pod-security.kubernetes.io/enforce: restricted so nothing weaker can run beside them.
  • Supply chain: verify images by digest with cosign verify against the GitHub Actions OIDC issuer and the project's release.yml workflow identity, check SLSA provenance and pull the SPDX SBOM attestation. Only the current minor release is supported, so plan upgrades rather than pinning for years.

Where identity fits: the store's provider credential

Every store authenticates to the provider as a non-human identity, and that credential is usually more powerful than anything else in the namespace. Prefer the provider's workload identity (IRSA or EKS Pod Identity on AWS, Workload Identity on GKE and AKS, Kubernetes auth on Vault) over static keys in auth.secretRef, because a static key in a Kubernetes Secret is exactly what an attacker with cluster read access takes first. The Tesla Kubernetes cryptojacking incident started with long-lived AWS credentials readable inside a pod.

  • Least privilege on the provider: grant secretsmanager:GetSecretValue, DescribeSecret and ListSecretVersionIds on a name prefix; note that the documented example grants ListSecrets and BatchGetSecretValue on *, so check what that exposes in your account.
  • Write access only for PushSecret stores: CreateSecret, PutSecretValue and DeleteSecret belong on a separate role, with DeleteSecret conditioned on the tag managed-by=external-secrets as the AWS provider docs suggest.
  • Provider-side network policy: restrict the role or vault to the cluster's VPC endpoint or private link so a stolen token is useless off-network.

See the Kubernetes NHI Security Guide and the Secrets Zero Problem Guide for the bootstrap question.

Sync behaviour, rotation and deletion

FieldValues (default first)Security consequence
spec.refreshPolicyPeriodic, OnChange, CreatedOnceOnly Periodic picks up a value rotated in the provider; the other two leave the old value in the cluster
spec.refreshIntervalDuration, for example 1h; 0 syncs onceSets the worst-case lag between rotating in the vault and pods seeing it
spec.target.creationPolicyOwner, Orphan, Merge, NoneOwner deletes the Secret with the ExternalSecret; Orphan leaves copies behind that nobody tracks
spec.target.deletionPolicyRetain, Delete, MergeWith Retain, deleting a secret in the provider does not remove it from the cluster
spec.target.immutabletrue or unsetThe only setting that stops an existing Secret being overwritten when the ExternalSecret is recreated
PushSecret deletionPolicyNone, DeleteNone leaves provider secrets in place after the PushSecret is deleted
  • Rotation needs a reload: a refreshed Secret does not restart pods that read it at start-up as environment variables. Pair rotation with a rollout trigger or mount secrets as volumes and have the application reload.
  • Treat dataFrom.find as broad access: a regexp or tag search pulls every matching key into one Secret. Restrict .spec.data[].remoteRef.key and dataFrom to an approved prefix per namespace with admission policy.
  • Revocation means deleting in two places: on an incident, rotate in the provider, then confirm the cluster copy changed, or delete it, because Retain keeps the old value.

Detection and measurement

  • ESO metrics: alert on externalsecret_sync_calls_error as a ratio of externalsecret_sync_calls_total, on externalsecret_status_condition and secretstore_status_condition not Ready, on controller_runtime_reconcile_total{result="error"}, and on workqueue_depth staying above zero. externalsecret_provider_api_calls_count by provider, call and status shows denied calls.
  • Kubernetes audit log: record create and update on all ESO kinds, pods/exec into the ESO namespace, and any access to Secrets by identities other than the ESO controller and the workloads that own them. See the Kubernetes Audit Log Detection Guide.
  • Provider logs: CloudTrail, Vault audit or Key Vault diagnostics should show reads only from the expected roles, from the cluster network, at roughly the refresh cadence. A spike in ListSecrets or reads of keys outside a store's prefix is a strong signal. See Secrets Access Logging and Detection.

Metrics that show the programme is working:

  1. Percentage of stores using workload identity rather than a static secretRef (target 100%).
  2. Number of ClusterSecretStores without spec.conditions (target 0).
  3. Sync error rate over 24 hours, and median time from provider rotation to cluster update.
  4. Count of orphaned Secrets: labelled as ESO-managed but with no owning ExternalSecret.
  5. Admission policy violations per week by namespace, trending down after onboarding.

Phased rollout

  1. Inventory: list every store, its auth method and provider role, every ClusterSecretStore's conditions, and which CRDs and reconcilers are enabled.
  2. Disable unused features: switch off PushSecret, cluster external secrets and cluster stores if nothing uses them; disable the reconciler and the CRD together. Test in a non-production cluster first.
  3. Move to workload identity: replace static provider keys store by store, then revoke the keys and delete the Kubernetes Secrets that held them.
  4. Admission policy in audit mode: deploy Kyverno or Gatekeeper rules for allowed providers, key prefixes per namespace and permitted store references in Audit, review violations for two weeks, then switch to Enforce.
  5. Network and pod security: apply default deny NetworkPolicies and the restricted Pod Security label, watching sync metrics for breakage.
  6. Rollback: keep the previous Helm values in Git; policy rules can be returned to Audit and NetworkPolicies removed without touching synced Secrets, which stay in place under the default Retain.

Framework mapping

Control areaNIST CSF 2.0NIST SP 800-53 r5MITRE ATT&CK
Least privilege for controller, users and provider rolesPR.AA-05AC-6T1552.007 Container API
Provider credential management and rotationPR.AA-01IA-5, SC-12T1552.001 Credentials In Files
Disable unused CRDs and reconcilersPR.PS-01CM-7, CM-6T1613 Container and Resource Discovery
Image signature and provenance checksPR.PS-01SR-4, SR-11None specific
Secrets at rest and in transitPR.DS-01, PR.DS-02SC-28, SC-8None specific
Sync and access monitoringDE.CM-09AU-6T1609 Container Administration Command

Common failure patterns

  • One ClusterSecretStore with an admin-grade role: any team that can create an ExternalSecret can name any key. Split by namespace or add conditions and a key-prefix policy.
  • Static cloud keys bootstrapping the store: the key sits in a Kubernetes Secret, often never rotated, and is readable by anyone with Secret read in that namespace.
  • Extra workloads in the ESO namespace: debugging pods or sidecars there can reach the controller's service account and token.
  • Assuming rotation is automatic: CreatedOnce or OnChange stores, or pods that only read environment variables at start-up, keep the old credential long after the vault rotated it.
  • Secrets still committed beside the ExternalSecret: teams keep the old base64 Secret manifest in the repository. The exposed Kubernetes Secrets case involving SAP shows how long such files stay valid on public GitHub.

Practitioner checklist

  • Run ESO in a dedicated namespace with the restricted Pod Security label and nothing else deployed there.
  • Set rbac.serviceAccountTokenCreate: false and deny pods/exec in the ESO namespace.
  • Disable the PushSecret, ClusterExternalSecret and ClusterSecretStore reconcilers and CRDs you do not use.
  • Give every ClusterSecretStore spec.conditions and stop tenants changing the labels it depends on.
  • Use workload identity for every store and a separate, prefix-scoped provider role per store.
  • Enforce allowed providers, key prefixes and store references with Kyverno or Gatekeeper.
  • Apply default deny NetworkPolicies with only the documented ports open.
  • Verify image signatures and provenance before each upgrade, and stay on the supported minor release.
  • Alert on sync errors, not-Ready stores and unexpected provider reads.

Standards and references

Related NHI Mgmt Group resources: Kubernetes Secrets Security Guide · GitOps Security Guide · SOPS and Sealed Secrets · Cloud Secrets Managers Guide · Kubernetes Admission Control Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 28 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org