Self-hosted service
external-secrets/external-secrets avatar
external-secrets/external-secrets

External Secrets Operator: syncing AWS, Vault and Key Vault data into Kubernetes Secrets

External Secrets Operator reads information from a third-party service like AWS Secrets Manager and automatically injects the values as Kubernetes Secrets.

6,888 stars1,446 forksGoApache-2.0

At a glance

What is it?
External Secrets Operator is a Kubernetes operator that reads from third-party secret managers and writes the values into Kubernetes Secrets. This review covers the Custom Resource flow, the Helm install path, and where the design stops being the right fit.
Who is it for?
Adopt External Secrets Operator if your secrets already live in a managed store and you want Kubernetes workloads to consume them as ordinary Secret objects without copying values by hand. Do not adopt it if you need a Kubernetes Secret to exist before the operator's controllers are running, or if you want secret material encrypted inside Git rather than fetched from a live API at runtime.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap External Secrets Operator fills between a secret manager and a pod

Kubernetes has no built-in way to read a value from AWS Secrets Manager, HashiCorp Vault or Azure Key Vault and hand it to a container. The usual workaround is a pipeline step or a manual copy: someone pulls the value, base64-encodes it, and applies a Secret manifest. That copy drifts the moment the upstream value rotates, and it puts the plaintext through whatever system ran the apply.

External Secrets Operator inverts the direction. The README describes it as a Kubernetes operator that integrates external secret management systems and injects the values into a Kubernetes Secret. The operator runs inside the cluster and pulls on a schedule you control, so the Kubernetes Secret is a projection of the upstream value rather than a snapshot someone pasted in.

It is aimed at platform teams running workloads on Kubernetes that already keep credentials in one of the supported stores. The README lists AWS Secrets Manager, HashiCorp Vault, Google Secrets Manager, Azure Key Vault, IBM Cloud Secrets Manager, Akeyless, CyberArk Secrets Manager and Pulumi ESC, and the repository carries a providers/ directory alongside generators/, which is where per-provider integration code lives. If your store is not represented there, the operator has nothing to talk to.

Custom Resources, controllers and the reconciliation loop

The mechanism is the standard Kubernetes operator pattern: Custom Resource Definitions plus controllers that reconcile desired state against observed state. The repository layout makes this concrete. apis/ holds the API types, config/crds holds the CRD manifests, pkg/ holds the controller and provider logic, and main.go is the entrypoint that the Dockerfile copies to /bin/external-secrets.

The user-facing objects are the SecretStore and ClusterSecretStore, which describe how to authenticate to a provider, and the ExternalSecret, which names a target Kubernetes Secret and the remote keys to pull into it. A SecretStore is namespaced; a ClusterSecretStore is cluster-wide, which is why it appears in search queries so often: teams reach for it when many namespaces need the same backend credentials.

Reconciliation is periodic. The operator authenticates to the provider using the credentials referenced by the store, fetches the requested keys, and writes or updates the target Secret. The README does not document rollback behaviour for a failed sync, so the safe assumption is that the last successfully written Secret stays in place until a later reconcile succeeds. Treat that as a design constraint, not a guarantee: if you need the previous value restored automatically, the README is silent on it.

The generators/ tree is a separate axis. Entries such as generators/v1/password, generators/v1/sshkey, generators/v1/uuid and generators/v1/webhook produce values rather than fetch them, and generators/v1/acr, generators/v1/ecr, generators/v1/gcr and generators/v1/quay mint registry credentials. Those are for the case where the secret does not exist upstream yet.

Installing External Secrets Operator with the Helm chart

The README points to external-secrets.io for guides and reference documentation, and the release list carries a chart version alongside each application version, which tells you the two are versioned separately. The chart is published under the external-secrets-operator repository on Artifact Hub, and the operator is also listed on operatorhub.io.

The README does not reproduce the install commands, so the block below is the repository's own build and image tooling rather than a chart invocation. The Makefile exports IMAGE_REGISTRY as ghcr.io and IMAGE_REPO as external-secrets/external-secrets, and the default goal builds every architecture listed in ARCH.

bash
make all
make docker.build

The Dockerfile copies bin/external-secrets-${TARGETOS}-${TARGETARCH} into /bin/external-secrets and sets the entrypoint to that binary, running as USER 65534. That is what a container built from this repository executes.

dockerfile
FROM gcr.io/distroless/static@sha256:f2ea2709ac8db56323cbd7d014277f32cb572d9ea124b0076f7aafe5980678fe
COPY bin/external-secrets-${TARGETOS}-${TARGETARCH} /bin/external-secrets
USER 65534
ENTRYPOINT ["/bin/external-secrets"]

For a cluster install, follow the guides on external-secrets.io and pin both the chart version and the application version. The repository ships deploy/ and config/crds, which is where the CRD manifests the operator needs come from. The README does not list the provider-specific fields for a SecretStore, so take those from the provider page in the documentation rather than guessing.

Where the operator is the wrong tool

The operator is a runtime dependency, and that has consequences. If the controllers are not running, no new Secret is written. A cluster that boots before the operator is scheduled, or a namespace where the operator has been scaled to zero, will have workloads waiting on Secrets that do not exist yet. Workloads that read the Secret at startup and fail hard will crash-loop rather than wait.

Rotation is not instantaneous. The operator reconciles on an interval, so the gap between a value changing upstream and the Kubernetes Secret reflecting it is bounded by that interval plus the time the provider API takes to answer. A pod that caches the value in memory at start does not pick up the new one until it restarts, regardless of how quickly the Secret object updates.

The provider credential is the real blast radius. A ClusterSecretStore holds a reference to credentials that can read many secrets across many namespaces. That is the point of the cluster-scoped object, and it is also why the RBAC around who may create a ClusterSecretStore matters more than the ExternalSecret itself. The repository ships SECURITY.md and SECURITY_RESPONSE.md, and the README asks that vulnerabilities be reported to [email protected] rather than through public issues.

Finally, this is not a GitOps encryption tool. If your requirement is that secret material be encrypted and committed to a repository so that a cluster can reconstruct it without network access to a provider, the operator's model is the opposite of what you want.

External Secrets Operator compared with Sealed Secrets and the CSI driver

Sealed Secrets solves a different half of the problem. It encrypts a Secret so it can be committed to Git and decrypted only by a controller in the target cluster. Nothing is fetched from an external API, and nothing rotates on its own. The trade-off is that the encrypted blob is the source of truth, so rotating a credential means re-sealing and committing it. With External Secrets Operator the source of truth stays in the provider and the cluster holds a copy.

The Secrets Store CSI driver is closer in spirit but differs in delivery. It mounts secret material into a pod as a volume through the CSI interface rather than writing a Kubernetes Secret object. That means no Secret exists in etcd for anything else to read, but it also means anything that expects an ordinary Secret, including many Helm charts and operators, cannot consume it directly. External Secrets Operator writes a real Secret, which is why it composes with the rest of the ecosystem and why the plaintext ends up in etcd.

HashiCorp's own Vault operator is the narrower option: it targets Vault specifically, so if Vault is your only backend it may fit with less configuration surface. External Secrets Operator's advantage is breadth. The providers/ directory covers many backends under one API shape, so a team moving from one store to another changes the store definition rather than the ExternalSecret.

Maintenance, release cadence and licence terms

The repository is not archived, and the last push was on 2026-09-21. Recent releases are v2.11.0 on 2026-09-18, v2.10.0 on 2026-08-28, and helm-chart-2.11.0 on 2026-09-21. The chart version and the application version move on separate tracks, so an upgrade plan has to name both.

The README describes a bi-weekly development meeting held every odd Wednesday, with alternating times, notes kept in a public document and announcements in the Kubernetes Slack channel. It also points to a roadmap in the documentation and to a stability and support policy page. Those are the two documents to read before you commit to a version, because the README itself does not state a support window or a deprecation timeline. DEPRECATING.md exists at the repository root, which suggests the project has a written process, but the README does not summarize it.

The licence is Apache-2.0, which permits commercial use and modification and includes an explicit patent grant. It does not impose copyleft obligations on your own code. Nothing here is legal advice, and if you redistribute the operator inside a product you should read LICENSE and the NOTICE handling in .licenserc.yaml yourself rather than relying on this summary. The README also notes that SBOM and provenance files are attached to GitHub releases and to container images, which matters if your supply-chain policy requires attestations.

Editorial conclusion

Adopt External Secrets Operator if your secrets already live in a managed store and you want Kubernetes workloads to consume them as ordinary Secret objects without copying values by hand. Do not adopt it if you need a Kubernetes Secret to exist before the operator's controllers are running, or if you want secret material encrypted inside Git rather than fetched from a live API at runtime. Before committing, verify that your provider appears in the providers/ directory, check that the CRD version in config/crds matches the Helm chart you plan to install, and confirm your cluster's Kubernetes version against the chart's stated support policy.

Frequently asked questions

What is External Secrets Operator in Kubernetes?

It is a Kubernetes operator that integrates external secret management systems and injects the values into Kubernetes Secrets. It runs as a controller inside the cluster and reconciles Custom Resources that describe which remote keys should land in which Secret.

How do I install External Secrets Operator?

The README points to external-secrets.io for installation guides, and the project publishes a Helm chart under the external-secrets-operator repository on Artifact Hub as well as a listing on operatorhub.io. The chart version and the application version are released separately, so pin both.

How do I use External Secrets Operator in Kubernetes?

You create a SecretStore or ClusterSecretStore describing how to authenticate to the provider, then an ExternalSecret that names the target Kubernetes Secret and the remote keys to pull. The operator reconciles periodically and writes the values into that Secret.

How does External Secrets Operator differ from the Secrets Store CSI driver?

The CSI driver mounts secret material into a pod as a volume, so no Kubernetes Secret object is created. External Secrets Operator writes an actual Secret, which other workloads and charts can consume, but that also means the value is stored in etcd.

How does External Secrets Operator differ from Sealed Secrets?

Sealed Secrets encrypts a Secret so it can be committed to Git and decrypted in the cluster, with no external API involved. External Secrets Operator instead keeps the source of truth in a provider such as AWS Secrets Manager or Vault and fetches values at runtime.

What is an external secret?

In this project the term refers to the ExternalSecret Custom Resource, which names a target Kubernetes Secret and the remote keys to pull into it from a provider such as AWS Secrets Manager or Vault. The operator reconciles that object and writes the resulting Secret.

Official sources

  1. external-secrets/external-secrets on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/external-secrets-external-secrets.svg)](https://hysenlabs.com/projects/external-secrets-external-secrets)