Manage your secrets in Git with SOPS for Kubernetes ☸️
Tags: sops, kubernetes, git, devops
Published: 2020-06-13 13:25:56


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](https://kubernetes.io/docs/concepts/configuration/secret/).

# 😊 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: 

{% asciinema 339181 %}

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.

{% asciinema 339182 %}

The SOPS output is like this: 

```yaml
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`.

{% asciinema 339183 %}

**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: 

```yaml
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.

{% asciinema 339184 %}

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](https://dev.to/stack-labs/manage-your-secrets-in-git-with-sops-gitlab-ci-2jnd).   

```yaml
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](https://gitlab.com/davinkevin/sops-blog-post).