skip to content

External Secret Integration

Real credentials usually live in Vault or a cloud secret manager, so the cluster needs a bridge: an operator that syncs them into a Secret, or a CSI driver that mounts them into the pod. Interviewers ask because rotation must work without a redeploy.

part ofKubernetesoverview, primer and where to startread it →
on this pageshow

questions

5

How does the External Secrets Operator turn a value in an external secret manager into a Kubernetes Secret, and what does an ExternalSecret's refreshInterval control?

level: middleimportance: must knowfreq 68%

answer

  1. store says how, ExternalSecret says what
  2. namespaced vs cluster-scoped store
  3. target Secret owned by default
  4. one hour unless you say otherwise
  5. staleness bound and provider rate

basics

~20 s

A SecretStore or ClusterSecretStore defines provider access. An ExternalSecret names remote keys and a target Secret. The operator fetches the values, writes the Secret, and re-reads the provider every refreshInterval, which defaults to one hour.

solid answer

~40 s

The External Secrets Operator splits the job into two custom resources in `external-secrets.io/v1`. A **`SecretStore`** (namespaced) or **`ClusterSecretStore`** (cluster-scoped) holds the provider connection and the credential used to authenticate. An **`ExternalSecret`** references a store through `secretStoreRef`, lists remote keys under `data` (`secretKey` plus `remoteRef.key` and `property`) or `dataFrom`, and names a `target` Secret. The controller reads the provider, writes an ordinary `Secret`, and by default owns it (`creationPolicy: Owner`). `refreshInterval` (default `1h0m0s`) is how long it waits before reading the provider again. `0s` means fetch once. A change to the ExternalSecret itself triggers an immediate re-read. So `refreshInterval` bounds how stale the Secret can be after a rotation, and it also sets your request rate against the provider.

code

yaml · 18 lines
yaml
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: tracking-db
  namespace: shipment-tracking
spec:
  refreshInterval: 15m
  secretStoreRef:
    kind: SecretStore
    name: tracking-vault
  target:
    name: tracking-db
    creationPolicy: Owner
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: prod/tracking/db
        property: password

go deeper

for a junior

Recall the pieces: a store that knows how to reach the secret manager, an ExternalSecret that names what to fetch, and an ordinary Secret as the result.

for a middle

Explain the reconcile loop, the one-hour default, what 0s means, and how creationPolicy Owner ties the Secret's lifetime to the ExternalSecret.

for a senior

Show operational judgment: read the Ready condition, force a sync by changing the ExternalSecret, and know that an outage keeps the last good value while blocking rotation.

for a principal

Discuss the interval as a trade between staleness after rotation and provider request volume and cost, and how store scoping shapes who can read what.

## Why a bridge is needed Most organisations keep real credentials in a **secret manager**: a Vault-style server or a cloud provider's secret service. Workloads in Kubernetes, however, consume **`Secret`** objects through environment variables or volumes. The **External Secrets Operator (ESO)** is a controller that bridges the two. It reads values from the external system and writes them into native Secrets, so applications need no provider SDK and no provider credentials of their own. ## The two resources ESO's API group is `external-secrets.io`, with `v1` as the stored version. - **`SecretStore`** is namespaced. It describes *how to reach* one provider (`spec.provider`) and *how to authenticate* (for example a ServiceAccount token exchange or a reference to a credential Secret). Only ExternalSecrets in the **same namespace** can use it. - **`ClusterSecretStore`** has the same shape but is cluster-scoped, so any namespace can reference it. Its `spec.conditions` (`namespaceSelector`, `namespaces`, `namespaceRegexes`) can limit which namespaces may use it. - **`ExternalSecret`** is namespaced. It says *what to fetch* and *where to put it*: - `spec.secretStoreRef` holds `name` and `kind` (`SecretStore` or `ClusterSecretStore`). - `spec.data[]` maps one Secret key (`secretKey`) to a remote value (`remoteRef.key`, optionally `remoteRef.property` for one field of a JSON value). - `spec.dataFrom[]` pulls many keys at once, for example by extracting a whole JSON document. - `spec.target` holds the Secret `name`, a `creationPolicy`, a `deletionPolicy` and an optional `template` for shaping the output. ## The reconcile loop 1. The controller watches ExternalSecrets and the Secrets it manages. 2. On reconcile it resolves the store, authenticates to the provider and fetches every referenced value. 3. It builds the target `Secret` and adds the label `reconcile.external-secrets.io/managed: "true"` and an annotation `reconcile.external-secrets.io/data-hash` holding a hash of the data. 4. It creates or updates the Secret and sets the ExternalSecret's `Ready` condition (reason `SecretSynced`, or `SecretSyncedError` on failure). 5. It requeues for the next refresh. The controller skips a refresh only when the interval has not elapsed, the ExternalSecret is unchanged, **and** the target Secret still exists with the right label and data hash. A deleted or hand-edited Secret is therefore treated as drift and rewritten from the provider. ## refreshInterval and refreshPolicy | Setting | Behaviour | |---|---| | `refreshInterval` unset | Defaults to `1h0m0s` | | `refreshInterval: 15m` | Re-reads the provider every 15 minutes | | `refreshInterval: 0s` | Fetches once, then stops periodic refresh | | `refreshPolicy: Periodic` | Refresh on the interval (the effective default) | | `refreshPolicy: OnChange` | Refresh only when the ExternalSecret's spec or metadata changes | | `refreshPolicy: CreatedOnce` | Create the Secret once and never update it | Two consequences matter in interviews: - **Staleness bound.** After a value is rotated in the provider, the Secret can lag by up to one `refreshInterval`. Editing the ExternalSecret, for example by bumping an annotation, forces an early re-read. - **Provider load.** Every refresh is a provider API call. A short interval on hundreds of objects can hit provider rate limits or run up per-request costs. ## Ownership and deletion - `creationPolicy` defaults to **`Owner`**: the Secret gets an `ownerReference` to the ExternalSecret and is garbage-collected when the ExternalSecret is deleted. `Orphan` leaves it behind, `Merge` only merges keys into an existing Secret, `CreateOrMerge` creates the Secret if it is missing and merges into it otherwise, and `None` writes nothing. - `deletionPolicy` defaults to **`Retain`**: if the provider value disappears, the last synced Secret is kept. `Delete` removes it, and `Merge` removes only the affected keys. - If the provider is **unreachable**, the controller marks the ExternalSecret failed and leaves the existing Secret alone, so running workloads keep working with the last good value. ## Worked example The shipment-tracking API needs its database password. A namespaced SecretStore in `shipment-tracking` authenticates with that namespace's ServiceAccount. An ExternalSecret maps `remoteRef.key: prod/tracking/db` and `property: password` to the Secret key `DB_PASSWORD` in a Secret named `tracking-db`, with `refreshInterval: 15m`. Git contains only these two manifests and no secret material. What ESO does **not** do is make the running process use the new value. It updates the Secret object. How Pods pick that up depends on how they consume it.

  • The provider value was rotated five minutes ago and you cannot wait for the refresh. How do you force a sync?
    Change the ExternalSecret object, for example by adding or bumping an annotation with `kubectl annotate --overwrite`. The controller refreshes whenever the ExternalSecret changes, regardless of the interval. Then confirm that the `Ready` condition reports `SecretSynced`.
  • Someone runs kubectl edit on the synced Secret and changes the password by hand. What happens?
    The operator keeps a data-hash annotation and the managed label on the Secret and watches it. The edited data no longer matches the hash, so the next reconcile treats it as drift and rewrites the value from the provider. Manual edits do not stick.
  • The provider is down for an hour. Do Pods lose their credentials?
    No. A failed fetch marks the ExternalSecret `Ready=False` with reason `SecretSyncedError` and leaves the existing Secret untouched, so running and newly started Pods still get the last good value. Alert on the condition, because a rotation during the outage will not propagate.

saying these in an interview costs you the question

  • The operator injects values straight into Pods, bypassing Secrets
  • refreshInterval restarts the Pods that use the Secret
  • A ClusterSecretStore is required for any cross-team setup
  • Deleting the ExternalSecret always leaves the Secret behind
  • A provider outage wipes the synced Secret
  • Shorter refreshInterval is free, so use seconds everywhere
open as a page

The shipment-tracking API reads its database password from a Kubernetes Secret synced by the External Secrets Operator: after the password rotates upstream, how do running Pods get the new value without a redeploy?

level: seniorimportance: must knowfreq 58%

basics

~20 s

The operator updates the Secret within one refreshInterval, but only volume-mounted files change in running Pods, never env vars. Mount files the app re-reads, or trigger a rolling restart, and keep both passwords valid until every Pod has switched.

open as a page

Your team deploys to Kubernetes with GitOps: how can Secret values live in Git safely, and how do Sealed Secrets and SOPS differ?

level: juniorimportance: should knowfreq 52%

basics

~20 s

Never commit a plain Secret manifest, because base64 is readable. Sealed Secrets commits a SealedSecret that only an in-cluster controller can decrypt. SOPS commits values encrypted with an external key and decrypts them at deploy time.

open as a page

How does the Secrets Store CSI Driver deliver external secrets into a Kubernetes Pod, and what does a SecretProviderClass's secretObjects field add?

level: middleimportance: should knowfreq 40%

basics

~20 s

A Pod mounts an inline CSI volume naming a SecretProviderClass. At mount time the driver asks a provider plugin for the values and writes them as files. secretObjects also mirrors them into a Kubernetes Secret, for example for env vars.

open as a page

A platform team runs 612 External Secrets Operator ExternalSecrets for many teams on one 48-node Kubernetes cluster: how would you design store scoping, refresh cadence and outage behaviour?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

Give each team a namespaced SecretStore with its own provider identity, and keep ClusterSecretStores few and condition-limited. Tier refreshInterval by credential class within the provider call budget. Alert on failed syncs, because an outage keeps values but stops rotation.

open as a page