Lifecycle
The External Secrets Operator manages the lifecycle of secrets in Kubernetes. With refreshPolicy, creationPolicy and deletionPolicy you get fine-grained control of its lifecycle.
Creation/Deletion Policy Combinations
Some combinations of creationPolicy/deletionPolicy are not allowed as they would delete existing secrets:
- deletionPolicy=Delete & creationPolicy=Merge
- deletionPolicy=Delete & creationPolicy=CreateOrMerge
- deletionPolicy=Delete & creationPolicy=None
- deletionPolicy=Merge & creationPolicy=None
Refresh Policy
The field spec.refreshPolicy defines how the operator refreshes the secret.
Periodic (default)
Refreshes the secret at a fixed interval via spec.refreshInterval. Due to backwards compatibility, setting a refresh interval of 0 will result in the same behavior as CreatedOnce.
OnChange
Refreshes the secret only when the ExternalSecret is updated.
CreatedOnce
Refreshes the secret only once per ExternalSecret object, on its first reconcile.
The sync state lives on the ExternalSecret's status, so deleting and recreating the
ExternalSecret resets it and triggers another one-time sync. Depending on the
creation policy that sync may overwrite the operator-managed keys of an existing
target Secret; creationPolicy=None does not update it, and spec.target.immutable:
true prevents data rewrites.
State is not persisted across ExternalSecret objects
ESO is stateless across ExternalSecret objects: it does not persist sync claims
or reclaim orphaned Secrets when an ExternalSecret is recreated. creationPolicy
(including Orphan) does not protect a pre-existing target Secret from being
rewritten on that sync. To keep an already-populated Secret from being overwritten
on recreation, set spec.target.immutable: true (optionally together with
refreshPolicy: CreatedOnce).
Creation Policy
The field spec.target.creationPolicy defines how the operator creates the secret.
Owner (default)
The External Secret Operator creates secret and sets the ownerReference field on the Secret. This secret is subject to garbage collection if the initial ExternalSecret is absent. If a secret with the same name already exists that is not owned by the controller it will result in a conflict. The operator will just error out, not claiming the ownership.
Secrets with ownerReference field not found
If the secret exists and the ownerReference field is not found, the controller treats this secret as orphaned. It will take ownership of this secret by adding an ownerReference field and updating it.
Orphan
Whenever triggered via RefreshPolicy conditions, the operator creates/updates
the target Secret according to the provider available information.
It does not set an ownerReference, so it does not trigger
garbage collection of the Secret when the ExternalSecret object is deleted.
The operator still watches the Secret, but for Orphan it re-syncs only when a refresh
is due (see the warning below and the behavior matrix), not on
every change to the Secret.
Unwanted reverts of manual changes
If you set spec.refreshPolicy to Periodic or OnChange and spec.target.creationPolicy to Orphan,
any changes manually done to the Secret will eventually be replaced on the next sync interval
or on the next update to ExternalSecret object. That manual change is then lost forever.
Use creationPolicy=Orphan with caution.
Merge
The operator does not create a secret. Instead, it expects the secret to already exist. Values from the secret provider will be merged into the existing secret. Note: the controller takes ownership of a field even if it is owned by a different entity. Multiple ExternalSecrets can use creationPolicy=Merge with a single secret as long as the fields don't collide - otherwise you end up in an oscillating state.
CreateOrMerge
Creates the Secret if it does not exist and, if it does, merges the provider values
into it while preserving keys owned by others (like Merge), without setting an
ownerReference (like Orphan). Unlike Merge it also creates a missing Secret,
so a deleted target is recreated immediately (driven by the Secret watch) while the
ExternalSecret exists; unlike Owner the Secret is retained when the
ExternalSecret is deleted. Combined with spec.target.immutable: true it gives
"create once, freeze, recreate if deleted, keep on ExternalSecret deletion". Note:
deletionPolicy=Delete is not allowed, the controller does not own the Secret.
None
The operator does not create or update the secret, this is basically a no-op.
Immutable target
Setting spec.target.immutable: true marks the generated Kind=Secret as immutable,
so its data is never rewritten once the Secret exists (Kubernetes itself also blocks
edits to an immutable Secret's data). It does not affect whether a missing Secret is
created or recreated, that is governed by creationPolicy and refreshPolicy. See the
behavior matrix for the full interaction.
Deletion Policy
DeletionPolicy defines what should happen if a given secret gets deleted from the provider.
DeletionPolicy is only supported on the specific providers, please refer to our stability/support table.
Retain (default)
Retain will retain the secret if all provider secrets have been deleted. If a provider secret does not exist the ExternalSecret gets into the SecretSyncedError status.
Delete
Delete deletes the secret if all provider secrets are deleted.
If a secret gets deleted on the provider side and is not accessible
anymore this is not considered an error and the ExternalSecret
does not go into SecretSyncedError status. This is also true for new
ExternalSecrets mapping to non-existing secrets in the provider.
deletionPolicy=Delete only takes effect with creationPolicy=Owner; the operator
refuses to delete a Secret it does not own and reports a SecretSyncedError otherwise.
Merge
Merge removes keys in the secret, but not the secret itself. If a secret gets deleted on the provider side and is not accessible anymore this is not considered an error and the ExternalSecret does not go into SecretSyncedError status.
Behavior matrix
How creationPolicy and refreshPolicy combine to drive the Secret operations.
deletionPolicy is a separate axis (covered below the table) that only fires when
the provider returns no data.
| creationPolicy | refreshPolicy | Create if missing | Reflect source change | Overwrite on ES re-create | Recreate if Secret deleted | Retain on ES delete |
|---|---|---|---|---|---|---|
| Owner | Periodic | Yes | Yes (at interval) | Yes | Yes (immediate) | No (GC via ownerRef) |
| Owner | OnChange | Yes | Only on ES change | Yes | Yes (immediate) | No (GC via ownerRef) |
| Owner | CreatedOnce | Yes | No | Yes | Yes (immediate) | No (GC via ownerRef) |
| Orphan | Periodic | Yes | Yes (at interval) | Yes | Yes (at interval) | Yes |
| Orphan | OnChange | Yes | Only on ES change | Yes | No (until ES change) | Yes |
| Orphan | CreatedOnce | Yes | No | Yes | No | Yes |
| Merge | Periodic | No (waits) | Yes (at interval) | Yes (if target exists) | No (never creates) | Yes |
| Merge | OnChange | No (waits) | Only on ES change | Yes (if target exists) | No (never creates) | Yes |
| Merge | CreatedOnce | No (waits) | No | Yes (if target exists) | No (never creates) | Yes |
| CreateOrMerge | Periodic | Yes | Yes (at interval) | Yes | Yes (immediate) | Yes |
| CreateOrMerge | OnChange | Yes | Only on ES change | Yes | Yes (immediate) | Yes |
| CreateOrMerge | CreatedOnce | Yes | No | Yes | Yes (immediate) | Yes |
| None | any | No (no-op) | No | No | No | Yes (nothing created) |
Column meanings:
- Reflect source change: a value changing in the provider is pulled into the
Secret. ESO is pull-based and does not watch providers, so only
Periodicpolls (at each interval).OnChangere-syncs only when theExternalSecretspec or metadata changes, or when you set theforce-syncannotation.CreatedOncenever re-syncs. - Overwrite on ES re-create: deleting and recreating the
ExternalSecretobject resets its status, so the next sync overwrites the ES-managed keys of an existing target (keys owned by others are preserved). This is independent ofrefreshPolicy; onlyspec.target.immutable: trueprevents it. - Recreate if Secret deleted: you delete the target Secret while the
ExternalSecretstill exists.Ownertreats a missing Secret as invalid and recreates it immediately via the Secret watch.Orphantreats a missing Secret as valid, so it only recreates when a refresh is triggered (aPeriodicinterval); underCreatedOnceorOnChangeit stays deleted.Mergenever creates. - Retain on ES delete: whether the target Secret survives deletion of the
ExternalSecret. OnlyOwnersets anownerReference, so onlyOwneris garbage-collected.
Modifiers that cut across every row:
spec.target.immutable: true: once the target Secret exists, its data is never rewritten, so "Reflect source change" and "Overwrite on ES re-create" become No. It does not affect "Create if missing" or "Recreate if Secret deleted", a Secret that does not exist has no data to protect, so it is created or recreated fresh.refreshInterval: 0withPeriodicbehaves likeCreatedOnce.deletionPolicy(Retain, Delete, Merge) only acts when the provider returns no data, which is only detected on a re-sync. So underCreatedOncea provider-side deletion is never detected, underOnChangeonly on anExternalSecretchange, and underPeriodicat the next interval.