1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
[ConfigMaps]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#configmap-v1-core
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
[Go plugin]: https://golang.org/pkg/plugin
[Secrets]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#secret-v1-core
[base64]: https://tools.ietf.org/html/rfc4648#section-4
[configuration directory]: https://wiki.archlinux.org/index.php/XDG_Base_Directory#Specification
[grpc]: https://grpc.io
[tag]: /../../releases
[v2.0.3]: /../../releases/tag/v2.0.3
[`exec.Command`]: https://golang.org/pkg/os/exec/#Command
# Generating Secrets
## What's a Secret?
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.
## Make a place to work
<!-- @establishBase @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
## Secret values from local files
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:
<!-- @makeEnvFile @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/foo.env
ROUTER_PASSWORD=admin
DB_PASSWORD=iloveyou
EOF
```
Make a text file with a long secret:
<!-- @makeLongSecretFile @testAgainstLatestRelease -->
```
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:
<!-- @makeKustomization1 @testAgainstLatestRelease -->
```
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:
<!-- @build1 @testAgainstLatestRelease -->
```
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.
## Secret values from anywhere
A general alternative is to enshrine secret
value generation in a [plugin](../docs/plugins).
The values can then come in via, say, an
authenticated and authorized RPC to a password
vault service.
[sgp]: ../plugin/someteam.example.com/v1/secretsfromdatabase
Here's a [secret generator plugin][sgp]
that pretends to pull the values of a map
from a database.
Download it
<!-- @copyPlugin @testAgainstLatestRelease -->
```
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
<!-- @compilePlugin @xtest -->
```
go build -buildmode plugin \
-o $dir/SecretsFromDatabase.so \
$dir/SecretsFromDatabase.go
```
Create a configuration file for it:
<!-- @makeConfiguration @testAgainstLatestRelease -->
```
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:
<!-- @makeKustomization2 @testAgainstLatestRelease -->
```
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`:
<!-- @build2 @xtest -->
```
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.
|