In previous parts, we see how to manage our secrets in Git and usable by humans and CI. Right now, we will discover how
to integrate it with Kubernetes, and especially with Kubernetes Secrets.
😊 Naive usage
Since the beginning, Alice
, Bobby
and Devon
are using only *.env
file to store secrets. They have to use them
in a Kubernetes context, to create a secret named app-secret
. The simple (and naive way) to do this is to use
the kubectl
application to create the secret from an env files:
This solution is pretty basic and rely on the capacity of the kubectl
cli to create secret from an *.env
file. The main problem here is the fact we have to generate our secret from the env file. In Kubernetes context, when we have multiple manifests, we like to have the same semantic and organisation, which is simpler to read and debug.
🔒 Sops & YAML
To match the team expectation, Devon
will move to a Kubernetes YAML
format for secrets instead of relying on *.env
files. To do so, he will use the output generated from the previous example and use sops to encrypt it.
The SOPS output is like this:
apiVersion: ENC[AES256_GCM,data:gEA=,iv:2jeZ0y0SEPXZTgrsmYXc7LgPydoPwnKzF4GVqykSw5M=,tag:YzEMrctU19sUIqat+LUFIw==,type:str]
data:
secret: ENC[AES256_GCM,data:uJIDP3yMdFyW/7bnBAU0MJp07xmF0nlh,iv:ardoVW+p9HLNpaWfXOWrevZFdNJqGJvt00jPbkrr7p4=,tag:mB3wqa7kNE7gZ9J87IboNg==,type:str]
kind: ENC[AES256_GCM,data:tu+OHbXI,iv:QfqZeYOkTPTzJ618gh+/zGWPMDBJfjp+GwM8yBZCD+Y=,tag:XrJfNhmyDhOQNncd/uNvxA==,type:str]
metadata:
name: ENC[AES256_GCM,data:X8WMTByIcUrjag==,iv:pQ6xt5DPchrxwXtt98l4mgCixpcpaA2ewST0lAqYY4E=,tag:fqj/1PbzbhjIhRx9Ogitxg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
lastmodified: '2020-06-13T12:21:16Z'
mac: ENC[AES256_GCM,data:dU1bm2GBwdkqMQqEa+b0EfuMG5BRiiHDxNjB3tvB4JTVxqamQ17A47tzMld93/lZnJWRb4BtDFUI2xHh/5BCpxdI4J67AvWdv91usRgpgh7z7SF4pK4UUVah3WDYd3tvo+VzugvN6b4V+oGZlfJM789dJrTDOjSCAyyaaa/Qfb0=,iv:Cdaet+2Sowq50TDIkDO1RXi4vgaVqe7rYz08PHybAv0=,tag:1aeR/f4NnydiP2Vuuvljvw==,type:str]
pgp:
- created_at: '2020-06-13T12:21:16Z'
enc: |
-----BEGIN PGP MESSAGE-----
hQGMA5/a4uV8wP1EAQwAshoGsWCKiYnsi1Rr/HoMtvp8Tx5cmUWLPz0OsGsQUFc/
HQ48h7KUAjemTBnyQ6SpZUK2uI5YOLnOIqNcQJvNb4o30o0M3kuD2KNzSbsRGt3j
vODVKcs699sT1mX/rc6/EzpLy0NUgrAlXn7IUG+rhnk97OvfMdjP6+i77OpSU9Uc
5l6FWokBzFBvL6EENay6EO54C17MBXijoM4h6x7YajOjk5VNFtUl7wh039VGWZpQ
7vMuTbla06DWAHIFKIOs54yEh+vMTMgnsg8NrPzz4xqKDMcmZoQIm1jwc8EvxYK4
nGI4LpXO8VMgCyHBEcMjCGhZ5xXAiMRzF9M8XAWRfDFgYjDosL8QOQkl4vVnsf4e
5bhITFz1ZGaJwEeVzlt82cxWy4+BNq+lfAghqEnHGAjLGFIgTiRtVB47NLk9WPIT
T7Qv5gvATdW0rNHecfoGCKWx15ZJezXSo8Vtt5eVPgdYd3wO76Uw6XWhkxwSgQNT
vE7W5qvLoqxZrJs4Kyd20l4BQzSEiHJRg7wmWx9Y0BhyzF1Zh6F0oQBxTzGjP0f1
J9THfwIOhyOBwm8bWkEz7ac84o2NEItdrvlhrB0Y61ZfRl6xZKWqFxJ3N1yVHxxM
MWRYzaQcuoh5670lRhY5
=KjAd
-----END PGP MESSAGE-----
fp: 57E6DA39E907744429FB07871141FE9F63986243
unencrypted_suffix: _unencrypted
version: 3.5.0
SOPS is encrypting every value of the previously generated YAML
, including kind
or apiVersion
and metadata.name
. This is problematic because the whole team need to be able to read keys, which are not sensible in this Kubernetes secret.
🔏 Encrypt specific keys only
SOPS provides an handy parameter to choose which keys should be encrypted. This could be used directly from the command line sops --encrypt --encrypted-regex '^(data|stringData)$' app-secret.yaml
.
DISCLAIMER: For concision, I've removed a part of the generated files. SOPS parameters are included into the YAML and are verbose.
The file looks like this now:
apiVersion: v1
data:
secret: ENC[AES256_GCM,data:RLfYML8bJ0d5kN0nudgGgJJQIJMHK9MB,iv:6rurG5rErwn2O7PrHVoPjRnkMT5MjenhRmF3Vxh/cVw=,tag:4B5NeHbTmm0yl5VFlA9fww==,type:str]
kind: Secret
metadata:
name: app-secret
sops:
kms: []
gcp_kms: []
azure_kv: []
lastmodified: '2020-06-13T12:32:40Z'
mac: ENC[AES256_GCM,data:jl00u8YtegEi3lvuHv70PtI6Zywo8tSDH2DKk2jw+b4yiUGU2y9T82t3bE6ahY1MWy1U6CRK9NYKBS8p5HJqDjH/N21rhQy7k3g4BuzG/CJt2S/xio0KaAwwGXURUtXbHpXLrko22q0cgqCrsr/IFvz65r6WNhji0utSC1FKCPQ=,iv:XoilcDIZR8ir/ySbu+xVGNO0NkEkQr/IlyKXvAyyeyM=,tag:Hraabep8cq85M3OjvjoQBA==,type:str]
pgp: ... # Removed for concision
encrypted_regex: ^(data|stringData)$
version: 3.5.0
We can do better, because SOPS provides us a solution to store configuration required for every secret directly into the .sops.yaml
. We can add the key encrypted-regex
to simplify the command line. This is helpful when you need to add another secret key in an existing secret.
Every team member can now read and edit Kubernetes secret simply 🎉.
🦊 CI Integration
The CI needs to be adjusted to be able to deploy those manifests. We are using the base described in the previous article.
deploy int:
image: registry.gitlab.com/davinkevin/sops-blog-post-repository/gcloud-sops
before_script:
- *auth
script:
- sops -d app-secret.yaml | kubectl apply -f -
Conclusion
If you are using Kubernetes, and you want to manage your secrets in Git, SOPS will be a good match ❤️. You will be able to encrypt only desired value in a YAML
file to keep it readable, by a human and other tools working on Kubernetes manifests.
You can find the source code of this article, files and scripts in this GitLab repository.