27 Apr 2017

Encrypted git repositories

I recently replaced my unison config with git. Previously, unison would sync my org-mode files to an encfs directory on my server. So if my server were ever compromised, at least my org files would be encrypted. I wanted similar security from unison's replacement. For reference, here's how I set up an encrypted git repository.

This guide assumes you have an existing gpg key.

Installing git-remote-gcrypt

To encrypt the repository I'm using the git-remote-gcrypt plugin (github mirror).

git clone https://git.spwhitton.name/git-remote-gcrypt
cd git-remote-gcrypt
sudo ./install.sh

Configuring git for git-remote-gcrypt

I'm using a global configuration, but you can set these git-config properties per-repository if you prefer. See the configuration notes on git-remote-gcrypt's README for more info on the available options.

I'm using gpg-agent so the --use-agent option needs passing to gpg, otherwise I get an error saying "gpg: Sorry, no terminal at all requested - can't get input".

git config --global --add gcrypt.gpg-args "--use-agent"

I publish the participant (public) keys so I don't get prompted for unnecessary gpg passwords when cloning/pulling from the server. Note that this is turned off by default for privacy.

git config --global --add gcrypt.publish-participants true

Let's also set the global git signing key while we're at it. My public key ID is 0E0A719A. If you don't know your key ID, you can list your local keys using gpg --list-secret-keys, taking the last eight characters of the appropriate key ID should work.

git config --global user.signingkey 0E0A719A

Use your key ID instead of 0E0A719A!

Add participant keys for the encrypted repositories as a space-separated list (again, I'm doing the globally).

git config --global --add gcrypt.participants "0E0A719A"

Use your key ID instead of 0E0A719A!

Create an encrypted repository

First, create your git repository as normal:

mkdir ./example-crypt
cd ./example-crypt
echo "TEST" > README
git init
git add README
git commit -am "first commit"

Then, set up a git remote using the gcrypt protocol:

git remote add origin gcrypt::rsync://username@your-server.com:example-crypt
git push -u origin master

That's it! SSH into your server to confirm that the repository is encrypted.

Cloning your encrypted repository

On another machine, I want to clone the above repository. This assumes I have the same gpg key installed on both machines (otherwise, you'll need to go back and add this new gpg key's ID to your gcrypt.participants config).

Install git-remote-gcrypt on this machine too, then clone using the gcrypt protocol.

git clone gcrypt::rsync://username@your-server.com:example.crypt

If you get "gpg: decryption failed: No secret key" there may have been a typo in the passphrase when you pushed for the first time - it turns out gpgtools will save the wrong passphrase to the keychain without complaining (source).

Using the repositories

After setting up the encrypted remotes as above, you should be able to push to and pull from the repository as normal, though you may occasionally be prompted for your gpg key passphrase. You can configure gpg-agent to cache passphrases for a custom length of time, see the gpg-agent documentation for details.