I had a bit of trouble figuring out how to use bitnami's sealed secrets with helm
Here's a definition of done to help you see what I was trying to achieve.
Definition of done
- Single secret available for a release in a namespace, listing all secret variables
- Regular helm workflow, with no extra kubeseal commands for developers
- Encrypted secrets clearly visible in git
- Sealedsecret managed by helm
After much suffering, here's what I came up with. A pre-commit hook that creates the single sealedsecret in my chart. It took me a while, so I thought I should share in case someone can improve it.
app/templates/sealedsecret.yml ->
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: {{ include "app.fullname" . }}
labels:
...
spec:
encryptedData:
{{- range $key, $val := .Values.secret }}
{{ $key }}: {{ $val | quote }}
{{- end }}
./env/ci.values.yml ->
...
env:
...
NODE_ENV: production
AWS_BUCKET: xyz
./env/ci.secrets.yml ->
...
AWS_ACCESS_KEY_ID: abc123
AWS_SECRET_ACCESS_KEY: xyz
Pre-commit hook ->
#!/bin/bash
# use bash, as echo -n does not work in #!/bin/sh
# dependencies
# - yq : read secrets.yml
# - kubeseal : encrypt secrets with kubernetes cluster sealed secrets public key
set -e
encrypt() {
# the full name of the app - {release}-{chart} or just {release}
fullname="YOUR APP FULL NAME"
# the top level yaml key for secrets in the values.yml file
secret_prefix="secret"
# the name and namespace of the sealed secrets controller after installation to the cluster
controller_name="sealed-secrets"
controller_namespace="default"
# find namespace specific values and secrets files, and a temporary file for storing intermediate values
namespace=${1}
secrets_file=${GIT_DIR:-$PWD}/env/${namespace}.secrets.yml
values_file=${GIT_DIR:-$PWD}/env/${namespace}.values.yml
tmp_secret_file=${GIT_DIR:-$PWD}/env/tmpsecretfile
if [[ ! -f "$secrets_file" ]]; then
echo "No secrets to encrypt in $secrets. Skipping..."
return
fi
# get all secret key names
keys=$(yq r -j $secrets_file | jq -r 'keys[]')
# count keys, and strip whitespace
nkeys=$(wc -w <<<$keys | sed 's/ //g')
echo "Encrypting $nkeys secrets from $secrets..."
# we will write each key to the values file
for key in $keys; do
# echo with -n to file first, otherwise you might have a trailing new line in your decrypted value
echo -n $(yq r $secrets_file $key) >${tmp_secret_file}
# --name should match the name of the sealedsecret (data-platform.fullname from _helpers.tpl)
encrypted=$(kubeseal --raw --name=${fullname} --namespace=${namespace} --from-file=${tmp_secret_file} --controller-name=${controller_name} --controller-namespace=${controller_namespace})
rm ${tmp_secret_file}
# write the secret to the values file
yq w -i $values_file "$secret_prefix.$key" $encrypted
done
echo "Successfully wrote ciphertext to $values."
}
encrypt ci
encrypt qa
encrypt prod
git add env
The folder structure is as follows: app/templates/sealedsecret.yml env/ci.values.yml env/ci.secrets.yml
After running git commit
, the env/ci.values.yml
file is now as follows
env:
...
NODE_ENV: production
AWS_BUCKET: xyz
secret:
AWS_ACCESS_KEY_ID: ...encrypted data
AWS_SECRET_ACCESS_KEY: ...encrypted data
Make sure to add env/*.secrets.yml to your .gitignore!