* Added draft for SecretSink Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * Fixing typo and adding more comments Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * Dedicating new CRD to SecretSink Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * Redoing secretSink proposal Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * Moved selector to spec level. Removed secretStore selector from remoteRef Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * Update wording on design/001-secretsink.md Co-authored-by: Moritz Johner <moolen@users.noreply.github.com> Co-authored-by: Moritz Johner <moolen@users.noreply.github.com>
6.2 KiB
---
title: SecretSink
version: v1alpha1
authors:
creation-date: 2022-01-25
status: draft
---
Secret Sink
Table of Contents
// autogen please
Summary
The Secret Sink is a feature to allow Secrets from Kubernetes to be saved back into some providers. Where ExternalSecret is responsible to download a Secret from a Provider into Kubernetes (as a K8s Secret), SecretSink will upload a Kubernetes Secret to a Provider.
Motivation
Secret Sink allows some inCluster generated secrets to also be available on a given secret provider. It also allows multiple Providers having the same secret (which means a way to perform failover in case a given secret provider is on downtime or compromised for whatever the reason).
Goals
- CRD Design for the SecretSink
- Define the need for a SinkStore
Non-Goals
Do not implement full compatibility mechanisms with each provider (we are not Terraform neither Crossplane)
Terminology
- Sink object: any Secret (a part or the whole secret) from Kubernetes that is going to be uploaded to a Provider.
Proposal
A controller that checks for Sink Objects, gets K8s Secrets and creates the equivalent secret on the SecretStore Provider.
User Stories
- As an ESO Operator I want to be able to Sync Secrets in my cluster with my External Provider
- As an ESO Operator I want to be able to Sync Secrets even if they are not bound to a given ExternalSecret
API
Proposed CRD changes:
apiVersion: external-secrets.io/v1alpha1
kind: SecretStore
metadata:
name: example
namespace: example-ns
spec:
controller: dev
retrySettings:
maxRetries: 5
retryInterval: "10s"
provider:
aws:
service: SecretsManager
role: iam-role
region: eu-central-1
encryptionConfig: {} # Specific config for Creating Secrets on AWS
auth:
secretRef:
accessKeyID:
name: awssm-secret
key: access-key
secretAccessKey:
name: awssm-secret
key: secret-access-key
vault:
server: "https://vault.acme.org"
path: "secret"
version: "v2"
encryptionConfig: {} # Specific config for Creating Secrets on Vault ()
namespace: "a-team"
caBundle: "..."
caProvider:
type: "Secret"
name: "my-cert-secret"
key: "cert-key"
auth:
tokenSecretRef:
name: "my-secret"
namespace: "secret-admin"
key: "vault-token"
appRole:
path: "approle"
roleId: "db02de05-fa39-4855-059b-67221c5c2f63"
secretRef:
name: "my-secret"
namespace: "secret-admin"
key: "vault-token"
kubernetes:
mountPath: "kubernetes"
role: "demo"
serviceAccountRef:
name: "my-sa"
namespace: "secret-admin"
secretRef:
name: "my-secret"
namespace: "secret-admin"
key: "vault"
gcpsm:
encryptionConfig: {} # Specific config for Creating Secrets GCP SM
auth:
secretRef:
secretAccessKeySecretRef:
name: gcpsm-secret
key: secret-access-credentials
projectID: myproject
apiVersion: external-secrets.io/v1alpha1
kind: SecretSink
metadata:
name: "hello-world"
namespace: my-ns # Same of the SecretStores
spec:
secretStoreRefs:
- name: secret-store
kind: SecretStore
- name: secret-store-2
kind: SecretStore
- name: cluster-secret-store
kind: ClusterSecretStore
refreshInterval: "1h"
selector:
secret:
name: foobar
data:
match:
- secretKey: foobar
remoteRefs:
- remoteKey: my/path/foobar
property: my-property #optional. To allow coming back from a 'dataFrom'
- remoteKey: secret/my-path-foobar
property: another-property
rewrite:
- secretKey: game-(.+).(.+)
remoteRefs:
- remoteKey: my/path/($1)
property: prop-($2)
- remoteKey: my-path-($1)-($2) #Applies this way to all other secretStores
status:
refreshTime: "2019-08-12T12:33:02Z"
conditions:
- type: Ready
status: "True"
reason: "SecretSynced"
message: "Secret was synced" #Fully synced
lastTransitionTime: "2019-08-12T12:33:02Z"
- type: Ready
status: "True"
reason: "SecretSyncError"
message: "Secret sync failed to Sink SecretStore: abc"
lastTransitionTime: "2019-08-12T12:33:02Z"
- type: Ready
status: "False"
reason: "SecretSyncError"
message: "Secret sync failed to Sink SecretStore: abc, def"
lastTransitionTime: "2019-08-12T12:33:02Z"
Behavior
When checking SecretSink for the Source Secret, check existing labels for SecretStore reference of that particular Secret. If this SecretStore reference is an object in SecretSink SecretStore lists, a SecretSyncError should be emited as we cannot sync the secret to the same SecretStore.
If the SecretStores are all fine or if the Secret has no labels (secret created by user / another tool), for Each SecretStore, get the SyncState of this store (New, SecretSynced, SecretSyncedErr).
If new Secret, or SecretSynced with refreshInterval expired, get the secret from the secretStore and see if it matches the content of the secrets. If it doesn't match, create a new secret (bumping the version, if possible) within the provider. On errors, emit SecretSyncedErr.
Drawbacks
We had several discussions on how to implement this feature, and it turns out just by typing how many duplicate fields we would have defeated my original issue to have two separate CRDs. The biggest drawback of this solution is that it implies SecretStores to be able to write with no other mechanism available. Also, it might overload the reconciliation loop as we have 1xN secret Syncing, where most of them are actually outside the cluster.
Acceptance Criteria
- ExternalSecrets create appropriate labels on generated Secrets
- SecretSinks can read labels on source Secrets
- SecretSinks cannot have same references to SecretStores
- SecretSinks respect refreshInterval
Alternatives
Using some integration with Crossplane can allow to sync the secrets. Cons is this must be either manual or through some integration that would be an independent project on its own.