The `ExternalSecret` describes what data should be fetched, how the data should be transformed and saved as a `Kind=Secret`: * tells the operator what secrets should be synced by using `spec.data` to explicitly sync individual keys or use `spec.dataFrom` to get **all values** from the external API. * you can specify how the secret should look like by specifying a `spec.target.template` ## Template When the controller reconciles the `ExternalSecret` it will use the `spec.template` as a blueprint to construct a new `Kind=Secret`. You can use golang templates to define the blueprint and use template functions to transform secret values. You can also pull in `ConfigMaps` that contain golang-template data using `templateFrom`. See [advanced templating](../guides/templating.md) for details. ## Update behavior with 3 different refresh policies You can control how and when the `ExternalSecret` is refreshed by setting the `spec.refreshPolicy` field. If not specified, the default behavior is `Periodic`. ### CreatedOnce With `refreshPolicy: CreatedOnce`, the controller will: - Create the `Kind=Secret` only if it does not exist yet - Never update the `Kind=Secret` afterwards if the source data changes - Update/ Recreate the `Kind=Secret` if it gets changed/Deleted - Useful for immutable credentials or when you want to manage updates manually Example: ```yaml apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: example spec: refreshPolicy: CreatedOnce # other fields... ``` ### Periodic With `refreshPolicy: Periodic` (the default behavior), the controller will: - Create the `Kind=Secret` if it doesn't exist - Update the `Kind=Secret` regularly based on the `spec.refreshInterval` duration - When `spec.refreshInterval` is set to zero, it will only create the secret once and not update it afterward - When `spec.refreshInterval` is set to a value greater than zero, the controller will update the `Kind=Secret` at the specified interval or when the `ExternalSecret` specification changes Example: ```yaml apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: example spec: refreshPolicy: Periodic refreshInterval: 1h0m0s # Update every hour # other fields... ``` ### OnChange With `refreshPolicy: OnChange`, the controller will: - Create the `Kind=Secret` if it doesn't exist - Update the `Kind=Secret` only when the `ExternalSecret`'s metadata or specification changes - This policy is independent of the `refreshInterval` value - Useful when you want to manually control when the secret is updated, by modifying the `ExternalSecret` resource Example: ```yaml apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: example spec: refreshPolicy: OnChange # other fields... ``` ## Manual Refresh If supported by the configured `refreshPolicy`, you can manually trigger a refresh of the `Kind=Secret` by updating the annotations of the `ExternalSecret`: ``` kubectl annotate es my-es force-sync=$(date +%s) --overwrite ``` ## SyncWindows `syncWindows` restricts **when** periodic refreshes may occur. It is evaluated in UTC and applies only to the `Periodic` refresh policy (or when `refreshPolicy` is unset). `OnChange` and `CreatedOnce` policies are unaffected. A sync-windows block carries a shared `kind` and a list of `schedule + duration` entries: - `kind: allow` -- periodic syncs are permitted **only** while at least one window is active; all other times are blocked. - `kind: deny` -- periodic syncs are **blocked** while any window is active; all other times proceed normally. Each entry in `windows` uses a standard 5-field cron `schedule` (UTC) and a `duration` string (e.g. `8h`, `30m`). The window stays open for `duration` after each schedule firing. A window entry with an unparseable `schedule` is silently ignored and treated as inactive, so a typo does not permanently block syncs. ### Example: allow syncs only during business hours (Mon-Fri 09:00-17:00 UTC) ```yaml apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: example spec: refreshInterval: 1h syncWindows: kind: allow windows: - schedule: "0 9 * * 1-5" # weekdays at 09:00 UTC duration: 8h # window open until 17:00 UTC ``` ### Example: block syncs during a Saturday maintenance window (02:00-04:00 UTC) ```yaml apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: example spec: refreshInterval: 30m syncWindows: kind: deny windows: - schedule: "0 2 * * 6" # Saturdays at 02:00 UTC duration: 2h # block until 04:00 UTC ``` ### Multiple windows You can list several entries under `windows`. For `kind: allow`, the sync is permitted when **any** window is active. For `kind: deny`, the sync is blocked when **any** window is active. ### Interaction with refreshInterval `syncWindows` only suppresses sync operations -- it does not change how often the controller checks. The controller still requeues at `refreshInterval` regardless of whether a sync was blocked. This means that if `refreshInterval` is longer than `window.duration`, a window could open and close entirely between two consecutive checks and the sync would be missed for that occurrence. This is by design: `refreshInterval` is the primary driver; `syncWindows` is a gate on top of it. To ensure no window occurrence is missed, set `refreshInterval` to a value shorter than the smallest `window.duration`. ## Features Individual features are described in the [Guides section](../guides/introduction.md): * [Find many secrets / Extract from structured data](../guides/getallsecrets.md) * [Templating](../guides/templating.md) * [Using Generators](../guides/generator.md) * [Secret Ownership and Deletion](../guides/ownership-deletion-policy.md) * [Key Rewriting](../guides/datafrom-rewrite.md) * [Decoding Strategy](../guides/decoding-strategy.md) ## Example Take a look at an annotated example to understand the design behind the `ExternalSecret`. ``` yaml {% include 'full-external-secret.yaml' %} ```