Skip to content
This repository was archived by the owner on May 1, 2021. It is now read-only.

Commit 2f74887

Browse files
committed
1 parent 2187c60 commit 2f74887

File tree

2 files changed

+278
-0
lines changed

2 files changed

+278
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# CRD Spec
2+
3+
This repository contains the specification of the external-secrets CRD.
4+
5+
Find the [Spec here](./Spec.md). For the history of it see [#47](https://github.com/external-secrets/kubernetes-external-secrets/issues/47) and [#477](https://github.com/external-secrets/kubernetes-external-secrets/issues/477).
6+

Spec.md

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
```yaml
2+
---
3+
title: Standardize ExternalSecret CRD
4+
authors: all of us
5+
creation-date: 2020-09-01
6+
status: draft
7+
---
8+
```
9+
10+
# Standardize ExternalSecret CRD
11+
12+
## Table of Contents
13+
14+
<!-- toc -->
15+
- [Summary](#summary)
16+
- [Motivation](#motivation)
17+
- [Goals](#goals)
18+
- [Non-Goals](#non-goals)
19+
- [Terminology](#terminology)
20+
- [Use-Cases](#use-cases)
21+
- [Proposal](#proposal)
22+
- [API](#api)
23+
- [Alternatives](#alternatives)
24+
<!-- /toc -->
25+
26+
## Summary
27+
28+
This is a proposal to standardize the `ExternalSecret` CRD 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 `ExternalSecrets`.
29+
30+
## Motivation
31+
32+
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.
33+
34+
As a starting point i would like to define a **common denominator** for a CustomResourceDefinition that serves all known use-cases. This CRD should follow the standard alpha -> beta -> GA feature process.
35+
36+
Once the CRD API is defined we can move on with more delicate discussions about technology, organization and processes.
37+
38+
List of Projects known so far or related:
39+
* https://github.com/godaddy/kubernetes-external-secrets
40+
* https://github.com/itscontained/secret-manager
41+
* https://github.com/ContainerSolutions/externalsecret-operator
42+
* https://github.com/mumoshu/aws-secret-operator
43+
* https://github.com/cmattoon/aws-ssm
44+
* https://github.com/tuenti/secrets-manager
45+
* https://github.com/kubernetes-sigs/k8s-gsm-tools
46+
47+
### Goals
48+
49+
- Define a alpha CRD
50+
- Fully document the Spec and use-cases
51+
52+
### Non-Goals
53+
54+
This KEP proposes the CRD Spec and documents the use-cases, not the choice of technology or migration path towards implementing the CRD.
55+
56+
We do not want to sync secrets into a `ConfigMap`.
57+
58+
## Terminology
59+
60+
* Kubernetes External Secrets `KES`: A Application that runs a control loop which syncs secrets
61+
* KES `instance`: A single entity that runs a control loop.
62+
* ExternalSecret `ES`: A CustomResource that declares which secrets should be synced
63+
* Store: Is a **source** for secrets. The Store is external to KES. It can be a hosted service like Alibabacloud SecretsManager, AWS SystemsManager, Azure KeyVault...
64+
* Frontend: A **sink** for the synced secrets. Usually a `Secret`
65+
* Secret: credentials that act as a key to sensitive information
66+
67+
## Use-Cases
68+
* one global KES instance that manages ES in **all namespaces**, which gives access to **all stores**, with ACL
69+
* multiple global KES instances, each manages access to a single or multiple stores (e.g.: shard by stage or team...)
70+
* one KES per namespace (a user manages his/her own KES instance)
71+
72+
### User definitions
73+
* `operator :=` i manage one or multiple `KES` instances
74+
* `user :=` i only create `ES`, KES is managed by someone else
75+
76+
### User Stories
77+
From that we can derive the following requirements or user-stories:
78+
1. AS a KES operator i want to run multiple KES instances per cluster (e.g. one KES instance per DEV/PROD)
79+
2. AS a KES operator or user i want to integrate **multiple stores** from a **single KES instance** (e.g. dev namespace has access only to dev secrets)
80+
3. AS a KES user i want to control the sink for the secrets (aka frontend: store secret as `kind=Secret`)
81+
4. AS a KES user i want to fetch **from multiple** stores and store the secrets **in a single** Frontend
82+
5. AS a KES operator i want to limit the access to certain stores or subresources (e.g. having one central KES instance that handles all ES - similar to `iam.amazonaws.com/permitted` annotation per namespace)
83+
4. AS a KES user i want to provide an application with a configuration that contains a secret
84+
85+
### Stores
86+
87+
These stores are relevant:
88+
* AWS Secure Systems Manager Parameter Store
89+
* AWS Secrets Manager
90+
* Hashicorp Vault
91+
* Azure Key Vault
92+
* Alibaba Cloud KMS Secret Manager
93+
* Google Cloud Platform Secret Manager
94+
* Kubernetes (see #422)
95+
* noop (see #476)
96+
97+
### Frontends
98+
99+
* Kind=Secret
100+
* *potentially* we could sync store to store
101+
102+
## Proposal
103+
104+
### API
105+
106+
### External Secret
107+
108+
The `ExternalSecret` CustomResourceDefinition is **namespaced**. It defines the following:
109+
1. source for the secret (store)
110+
2. sink for the secret (fronted)
111+
3. and a mapping to translate the keys
112+
113+
```yaml
114+
apiVersion: external-secrets.k8s.io/v1alpha1
115+
kind: ExternalSecret
116+
metadata: {...}
117+
118+
spec:
119+
120+
# the amount of time before the values will be read again from the store
121+
# may be set to zero to fetch and create it once
122+
refreshInterval: "1h"
123+
124+
# there can only be one target per ES
125+
target:
126+
# The secret name of the resource
127+
# defaults to .metadata.name of the ExternalSecret. immutable.
128+
name: my-secret
129+
130+
# Enum with values: 'Owner', 'Merge', or 'None'
131+
# Default value of 'Owner'
132+
# Owner creates the secret and sets .metadata.ownerReferences of the resource
133+
# Merge does not create the secret, but merges in the data fields to the secret
134+
# None does not create a secret (future use with injector)
135+
creationPolicy: 'Merge'
136+
137+
# specify a blueprint for the resulting Kind=Secret
138+
template:
139+
type: kubernetes.io/dockerconfigjson # or TLS...
140+
141+
metadata:
142+
annotations: {}
143+
labels: {}
144+
145+
# use inline templates to construct your desired config file that contains your secret
146+
data:
147+
config.yml: |
148+
endpoints:
149+
- https://{{ .data.user }}:{{ .data.password }}@api.exmaple.com
150+
151+
# Uses an existing template from configmap
152+
# secret is fetched, merged and templated within the referenced configMap data
153+
# It does not update the configmap, it creates a secret with: data["alertmanager.yml"] = ...result...
154+
templateFrom:
155+
- configMap:
156+
name: alertmanager
157+
items:
158+
- key: alertmanager.yaml
159+
160+
# data contains key/value pairs which correspond to the keys in the resulting secret
161+
data:
162+
163+
# EXAMPLE 1: simple mapping
164+
# one key from a store may hold multiple values
165+
# we need a way to map the values to the frontend
166+
# it is the responsibility of the store implementation to know how to extract a value
167+
tls.crt:
168+
key: /corp.org/dev/certs/ingress
169+
property: pubcert
170+
tls.key:
171+
key: /corp.org/dev/certs/ingress
172+
property: privkey
173+
174+
# used to fetch all properties from a secret.
175+
# if multiple dataFrom are specified, secrets are merged in the specified order
176+
dataFrom:
177+
- key: /user/all-creds
178+
179+
status:
180+
# represents the current phase of secret sync:
181+
# * Pending | ES created, controller did not yet sync the ES or other dependencies are missing (e.g. secret store or configmap template)
182+
# * Syncing | ES is being actively synced according to spec
183+
# * Failing | Secret can not be synced, this might require user intervention
184+
# * Failed | ES can not be synced right now and will not able to
185+
# * Completed | ES was synced successfully (one-time use only)
186+
phase: Syncing
187+
conditions:
188+
- type: InSync
189+
status: "True" # False if last sync was not successful
190+
reason: "SecretSynced"
191+
message: "Secret was synced"
192+
lastTransitionTime: "2019-08-12T12:33:02Z"
193+
lastSyncTime: "2020-09-23T16:27:53Z"
194+
195+
```
196+
197+
#### Behavior
198+
199+
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.
200+
201+
### External Secret Store
202+
203+
The store configuration in an `ExternalSecret` may contain a lot of redundancy, this can be factored out into its own CRD.
204+
These stores are defined in a particular namespace using `SecretStore` **or** globally with `GlobalSecretStore`.
205+
206+
```yaml
207+
apiVerson: external-secrets.k8s.io/v1alpha1
208+
kind: SecretStore # or ClusterSecretStore
209+
metadata:
210+
name: vault
211+
namespace: example-ns
212+
spec:
213+
214+
# optional.
215+
# used to select the correct KES controller (think: ingress.ingressClassName)
216+
# The KES controller is instantiated with a specific controller name
217+
# and filters ES based on this property
218+
controller: "dev"
219+
220+
store:
221+
type: vault
222+
parameters: # provider specific k/v pairs
223+
server: "https://vault.example.com"
224+
path: path/on/vault/store
225+
auth: {} # provider specific k/v pairs
226+
227+
status:
228+
# * Pending: e.g. referenced secret containing credentials is missing
229+
# * Running: all dependencies are met, sync
230+
phase: Running
231+
conditions:
232+
- type: Ready
233+
status: "False"
234+
reason: "ErrorConfig"
235+
message: "Unable to assume role arn:xxxx"
236+
lastTransitionTime: "2019-08-12T12:33:02Z"
237+
```
238+
239+
Example Secret that uses the reference to a store
240+
```yaml
241+
apiVersion: external-secrets.k8s.io/v1alpha1
242+
kind: ExternalSecret
243+
metadata:
244+
name: foo
245+
spec:
246+
storeRef:
247+
kind: SecretStore # ClusterSecretStore
248+
name: my-store
249+
target:
250+
name: my-secret
251+
template:
252+
type: kubernetes.io/TLS
253+
data:
254+
tls.crt:
255+
key: /corp.org/dev/certs/ingress
256+
property: pubcert
257+
tls.key:
258+
key: /corp.org/dev/certs/ingress
259+
property: privkey
260+
```
261+
262+
Workflow in a KES instance:
263+
1. A user creates a Store with a certain `spec.controller`
264+
2. A controller picks up the `ExternalSecret` if it matches the `controller` field
265+
3. The controller fetches the secret from the provider and stores it as kind=Secret in the same namespace as ES
266+
267+
268+
## Backlog
269+
270+
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:
271+
272+
1. Secret injection with a mutating Webhook [#81](https://github.com/godaddy/kubernetes-external-secrets/issues/81)

0 commit comments

Comments
 (0)