Kubernetes ConfigMaps and Secrets are both key:value maps, but the latter is intended to signal that its values have a sensitive nature - e.g. pass phrases or ssh keys.
Kubernetes developers work in various ways to hide the information in a Secret more carefully than the information held by ConfigMaps, Deployments, etc.
DEMO_HOME=$(mktemp -d)
kustomize has three different (builtin) ways to generate a secret from local files:
- get them from so-called env files (
NAME=VALUE
, one per line), - consume the entire contents of a file to make one secret value,
- get literal values from the kustomization file itself.
Here's an example combining all three methods:
Make an env file with some short secrets:
cat <<'EOF' >$DEMO_HOME/foo.env
ROUTER_PASSWORD=admin
DB_PASSWORD=iloveyou
EOF
Make a text file with a long secret:
cat <<'EOF' >$DEMO_HOME/longsecret.txt
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
EOF
And make a kustomization file referring to the above and additionally defining some literal KV pairs in line:
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
secretGenerator:
- name: mysecrets
envs:
- foo.env
files:
- longsecret.txt
literals:
- FRUIT=apple
- VEGETABLE=carrot
EOF
Now generate the Secret:
result=$(kustomize build $DEMO_HOME)
echo "$result"
# Spot check the result:
test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=")
This emits something like
apiVersion: v1 kind: Secret metadata: name: mysecrets-hfb5df789h type: Opaque data: FRUIT: YXBwbGU= VEGETABLE: Y2Fycm90 ROUTER_PASSWORD: YWRtaW4= DB_PASSWORD: aWxvdmV5b3U= longsecret.txt: TG9yZW0gaXBzdW0gZG9sb3Igc2l0I... (elided)
The name of the resource is the prefix mysecrets
(as specfied in the kustomization file), followed
by a hash of its contents.
Use your favorite base64 decoder to confirm the raw versions of any of these values.
The problem that these three approaches share is that the purported secrets must live on disk.
This adds additional security questions - who can see the files, who installs them, who deletes them, etc.
A general alternative is to enshrine secret value generation in a plugin.
The values can then come in via, say, an authenticated and authorized RPC to a password vault service.
Here's a secret generator plugin that pretends to pull the values of a map from a database.
Download it
repo=https://raw.githubusercontent.com/kubernetes-sigs/kustomize
pPath=plugin/someteam.example.com/v1/secretsfromdatabase
dir=$DEMO_HOME/kustomize/$pPath
mkdir -p $dir
curl -s -o $dir/SecretsFromDatabase.go \
${repo}/master/$pPath/SecretsFromDatabase.go
Compile it
go build -buildmode plugin \
-o $dir/SecretsFromDatabase.so \
$dir/SecretsFromDatabase.go
Create a configuration file for it:
cat <<'EOF' >$DEMO_HOME/secretFromDb.yaml
apiVersion: someteam.example.com/v1
kind: SecretsFromDatabase
metadata:
name: mySecretGenerator
name: forbiddenValues
namespace: production
keys:
- ROCKET
- VEGETABLE
EOF
Create a new kustomization file referencing this plugin:
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
generators:
- secretFromDb.yaml
EOF
Finally, generate the secret, setting
XDG_CONFIG_HOME
so that the plugin
can be found under $DEMO_HOME
:
result=$( \
XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build --enable_alpha_plugins $DEMO_HOME )
echo "$result"
# Spot check the result:
test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=")
This should emit something like:
apiVersion: v1 kind: Secret metadata: name: mysecrets-bdt27dbkd6 type: Opaque data: FRUIT: YXBwbGU= VEGETABLE: Y2Fycm90
i.e. a subset of the same values as above.