Mozilla SOPS
Overview
In the broadest terms SOPS is an editor of encrypted files that supports YAML, JSON, ENV, INI and BINARY formats and encrypts with AWS KMS, GCP KMS, Azure Key Vault, age, and PGP.
One trick of SOPS is that statement of supported file formats. It natively understands how to encrypt data, but keep the keys in plain-text.
This allows us to store our secrets in git without exposing the plaintext, but keeping meaningful capabilities such as diff, etc.
Example file
Let's encrypt an example, using age.
If we start with the following secret;
apiVersion: v1
kind: Secret
metadata:
name: mysecret
data:
email_username: ZW1haWx1c2VybmFtZQ==
email_password: QWN0aXZlVGhpcnRlZW5XaWxkZm93bERhbmRlckRpbmdvQW50aXRydXN0
secret_key: Q3ViYnlob2xlUmVjbGluZXJBcHBlYWxpbmdTYXVjaW5lc3NNYWx0R3JhdGlmeQ==
cookie_domain: bXlkb21haW4=
email_host: bWFpbGwubXlkb21haW4=
email_from: ZW1haWx1c2VybmFtZUBteWRvbWFpbg==
We can see it would be a bad idea to store this directly in git as base64 encoding is not safe enough. Let's encrypt to an age public key and see the results:
Encrypting
sops --encrypt --age age1jktzcd9xnqrlejxltljh4j5fdly0hr8yg4z08qlkspyx7946cudsapr3df secrets.yaml | tee secrets.enc.yaml
apiVersion: ENC[AES256_GCM,data:mgo=,iv:jtZQuqQB8UEGGxgq543OgU72k0A30Jiu8mVG2v3aYCU=,tag:vDL3C1kmHVLJCBFBj3dpkQ==,type:str]
kind: ENC[AES256_GCM,data:Ij0wgW7h,iv:KHYyf3b4xe4lwfuRDb03ngoKjd9vR+SBUe8wjVbrEUk=,tag:M0n7Rm2bXdmTgFZEmw9nFA==,type:str]
metadata:
name: ENC[AES256_GCM,data:IKscS2EadQ8=,iv:ywySZ+pE+sDYPp7Jj9c5z47Xw1JhlV6Bu1HSIevwTl4=,tag:K+TBZkwuZMABjSx9e5DWFA==,type:str]
data:
email_username: ENC[AES256_GCM,data:bA38D6vm/hssRcMPku6fBGjcVvA=,iv:hR2n6mdu1D7axx5EuvtAXCvtP9+6SyQT9ag02eZFcLc=,tag:aiB882AxrMONDvgolyVdxA==,type:str]
email_password: ENC[AES256_GCM,data:2/QIgbGBnzR+dOTzm2E80TNknCONbRQYwMhdy7zKZYq0akIJhwz8ucU9Z49yAEYDqVjDnYLnv0w=,iv:X/ODB11+KjlIPa6Z3SeIGVyUNYtg3/q3w5WF4BdrPfE=,tag:3qyqH12GthJCvegXnxnEqg==,type:str]
secret_key: ENC[AES256_GCM,data:P9NfXL//cnZpkwrxtVRhVug9nIkzpSHVpoN24rO36I0yNlxYp4fNlsZjyfy9aXqGMu5NzxTmmRumNbJxHKWsNw==,iv:8YLtE+7cxq96Pg072TjuI4NFj6FAaIw4AV6zwdmzbgk=,tag:YTobqYT8OpTJBiH/i/19rg==,type:str]
cookie_domain: ENC[AES256_GCM,data:nFs7TaN8RaQrVHL0,iv:APCZVvp51U7dBtgw1uC9GH6ZrPSI5vqol5jFyzUXFWs=,tag:2onB2seYnvWV92Oa/I2OAA==,type:str]
email_host: ENC[AES256_GCM,data:jepu2umzeE9/TfVSgJXcxTpNMqw=,iv:tRynuPfbXGLU0Uq9k4y78Z1of92VI4K+ZKv7Qp5Hnmc=,tag:fjXjVDELDktO30pG23uKEQ==,type:str]
email_from: ENC[AES256_GCM,data:NX/l1PPwcFYN3IA7L5Ruk80H7lfmfkf3tp6mzj+Td9Y=,iv:gbIJA9+E/fG4pVF7WAfjrTEDBsJGTOFmcETe3ZbbvI0=,tag:oU9Y+pxlZ9Gp/S3Ccqh7uQ==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1jktzcd9xnqrlejxltljh4j5fdly0hr8yg4z08qlkspyx7946cudsapr3df
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZTzVHZk5TZ2JvMFlDZnhC
eXJwWG9UUFM3VUhTSEJYdjhDaE94djhPNmt3CnBUTlZBeVV0eDdFUm9PZEJTR0Za
SE5vVDkxU3lHenQrWFhKaU5yNUlTSlkKLS0tIDRid2VMUk9HQVpZNnJxTUwzNkJt
ZWZDTFRxeDhYR3pyTkYwRUJ4bkIrdmsKd69nPaklFYzpnKve6DtofD8RofI+V8Ik
9GUqNLE3zk7MIOTPXu18yzbl6AdL8BIQ1i0uVsS1bhWvv+JMPHg+XQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-03-13T23:10:13Z"
mac: ENC[AES256_GCM,data:6WVDyXTv5X6aNmr2Gf8TdvmiKPYBw5ET0pcO2VMfv+ErgyjloyhS132lvPOQFRUN7MZ59kTVCzDGx2VJ1w7DWWJCd3/plISKxUPVKZapKCOPrBeUHPjPGgKBVIzA3K2w98C2j3AQWtNxY6iEl0TUcbBW4tmlUYVJbqZeYgeiBE0=,iv:uzT3F3EizSgAM3IuBsvorrevOXZItNF4IyQhwa51Amg=,tag:M2gRJXdRBokhtcYhGF2qVw==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1
You can edit the file directly with the sops $filename
command from now on.
Make sure you delete the original, and from now on only commit the .enc.yaml
files via git. Tools like
trufflehog can help here.
Decrypting and applying
If you wanted to apply this secret directly to kubernetes without writing the plain-text to disk you could do something like the following:
Next Steps
SOPS can do a lot more, including publishing directly to vault or S3. For that, and more including key management, key rotation, audit loggings see SOPS