External Secrets Operator adds a useful boundary: applications can consume Kubernetes Secret objects while the source value lives in a dedicated secret manager.

It also adds a new failure path. A backend token, SecretStore, controller, target Secret, and consuming workload all have to agree before rotation is actually safe.

Ownership Model

Write down the owner for each layer:

backend secret manager -> source value and access policy
SecretStore            -> authentication and provider configuration
ExternalSecret         -> mapping from backend key to Kubernetes Secret
target Secret          -> Kubernetes object consumed by workloads
application workload   -> reload behavior and verification
platform team          -> controller health, RBAC, namespaces, and alerts

If an ExternalSecret fails, do not assume it is an application bug or a secret-manager outage. Walk the chain.

Baseline Checks

Start read-only:

kubectl get clustersecretstore,secretstore -A
kubectl get externalsecret -A
kubectl get secret -A | grep -i '<target-name>'
kubectl -n external-secrets logs deploy/external-secrets --since=2h

Then inspect the specific object:

kubectl -n app-ns describe externalsecret app-secret
kubectl -n app-ns get externalsecret app-secret -o yaml

Look for:

  • Ready condition.
  • last refresh time.
  • refresh interval.
  • SecretStore reference.
  • target Secret name.
  • backend key or property mapping.
  • error messages from the provider.

Rotation Flow

A safe rotation usually looks like this:

write replacement in backend -> ExternalSecret refreshes target Secret
-> consumer reloads or rolls -> application verification passes
-> old credential is revoked upstream

If the backend supports versioned secrets, decide whether the ExternalSecret follows the latest version or a pinned version. Both models can work, but the rollback behavior is different.

Consumer Impact

Before treating an ExternalSecret error as urgent, identify consumers:

kubectl -n app-ns get deploy,statefulset,daemonset -o yaml | grep -n 'secretName\|secretKeyRef'
kubectl -n app-ns get pods -o wide

Classify impact:

  • no consumer exists yet.
  • consumer exists but target Secret is current.
  • target Secret is stale but pods still run.
  • target Secret is missing and pods cannot start.
  • old credential was revoked and running pods are failing.

This separates a controller configuration issue from active application impact.

GitOps Boundary

Keep the ExternalSecret and SecretStore configuration in Git when the cluster is GitOps-managed. Do not commit the generated target Secret value.

Review:

  • whether ArgoCD or Flux owns the ExternalSecret.
  • whether the generated target Secret is ignored, adopted, or pruned.
  • whether refresh interval changes are reviewed.
  • whether backend key names are environment-specific.
  • whether namespace owners can create stores or only references.

The generated Secret is runtime state. The mapping and access boundary are declared state.

Failure Model

The common failure is invisible staleness:

backend credential rotates -> ExternalSecret cannot authenticate
-> target Secret remains old -> pods keep running
-> old credential is revoked -> next restart fails

The operating rule: External Secrets Operator is healthy only when controller status, target Secret freshness, backend access, and consumer reload behavior are all visible.