---
title: External Secrets Operator CRD
version: v1alpha1
authors: all of us
creation-date: 2020-09-01
status: accepted
---
This is a proposal to standardize the External Secrets operator CRDs in an combined effort through all projects that deal with syncing external secrets. This proposal aims to do find the common denominator for all users of an External Secrets project.
There are a lot of different projects in the wild that essentially do the same thing: sync secrets with Kubernetes. The idea is to unify efforts into a single project that serves the needs of all users in this problem space.
As a starting point I (@moolen) would like to define a common denominator for a Custom Resource Definition that serves all known use-cases. This CRD should follow the standard alpha -> beta -> GA feature process.
Once the CRD API is defined we can move on with more delicate discussions about technology, organization and processes.
List of Projects known so far or related:
This KEP proposes the CRD Spec and documents the use-cases, not the choice of technology or migration path towards implementing the CRD.
We do not want to sync secrets into a ConfigMap.
ESO: A Application that runs a control loop which syncs secretsinstance: A single entity that runs a control loopST: A Custom Resource to authenticate and configure the connection between the ESO instance and the ProviderES: A Custom Resource that declares which secrets should be syncedSecret resourceoperator := I manage one or multiple ESO instancesuser := I only create ES, ESO is managed by someone elseFrom that we can derive the following requirements or user stories:
Secret resourceiam.amazonaws.com/permitted annotation per namespace)These providers are relevant for the project:
The ExternalSecret Custom Resource Definition is namespaced. It defines the following:
SecretStore)apiVersion: external-secrets.io/v1alpha1
kind: ExternalSecret
metadata: {...}
spec:
# SecretStoreRef defines which SecretStore to fetch the ExternalSecret data
secretStoreRef:
name: secret-store-name
kind: SecretStore # or ClusterSecretStore
# 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"
# There can only be one target per ES
target:
# The secret name of the resource
# Defaults to .metadata.name of the ExternalSecret
# It is immutable
name: my-secret
# Enum with values: 'Owner', 'Merge', or 'None'
# Default value of 'Owner'
# Owner creates the secret and sets .metadata.ownerReferences of the resource
# Merge does not create the secret, but merges in the data fields to the secret
# None does not create a secret (future use with injector)
creationPolicy: 'Merge'
# 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: |
endpoints:
- https://{{ .data.user }}:{{ .data.password }}@api.example.com
# 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: alertmanager
items:
- key: alertmanager.yaml
# Data defines the connection between the Kubernetes Secret keys and the Provider data
data:
- secretKey: secret-key-to-be-managed
remoteRef:
key: provider-key
version: provider-key-version
property: provider-key-property
# Used to fetch all properties from the Provider key
# If multiple dataFrom are specified, secrets are merged in the specified order
dataFrom:
- key: provider-key
version: provider-key-version
property: provider-key-property
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"
# servicebinding.io Provisioned Service reference to the secret
binding:
name: my-secret
The ExternalSecret control loop ensures that the target resource exists and stays up to date with the upstream provider. Because most upstream APIs are limited in throughput the control loop must implement some sort of jitter and retry/backoff mechanic.
The store configuration in an ExternalSecret may contain a lot of redundancy, this can be factored out into its own CRD.
These stores are defined in a particular namespace using SecretStore or globally with ClusterSecretStore.
apiVersion: external-secrets.io/v1alpha1
kind: SecretStore # or ClusterSecretStore
metadata:
name: vault
namespace: example-ns
spec:
# Used to select the correct ESO controller (think: ingress.ingressClassName)
# The ESO controller is instantiated with a specific controller name and filters ES based on this property
# Optional
controller: dev
# provider field contains the configuration to access the provider which contains the secret
# exactly one provider must be configured.
provider:
# AWS configures this store to sync secrets using AWS
aws:
# service defines what API should be used to fetch secrets
service: SecretsManager # or ParameterStore
# Auth defines the information necessary to authenticate against AWS by
# getting the accessKeyID and secretAccessKey from an already created Kubernetes Secret
auth:
secretRef:
accessKeyID:
name: awssm-secret
key: access-key
secretAccessKey:
name: awssm-secret
key: secret-access-key
# Role is a Role ARN which the SecretManager provider will assume
role: iam-role
# AWS Region to be used for the provider
region: eu-central-1
# AzureKV configures this store to sync secrets using Azure Key-Vault provider
azurekv:
# Auth defines the information necessary to authenticate against Azure
auth:
# The Azure Tenant to send requests to.
tenantId: 4be10619-c5d4-4032-bd6a-a697cb365a4a
# The Service-Princpal's clientID and clientSecret from an already created Kubernetes Secret
servicePrincipalSecretRef:
clientId:
name: azurekv-sp-secret
key: client-id
clientSecret:
name: azurekv-sp-secret
key: client-secret
# The URI to that KeyVault instance, as found in the Azure Portal & the az CLI output
vaultUri: https://my-vault09.vault.azure.net/
status:
# Standard condition schema
conditions:
# SecretStore ready condition indicates the given store is in ready
# state and able to referenced by ExternalSecrets
# If the `status` of this condition is `False`, ExternalSecret controllers
# should prevent attempts to fetch secrets
- type: Ready
status: "False"
reason: "ConfigError"
message: "SecretStore validation failed"
lastTransitionTime: "2019-08-12T12:33:02Z"
SecretStore with a certain spec.controllerExternalSecret if it matches the controller fieldWe have a bunch of features which are not relevant for the MVP implementation. We keep the features here in this backlog. Order is not specific: