Project: external-secrets (Provisioning / Security & Compliance)
File: design-crd-spec.md

```yaml title: External Secrets Operator CRD version: v1alpha1 authors: all of us creation-date: 2020-09-01 status: accepted ``` <!-- toc --> - - - - - - - - - <!-- /toc --> 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: https://github.com/godaddy/kubernetes-external-secrets https://github.com/itscontained/secret-manager https://github.com/ContainerSolutions/externalsecret-operator https://github.com/mumoshu/aws-secret-operator https://github.com/cmattoon/aws-ssm https://github.com/tuenti/secrets-manager https://github.com/kubernetes-sigs/k8s-gsm-tools Define an alpha CRD Fully document the Spec and use-cases 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`. External Secrets Operator `ESO`: A Application that runs a control loop which syncs secrets ESO `instance`: A single entity that runs a control loop Provider: Is a source* for secrets. The Provider is external to ESO. It can be a hosted service like Alibaba Cloud SecretsManager, AWS SystemsManager, Azure KeyVault etc SecretStore `ST`: A Custom Resource to authenticate and configure the connection between the ESO instance and the Provider ExternalSecret `ES`: A Custom Resource that declares which secrets should be synced Frontend: A sink* for the synced secrets, usually a `Secret` resource Secret: Credentials that act as a key to sensitive information One global ESO instance that manages ES in all namespaces, which gives access to all providers*, with ACL Multiple global ESO instances, each manages access to a single or multiple providers (e.g.: shard by stage or team...) One ESO per namespace (a user manages their own ESO instance) `operator :=` I manage one or multiple `ESO` instances `user :=` I only create `ES`, ESO is managed by someone else From that we can derive the following requirements or user stories: As a ESO operator I want to run multiple ESO instances per cluster (e.g. one ESO instance per DEV/PROD) As a ESO operator or user I want to integrate multiple SecretStores with a single ESO instance

dev namespace has access only to dev secrets) As a ESO user I want to control the Frontend for the secrets, usually a `Secret` resource As a ESO user I want to fetch from multiple Providers and store the secrets in a single Frontend As a ESO operator I want to limit the access to certain stores or sub resources (e.g. having one central ESO instance that handles all ES - similar to `iam.amazonaws.com/permitted` annotation per namespace) As a ESO user I want to provide an application with a configuration that contains a secret These providers are relevant for the project: AWS Secure Systems Manager Parameter Store AWS Secrets Manager Hashicorp Vault Azure Key Vault Alibaba Cloud KMS Secret Manager Google Cloud Platform Secret Manager Kubernetes (see ) noop (see ) A Secret Kubernetes resource potentially* we could sync Provider to Provider The `ExternalSecret` Custom Resource Definition is namespaced. It defines the following: Source for the secret (`SecretStore`) Sink for the secret (Fronted) A mapping to translate the keys ```yaml apiVersion: external-secrets.io/v1alpha1 kind: ExternalSecret metadata: {...} spec: secretStoreRef: name: secret-store-name kind: SecretStore # or ClusterSecretStore refreshInterval: "1h" target: name: my-secret creationPolicy: 'Merge' template: type: kubernetes.io/dockerconfigjson # or TLS... 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: refreshTime: "2019-08-12T12:33:02Z" conditions: type: Ready status: "True" # False if last refresh was not successful reason: "SecretSynced" message: "Secret was synced" lastTransitionTime: "2019-08-12T12:33:02Z" 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`. ```yaml apiVersion: external-secrets.io/v1alpha1 kind: SecretStore # or ClusterSecretStore metadata: name: vault namespace: example-ns spec: controller: dev provider: aws: service: SecretsManager # or ParameterStore auth: secretRef: accessKeyID: name: awssm-secret key: access-key secretAccessKey: name: awssm-secret key: secret-access-key role: iam-role region: eu-central-1 azurekv: auth: tenantId: 4be10619-c5d4-4032-bd6a-a697cb365a4a servicePrincipalSecretRef: clientId: name: azurekv-sp-secret key: client-id clientSecret: name: azurekv-sp-secret key: client-secret vaultUri: https://my-vault09.vault.azure.net/ status: conditions: type: Ready status: "False" reason: "ConfigError" message: "SecretStore validation failed" lastTransitionTime: "2019-08-12T12:33:02Z" ``` A user creates a `SecretStore` with a certain `spec.controller` A controller picks up the `ExternalSecret` if it matches the `controller` field The controller fetches the secret from the Provider and stores it as Secret Kubernetes resource in the same namespace as ES We 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: Secret injection with a mutating Webhook