ClusterExternalSecret

The ClusterExternalSecret is a cluster scoped resource that can be used to manage ExternalSecret resources in specific namespaces.
With namespaceSelectors you can select namespaces in which the ExternalSecret should be created.
If there is a conflict with an existing resource the controller will error out.
Example
Below is an example of the ClusterExternalSecret in use.
apiVersion: external-secrets.io/v1
kind: ClusterExternalSecret
metadata:
name: "hello-world"
spec:
# The name to be used on the ExternalSecrets
externalSecretName: "hello-world-es"
# This is a basic label selector to select the namespaces to deploy ExternalSecrets to.
# you can read more about them here https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#resources-that-support-set-based-requirements
# Deprecated: Use namespaceSelectors instead.
# namespaceSelector:
# matchLabels:
# cool: label
# This is a list of basic label selector to select the namespaces to deploy ExternalSecrets to.
# you can read more about them here https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#resources-that-support-set-based-requirements
# The list is OR'd together, so if any of the namespaceSelectors match the namespace,
# the ExternalSecret will be deployed to that namespace.
namespaceSelectors:
- matchLabels:
cool: label
# How often the ClusterExternalSecret should reconcile itself
# This will decide how often to check and make sure that the ExternalSecrets exist in the matching namespaces
refreshTime: "1m"
# This is the spec of the ExternalSecrets to be created
# The content of this was taken from our ExternalSecret example
externalSecretSpec:
secretStoreRef:
name: secret-store-name
kind: SecretStore
# 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: "1h0m0s"
target:
name: my-secret
creationPolicy: 'Merge'
template:
type: kubernetes.io/dockerconfigjson
metadata:
annotations: {}
labels: {}
data:
config.yml: |
endpoints:
- https://{{ .data.user }}:{{ .data.password }}@api.exmaple.com
templateFrom:
- configMap:
name: alertmanager
items:
- key: alertmanager.yaml
data:
- secretKey: secret-key-to-be-managed
remoteRef:
key: provider-key
version: provider-key-version
property: provider-key-property
dataFrom:
- key: provider-key
version: provider-key-version
property: provider-key-property
status:
# This will list any namespaces where the creation of the ExternalSecret failed
# This will not list any issues with the ExternalSecrets, you will have to check the
# ExternalSecrets to see any issues with them.
failedNamespaces:
- namespace: "matching-ns-1"
# This is one of the possible messages, and likely the most common
reason: "external secret already exists in namespace"
# You can find all matching and successfully deployed namespaces here
provisionedNamespaces:
- "matching-ns-3"
- "matching-ns-2"
# The condition can be Ready, PartiallyReady, or NotReady
# PartiallyReady would indicate an error in 1 or more namespaces
# NotReady would indicate errors in all namespaces meaning all ExternalSecrets resulted in errors
conditions:
- type: PartiallyReady
status: "True"
lastTransitionTime: "2022-01-12T12:33:02Z"
Reducing provider calls for large namespace sets
A ClusterExternalSecret creates one ExternalSecret per matched namespace,
and each of those ExternalSecrets independently polls the upstream provider on its own refreshInterval.
This means provider API calls scale linearly with the number of matched namespaces, which can be costly or hit rate limits.
This is a known characteristic of the design.

If your selector matches more than a handful of namespaces, the recommended pattern is to pull
from the upstream provider once into a single in-cluster Secret, then
use the Kubernetes provider to fan that
Secret out via the ClusterExternalSecret:
- A single namespace-scoped
ExternalSecretpulls from the upstream provider and writes aSecretin a dedicated "source" namespace. - A
ClusterSecretStoreusing the Kubernetes provider points at that sourceSecret. - A
ClusterExternalSecretreferences thatClusterSecretStore, replicating theSecretinto every matched namespace. Regardless of how many namespaces match, the upstream provider is only called by the single sourceExternalSecretin step 1.

# Step 1: A single ExternalSecret pulls from the upstream provider.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: shared-credentials
namespace: eso-fanout-source
spec:
refreshInterval: "1h"
secretStoreRef:
name: my-upstream-store
kind: ClusterSecretStore
target:
name: shared-credentials
dataFrom:
- extract:
key: path/to/shared-credentials
---
# Step 2: ClusterSecretStore reads the source Secret via the Kubernetes provider.
apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
name: shared-credentials-store
spec:
provider:
kubernetes:
remoteNamespace: eso-fanout-source
server:
caProvider:
type: ConfigMap
name: kube-root-ca.crt
namespace: eso-fanout-source
key: ca.crt
auth:
serviceAccount:
name: eso-fanout-reader
namespace: eso-fanout-source
---
# Step 3: ClusterExternalSecret fans the Secret out to matching namespaces.
apiVersion: external-secrets.io/v1
kind: ClusterExternalSecret
metadata:
name: shared-credentials
spec:
externalSecretName: shared-credentials
namespaceSelectors:
- matchLabels:
shared-credentials: "true"
externalSecretSpec:
refreshInterval: "1h"
secretStoreRef:
name: shared-credentials-store
kind: ClusterSecretStore
target:
name: shared-credentials
dataFrom:
- extract:
key: shared-credentials
The ServiceAccount and RBAC for the Kubernetes provider store are the same
as described in the Kubernetes provider docs.
Direct use of ClusterExternalSecret against a cloud-backed store is still
appropriate for small namespace sets or when per-namespace refresh isolation
is intentional. This is a recommendation for minimizing provider load, not
a deprecation of the simpler pattern shown above.
Synchronizing corresponding ExternalSecrets
Regular refreshes can be controlled using the refreshPolicy and
refreshInterval fields. Adhoc synchronizations can be triggered by
setting, updating or deleting the annotation external-secrets.io/force-sync
on the ClusterExternalSecret:
kubectl annotate ces my-ces external-secrets.io/force-sync=$(date +%s) --overwrite
Changes to this annotation will be synchronized to all ExternalSecrets owned by the ClusterExternalSecret.
Deprecations
namespaceSelector
The field namespaceSelector has been deprecated in favor of namespaceSelectors and will be removed in a future
version.