I'm learning about SOPS and setting it up as my preferred mechanism for storing secrets. Here are my notes.
It’s security mechanism is that we (i.e. client) use a PUBLIC key from the receiver (i.e. server) and encode it with a random key (I’m saying nonce but it could be reused)
This varies from RSA and SSH because the server uses a PUBLIC key to identify the client.
Web of trust operates by still using PGP (i.e. encoding with recipient’s public key) but additionally, we can encrypt/sign the data as our own by signing it with the client’s private key.
This means the recipient will initially decrypt via our (i.e. client’s) public key (verifying the source) and then decrypting via their (i.e. server’s) private key to get the data.
To reiterate, the data we send is twice encrypted source’s private key outer shell, recipient’s public key inner shell.
https://en.wikipedia.org/wiki/Web_of_trust#Simplified_Explanation
For a PGP setup, development machine must have the same public/private PGP key. Technically, we only need the public key to write content but for reading/editing we need the private key.
The production server will have the private key for decryption.
We can share the same PGP key for all services or make it per-service (obviously 1 is easier to maintain).
As an alternative to this sensitive setup, we can use AWS’ KMS which will manage these public/private keys for us. To access said keys, we can use AWS credentials and their access control policy.
The benefit of using KMS is it decouples the encryption key from access credentials. Great job by Mozilla here 💯
First, get SOPS installed by following its instructions:
To delete their PGP key (although you likely don’t need to; GPG is more of a credential manager):
- List installed keys via
gpg --list-keys
/home/todd/.gnupg/pubring.gpg
-----------------------------
pub 1024R/07FB1A0A 2015-10-08
uid SOPS Functional Tests (https://github.com/mozilla/sops/) <[email protected]>
sub 1024R/7CD79CC0 2015-10-08
- Delete desired key via
gpg --delete-keys {{fingerprint}}
andgpg --delete-secret-keys {{fingerprint}}
- In the example above, public fingerprint is
07FB1A0A
and private is7CD79CC0
- In the example above, public fingerprint is
- Verify empty files at
~/.gnupg/pubring.gpg
and~/.gnupg/secring.gpg
GPG cheatsheet here: http://irtfweb.ifa.hawaii.edu/~lockhart/gpg/gpg-cs.html
Now that we have SOPS installed, let’s set it up in our repo:
- Generate a GPG key for the repo
- Use
gpg --gen-key
. For configuration, I chose:- Key type: RSA and RSA
- Keysize: 2048
- Expiration: 0 (never expires, otherwise we will have to re-set up configs)
- Real name: {{repo}} PGP (e.g. “twolfson.com PGP”)
- Email address: {{email}}
- Comment: PGP credentials for {{repo}} secrets
- Password: Empty password
- You may use a password but all developers and scripts performing decryption will need to know that password
- This effectively makes the password useless since we are more concerned about compromising our secrets than the RSA key
- Use
- Find full fingerprint for keys via
gpg --fingerprint
- This will be
740D DBFA...
inKey fingerprint = 740D DBFA...
- This will be
- Create our file via
sops --pgp '{{full_fingerprint}}' secret.enc.yml
- For JSON, we can use a non-YAML extension
- For future edits of the file, we can use
sops secret.enc.yml
(our PGP fingerprint has been stored inside of the file)
- Extract private key to file via
gpg --export-secret-keys --armor {{fingerprint}} > private.rsa
--armor
exports a human-friendly ASCII format instead of binary
- Upload private key to our server via
rsync private.rsa {{server}}:private.rsa
- SSH onto our machine
- Import private key into
gpg
keychain viagpg --import private.rsa
- During deployment, decrypt
secret.enc.yml
to its plaintext variant viasops --decrypt secret.enc.yml > secret.yml
- Run server using plaintext
secret.yml