Skip to content

Instantly share code, notes, and snippets.

@foogunlana
Last active April 8, 2024 08:28
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save foogunlana/b75175b4ff62bc07258ea78274c698cd to your computer and use it in GitHub Desktop.
Save foogunlana/b75175b4ff62bc07258ea78274c698cd to your computer and use it in GitHub Desktop.
Helm + Sealed secrets
I had a bit of trouble figuring out how to use bitnami's [sealed secrets](https://github.com/bitnami-labs/sealed-secrets) with [helm](https://helm.sh)
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 ->
```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 ->
```yml
...
env:
...
NODE_ENV: production
AWS_BUCKET: xyz
```
./env/ci.secrets.yml ->
```yml
...
AWS_ACCESS_KEY_ID: abc123
AWS_SECRET_ACCESS_KEY: xyz
```
Pre-commit hook ->
```bash
#!/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
```yml
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!
@MaxWinterstein
Copy link

Thx! Might add the .md extension, so markup will get parsed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment