My adventures with retooling my personal infra repo continue this week with figuring out how to keep secrets secret outside of my previous method using ansible-vault.
The Ansible based solution has worked reasonably well for me for the last 7+ years but when making large repo edits I have a nasty habit of leaving the file decrypted and committing it to Github. Note my infra repos joke counter of "99.7% less leaked credentials" - yes that means I've leaked things three times. Yikes.
Enter git-crypt which offers transparent encryption to the user. Files you choose are encrypted when committed, and decrypted when checked out. It allows you to mix plain-text and encrypted content and allows for collaborators all via the battle tested GPG key system.
An example repo is provided at ironicbadger/gctest for you to view, fork, and otherwise enjoy.
GPG key basics
A GPG key pair contains a pair of keys, a public key and a private key. Much like with SSH keys the private key is a very important secret and should be guarded carefully.
If you don't have a GPG key it is simple to create one with:
gpg --full-gen-key
# 1) RSA and RSA
# keysize (default is 3072) - 4096
# key validity length - up to you
# GnuPG needs to construct a user ID to identify your key
# complete the prompts appropriately
#
# When happy with your selections, press O (Okay) to create the keypair
Verify the keys known to the system now includes your newly created key with:
gpg --list-keys
# /Users/bob/.gnupg/pubring.kbx
------------------------------
pub rsa4096/0xEB4F8DBF8DBF8DB3 2024-12-27 [SC]
Key fingerprint = F8DB F8DB F8DB F8DB F8DB F8DB F8DB F8DB F8DB 1463
uid [ultimate] bob <[email protected]>
sub rsa4096/0xF8DBF8DB07C2F8DB 2024-12-27 [E]
git-crypt basics
You'll need to install git-crypt - full instructions are provided via the git-crypt GitHub repo. This guide continues once git-crypt is installed.
Enter into your git repo directory. Make sure you are on the main/master branch, with no outstanding changes, initialise git-crypt, and add the key to repo. For example:
$ cd gctest
$ git init
$ git-crypt add-gpg-user [email protected]
git-crypt already committed the change (a new .gpg file in the .git-crypt directory), so now do:
$ git push
git-crypt encryption instructions
The files that you choose to encrypt are governed by the contents of the .gitattributes
file.
The following example file will automatically encrypt any file which containers .enc
somewhere in its filename. This could be secrets.enc
or secrets.enc.yaml
- both will be committed to GitHub as encrypted files all transparently to you.
.gitattributes !filter !diff
**/*.enc.* filter=git-crypt diff=git-crypt
**/*.enc/** filter=git-crypt diff=git-crypt
Commit the .gitattributes
file and then create a file with a pattern that matches your chose encryption filter pattern (`.enc` in my case).
You might at first wonder if git-crypt is doing anything. But once you commit and push your .enc
file it will automatically be encrypted and only viewable by someone with your PGP key (hopefully that's only you!). You'll be asked for a passphrase in addition to the key, so keep that safe too.
You can add extra collaborators to a repo with git-crypt but that's beyond the scope of this article - useful if you're in a dev team though!
If you'd like to keep the contents of that file encrypted on your local disk, we can do that with git-crypt too using git-crypt lock
. For example:
Multiple machines
It's likely you'll want to access this git repo from multiple machines. You'll need to copy your GPG key over, or add that GPG identity to the repo. If you're copying the key over export the private key (with care!) using:
$ gpg --export-secret-key -a > secretkey.asc
Then copy that file wherever you need it and import it on the other end with
$ gpg --import secretkey.asc
Once the keyfiles have served their purose securely delete them with:
$ shred secretkey.asc
$ rm secretkey.asc