Skip to content

ExternalSecret

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 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:

apiVersion: external-secrets.io/v1beta1
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:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: example
spec:
  refreshPolicy: Periodic
  refreshInterval: 1h  # 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:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: example
spec:
  refreshPolicy: OnChange
  # other fields...

Manual Refresh

Regardless of the refresh policy, you can always 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

Features

Individual features are described in the Guides section:

Example

Take a look at an annotated example to understand the design behind the ExternalSecret.

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: "hello-world"

  # labels and annotations are copied over to the
  # secret that will be created
  labels:
    acme.org/owned-by: "q-team"
  annotations:
    acme.org/sha: 1234

spec:

  # Optional, SecretStoreRef defines the default SecretStore to use when fetching the secret data.
  secretStoreRef:
    name: aws-store
    kind: SecretStore  # or ClusterSecretStore

  # RefreshPolicy determines how the ExternalSecret should be refreshed.
  # - CreatedOnce: Creates the Secret only if it does not exist and does not update it afterward
  # - Periodic: (default) Synchronizes the Secret at intervals specified by refreshInterval
  # - OnChange: Only synchronizes when the ExternalSecret's metadata or specification changes
  refreshPolicy: Periodic

  # RefreshInterval is the amount of time before the values reading again from the SecretStore provider
  # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" (from time.ParseDuration)
  # May be set to zero to fetch and create it once
  refreshInterval: "1h"

  # the target describes the secret that shall be created
  # there can only be one target per ExternalSecret
  target:

    # The secret name of the resource
    # Defaults to .metadata.name of the ExternalSecret
    # It is immutable
    name: application-config

    # Specifies the ExternalSecret ownership details in the created Secret. Options:
    # - Owner: (default) Creates the Secret and sets .metadata.ownerReferences. If the ExternalSecret is deleted, the Secret will also be deleted.
    # - Merge: Does not create the Secret but merges data fields into the existing Secret (expects the Secret to already exist).
    # - Orphan: Creates the Secret but does not set .metadata.ownerReferences. If the Secret already exists, it will be updated.
    # - None: Does not create or update the Secret (reserved for future use with injector).
    creationPolicy: Merge

    # Specifies what happens to the Secret when data fields are deleted from the provider (e.g., Vault, AWS Parameter Store). Options:
    # - Retain: (default) Retains the Secret if all Secret data fields have been deleted from the provider.
    # - Delete: Removes the Secret if all Secret data fields from the provider are deleted.
    # - Merge: Removes keys from the Secret but not the Secret itself.
    deletionPolicy: Retain

    # Specify a blueprint for the resulting Kind=Secret
    template:
      type: kubernetes.io/dockerconfigjson # or TLS...

      metadata:
        annotations: {}
        labels: {}

      # Use inline templates to construct your desired config file that contains your secret
      data:
        config.yml: |
          database:
            connection: postgres://{{ .username }}:{{ .password }}@{{ .database_host }}:5432/payments

      # Uses an existing template from configmap
      # Secret is fetched, merged and templated within the referenced configMap data
      # It does not update the configmap, it creates a secret with: data["alertmanager.yml"] = ...result...
      templateFrom:
      - configMap:
          name: application-config-tmpl
          items:
          - key: config.yml

  # Data defines the connection between the Kubernetes Secret keys and the Provider data
  data:
    - secretKey: username
      remoteRef:
        key: database-credentials
        version: v1
        property: username
        decodingStrategy: None # can be None, Base64, Base64URL or Auto

      # define the source of the secret. Can be a SecretStore or a Generator kind
      sourceRef:
        # point to a SecretStore that should be used to fetch a secret.
        # must be defined if no spec.secretStoreRef is defined.
        storeRef:
          name: aws-secretstore
          kind: ClusterSecretStore

  # Used to fetch all properties from the Provider key
  # If multiple dataFrom are specified, secrets are merged in the specified order
  # Can be defined using sourceRef.generatorRef or extract / find
  # Both use cases are exemplified below
  dataFrom:
  - sourceRef:
      generatorRef:
        apiVersion: generators.external-secrets.io/v1alpha1
        kind: ECRAuthorizationToken
        name: "my-ecr"
  #Or
  dataFrom:
  - extract:
      key: database-credentials
      version: v1
      property: data
      conversionStrategy: Default
      decodingStrategy: Auto
    rewrite:
    - regexp:
        source: "exp-(.*?)-ression"
        target: "rewriting-${1}-with-groups"
  - find:
      path: path-to-filter
      name:
        regexp: ".*foobar.*"
      tags:
        foo: bar
      conversionStrategy: Unicode
      decodingStrategy: Base64
    rewrite:
    - regexp:
        source: "foo"
        target: "bar"

status:
  # refreshTime is the time and date the external secret was fetched and
  # the target secret updated
  refreshTime: "2019-08-12T12:33:02Z"
  # Standard condition schema
  conditions:
  # ExternalSecret ready condition indicates the secret is ready for use.
  # This is defined as:
  # - The target secret exists
  # - The target secret has been refreshed within the last refreshInterval
  # - The target secret content is up-to-date based on any target templates
  - type: Ready
    status: "True" # False if last refresh was not successful
    reason: "SecretSynced"
    message: "Secret was synced"
    lastTransitionTime: "2019-08-12T12:33:02Z"