Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXXXII · GitOps SecretsExternalSystems

External secret systems — Vault, cloud KMS, and the controller that bridges them

Advanced⏱ ~24 minkubectlgit

What you'll learn

  • Describe the external-system class and what it puts in Git versus what it leaves in the store
  • Identify the four major external stores — Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager — and how the External Secrets Operator interfaces with each
  • Trace a reconcile cycle from a Git commit to a refreshed cluster Secret
  • Recognise the failure modes — store outage, credential expiry, RBAC drift — and how the controller surfaces them

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

The external-system class separates the two things that GitOps otherwise forces into one place: the desired configuration (which includes a credential by name) and the credential value (which is material the trust boundary cannot release). The repository holds the former; the external store holds the latter; a controller reconciles the cluster from both.

What goes in Git

A manifest in the repository does not contain the credential value. It contains:

  • A reference to the external store (a SecretStore or ClusterSecretStore resource naming Vault, AWS, Azure, or GCP).
  • A reference name that identifies which entry in the store the target Secret should be populated from.
  • A refresh interval and a rotation policy.

The cluster Secret resource is created by the controller, not committed by the engineer. The engineer’s commit creates the ExternalSecret resource; the controller creates the Secret.

flowchart LR
    A["Git commit: ExternalSecret manifest"] --> B["Flux / Argo: applies manifest"]
    B --> C["External Secrets Operator: reads store"]
    C --> D["Vault / AWS SM / AKV / GSM"]
    D --> C
    C --> E["Kubernetes Secret created"]
    E --> F["Pod consumes Secret"]

The cluster Secret exists only as long as the controller can reach the external store. If the store is unavailable, the Secret is either retained with the previous value or marked for refresh, depending on the configured policy.

The four major external stores

The External Secrets Operator interfaces with all four major managed stores through a provider abstraction:

  • HashiCorp Vault. Dynamic secrets, lease-based rotation, PKI, transit encryption. The most operationally heavy option but the most flexible.
  • AWS Secrets Manager. Native to AWS; integrates with IAM for both the controller and the workload identity. Rotation is replica-based and slower than Vault’s lease model.
  • Azure Key Vault. Native to Azure; integrates with Managed Identity and Azure AD. Backed by HSMs in the Premium tier.
  • Google Cloud Secret Manager. Native to GCP; integrates with Workload Identity. Versioning is per-secret and visible in the manifest.

The choice between them is rarely a security choice — all four are credible trust boundaries — and usually an operational choice: where is the workload, what identity model does the team already operate, and what rotation cadence is required.

The reconcile cycle

A typical flow:

  1. The engineer commits an ExternalSecret manifest naming a store and a reference. The reference is a string — a path in Vault, a name in AWS Secrets Manager.
  2. The GitOps controller (Flux or Argo CD) applies the manifest to the cluster.
  3. The External Secrets Operator reconciles. It authenticates to the store using its workload identity, fetches the value, and creates a Secret whose data matches the reference.
  4. On the configured refresh interval, the controller re-fetches. If the store value has rotated, the cluster Secret is updated; pods that mount the Secret see the new value on next mount or environment reload.

The GitOps commit is auditable. The store fetch is auditable in the store’s own log. The two audits together — “which manifest references which entry” and “which entry was returned at which time” — produce the same evidence a plaintext-in-Git system would, with the value never crossing the repository boundary.

Failure modes

The class has three failure modes that are not present in encrypted-at-rest or plaintext systems:

  • Store outage. The controller cannot fetch. Depending on policy, the cluster Secret is either retained with the previous value, or deleted, or marked as stale. The application either continues with a stale credential or fails.
  • RBAC drift. The controller’s workload identity loses access to the store. The reconcile fails with an authentication error. The cluster Secret is not refreshed.
  • Reference mismatch. The manifest names a path that does not exist in the store. The reconcile fails with a not-found error. The cluster Secret is not created.

All three surface in the ExternalSecret resource’s status field. A monitoring system that watches the status field catches all three.

Production discipline

  1. The store is the trust boundary, not the controller. Compromise of the controller yields a window of unauthorised fetches; compromise of the store yields the values. Harden the store first.
  2. Refresh intervals are short. A rotation in the store that takes 24 hours to reach the cluster is a rotation that is not yet complete.
  3. The manifest does not contain the reference’s value. A pull request that adds an ExternalSecret must not contain a test value, an example value, or a comment that quotes the store entry. Reviewers reject on sight.

Cross-course references

  • Linux for Production Sysadmins - Part XXXIV (ConfigMgmt) covers rotation patterns; the same cadence applies at the cluster boundary.
  • Ansible for Production Sysadmins - Part XXXVII (RepoArch) covers Ansible Vault; the threat-model split is the same.
  • Terraform for Production Sysadmins - Part XV (SensitiveVars) covers Terraform Cloud’s variable store; the same pattern.

Quiz

Knowledge check · 4 questions

  1. Q1. In the external-system class, what does the GitOps repository contain for a credential?

  2. Q2. A compromised application pod with the External Secrets Operator deployed can authenticate to AWS Secrets Manager and read arbitrary secrets.

  3. Q3. Name the four major external stores the External Secrets Operator interfaces with, and the one with native lease-based dynamic-secret rotation.

  4. Q4. Trace the audit trail for a credential rotation that flowed through External Secrets Operator.

    On Monday at 09:00 UTC, the on-call engineer rotates the production RDS password in AWS Secrets Manager. The cluster uses External Secrets Operator with a 15-minute refresh interval. The application pods mount the cluster Secret as an environment variable. The next deploy is scheduled for Wednesday.

Passing score: 75%. Answers are checked in this browser.