Kubernetes External Secrets allows you to use external secret management systems (e.g., AWS Secrets Manager) to securely add secrets in Kubernetes. Read more about the design and motivation for Kubernetes External Secrets on the GoDaddy Engineering Blog.
The project extends the Kubernetes API by adding a ExternalSecrets
object using Custom Resource Definition and a controller to implement the behavior of the object itself.
An ExternalSecret
declares how to fetch the secret data, while the controller converts all ExternalSecrets
to Secrets
.
The conversion is completely transparent to Pods
that can access Secrets
normally.
ExternalSecrets
are added in the cluster (e.g.,kubectl apply -f external-secret-example.yml
)- Controller fetches
ExternalSecrets
using the Kubernetes API - Controller uses
ExternalSecrets
to fetch secret data from external providers (e.g, AWS Secrets Manager) - Controller upsert
Secrets
Pods
can accessSecrets
normally
Alternatively, the included charts/kubernetes-external-secrets can be used to create the kubernetes-external-secrets
resources and Deployment
on a Kubernetes cluster using the Helm package manager.
helm install --name kubernetes-external-secrets \
--set env.AWS_REGION='<aws-region>' \
charts/kubernetes-external-secrets
Tip: A namespace can be specified by the
Helm
option '--namespace kube-external-secrets
'
To uninstall/delete the kubernetes-external-secrets
deployment:
helm delete kubernetes-external-secrets
The following table lists the configurable parameters of the kubernetes-external-secrets
chart and their default values.
Parameter | Description | Default |
---|---|---|
env.AWS_REGION |
Set AWS_REGION in Deployment Pod | us-west-2 |
env.POLLER_INTERVAL_MILLISECONDS |
Set POLLER_INTERVAL_MILLISECONDS in Deployment Pod | 10000 |
envVarsFromSecret.AWS_ACCESS_KEY_ID |
Set AWS_ACCESS_KEY_ID (from a secret) in Deployment Pod | |
envVarsFromSecret.AWS_SECRET_ACCESS_KEY |
Set AWS_SECRET_ACCESS_KEY (from a secret) in Deployment Pod | |
image.repository |
kubernetes-external-secrets Image name | godaddy/kubernetes-external-secrets |
image.tag |
kubernetes-external-secrets Image tag | 1.2.0 |
image.pullPolicy |
Image pull policy | IfNotPresent |
rbac.create |
Create & use RBAC resources | true |
serviceAccount.create |
Whether a new service account name should be created. | true |
serviceAccount.name |
Service account to be used. | automatically generated |
podAnnotations |
Annotations to be added to pods | {} |
replicaCount |
Number of replicas | 1 |
nodeSelector |
node labels for pod assignment | {} |
tolerations |
List of node taints to tolerate (requires Kubernetes >= 1.6) | [] |
affinity |
Affinity for pod assignment | {} |
resources |
Pod resource requests & limits | {} |
Specify each parameter using the --set key=value[,key=value]
argument to helm install
. For example,
helm install --name kubernetes-external-secrets \
--set env.POLLER_INTERVAL_MILLISECONDS='300000' \
--set podAnnotations."iam\.amazonaws\.com/role"='Name-Of-IAM-Role-With-SecretManager-Access' \
charts/kubernetes-external-secrets
If not running on EKS you will have to use an IAM user (in lieu of a role). Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env vars in the session/pod. You can use envVarsFromSecret in the helm chart to create these env vars from existing k8s secrets
Add your secret data to your backend. For example, AWS Secrets Manager:
aws secretsmanager create-secret --name hello-service/password --secret-string "1234"
AWS Parameter Store:
aws ssm put-parameter --name "/hello-service/password" --type "String" --value "1234"
and then create a hello-service-external-secret.yml
file:
apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
name: hello-service
secretDescriptor:
backendType: secretsManager
data:
- key: hello-service/password
name: password
or
apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
name: hello-service
secretDescriptor:
backendType: systemManager
data:
- key: /hello-service/password
name: password
Save the file and run:
kubectl apply -f hello-service-external-secret.yml
Wait a few minutes and verify that the associated Secret
has been created:
kubectl get secret hello-service -o=yaml
The Secret
created by the controller should look like:
apiVersion: v1
kind: Secret
metadata:
name: hello-service
type: Opaque
data:
password: MTIzNA==
kubernetes-external-secrets supports only AWS Secrets Manager.
kubernetes-external-secrets supports both JSON objects ("Secret key/value" in the AWS console) or strings ("Plaintext" in the AWS console). Using JSON objects is useful when you need to atomically update multiple values. For example, when rotating a client certificate and private key.
When writing an ExternalSecret for a JSON object you must specify the properties to use. For example, if we add our hello-service credentials as a single JSON object:
aws secretsmanager create-secret --region us-west-2 --name hello-service/credentials --secret-string '{"username":"admin","password":"1234"}'
We can declare which properties we want from hello-service/credentials:
apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
name: hello-service
secretDescriptor:
backendType: secretsManager
data:
- key: hello-service/credentials
name: password
property: password
- key: hello-service/credentials
name: username
property: username
Minikube is a tool that makes it easy to run a Kubernetes cluster locally.
Start minikube and the daemon. This creates the CustomerResourceDefinition
, and starts to process ExternalSecrets
:
minikube start
npm run nodemon
Localstack mocks AWS services locally so you can test without connecting to AWS.
Run localstack in a seperate terminal window
npm run localstack
Start minikube as above
minikube start
Run the daemon with localstack
npm run local
Add secrets using the AWS cli (example)
aws --endpoint-url=http://localhost:4584 secretsmanager create-secret --name hello-service/password --secret-string "1234"