Sealed Secrets in Kubernetes
GitOps advocates managing all your configuration through Git. In Kubernetes, we can manage resources inside the cluster using manifest files. The Secret
is used to help us store sensitive information, such as SSH Key, docker registry credentials. Developers can then easily reference the Secrets inside the manifest files without having to hard-code it directly. However, it is not good to manage Secret
inside a git repository. It is not secure as Kubernetes only encode the sensitive information with base64. We can quickly obtain the Secret by running
kubectl get secret secretname --output="jsonpath={.data.valuename}" | base64 --decode
Therefore, Bitnami Labs create a project called Sealed Secrets to solve this problem.
What is Sealed Secrets does?
Encrypt your Secret into a SealedSecret, which is safe to store - even to a public repository. The SealedSecret can be decrypted only by the controller running in the target cluster and nobody else (not even the original author) is able to obtain the original Secret from the SealedSecret.
How it works?
Sealed Secrets have two main components to make it works.
- A controller deployed in the cluster
- A client-side command-line tools:
kubeseal
kubeseal
uses RSA 4096 to encrypt Kubernetes Secret
, and SealedSecret
is a CRD (Custom Resource Definition) containing an encrypted Secret
that only the controller itself can decrypt. Therefore, it is safe to store the SealedSecret
in a public repository. I made a simple illustration to show how kubeseal
works:
Installation
You can checkout that latest release in their GitHub repository
Install SealedSecret Controller (Cluster Side)
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.16.0/controller.yaml
Install kubeseal
(Client Side)
# MacOS
brew install kubeseal
# Linux
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.16.0/kubeseal-linux-amd64 -O kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubeseal
Creating a Secret
To create a SealedSecret
, we need to first create a Secret
.
echo -n "Hello, World!" | kubectl create secret generic mysecret --dry-run --from-file=secret=/dev/stdin -o yaml > secret.yaml
It will create a secret.yaml
like this:
apiVersion: v1
data:
secret: SGVsbG8sIFdvcmxkIQ==
kind: Secret
metadata:
creationTimestamp: null
name: mysecret
We know that the secret is base64 encoded. So let’s try to decode the secret.
echo "SGVsbG8sIFdvcmxkIQ==" | base64 --decode
# Output: Hello, World!
Then create a SealedSecret
.
kubeseal --format yaml <secret.yaml >sealedsecret.yaml
It will create a sealedsecret.yaml
like this:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
creationTimestamp: null
name: mysecret
namespace: default
spec:
encryptedData:
secret: AgBiK....oSKfg
template:
data: null
metadata:
creationTimestamp: null
name: mysecret
namespace: default
Now apply the sealedsecret.yaml
.
kubectl apply -f sealedsecret.yaml
Now let’s create a busybox pod to test the SealedSecret
.
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
containers:
- name: testbox
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts:
- name: mysecretvol
mountPath: "/tmp/mysecret"
readOnly: true
volumes:
- name: mysecretvol
secret:
secretName: mysecret
Apply the busybox.yaml
and see if the secret is correct.
kubectl apply -f busybox.yaml
kubectl exec -it busybox -- cat /tmp/mysecret/secret
# Output: Hello, World!
You can see Hello, World!
printed. That means the SealedSecret
is working correctly. Now, remove the test secret and pods by running:
kubectl delete -f busybox.yaml -f sealedsecret.yaml
Resources
Sealed Secrets GitHub repository
AWS Open Source Blog: Managing secrets deployment in Kubernetes using Sealed Secrets