Sunday, June 23, 2024

Encrypted, private github repositories

 Github allows unlimited private repositories.  Sometimes, though, you need additional privacy.  I store many of my passwords and other sensitive information inside plain text files, and would like to version them with git and then upload them to github.  Even with private repositories, these text files are available to github employees, stored in cleartext in backups, available to law enforcement, etc. I'd like these files to be stored with encryption at Github, to ensure that only I have access to these files.  While I could do this with my own git instance, I like the availability, backups and worldwide reach of github, and I want to avoid maintaining one more thing.

This tutorial shows you how to have encrypted repositories at Github. In an encrypted repository, the contents of the repository at Github are encrypted with GnuPG. On all machines outside your own, these files are encrypted and secure. Nobody, not even employees at Github can examine the contents of the files. Without your gpg secret key, the entire repository at github is opaque to people.

The repositories can be private or public. For an encrypted repository, there is little difference between a public and a private repository, as the contents are not visible without your secret gpg key.  The benefits to having a private repository is that nobody can tell the repository exists, and you have an additional hurdle of an ssh key to download the repository. The benefit of a public repository is that you can have many contributors, and you can git clone the repository from anywhere, as far as you have the gpg secret key to decrypt the contents.


For this mini-tutorial, you should already have git working with ssh keys.  If you don't, follow these instructions. This tutorial is for Linux.


1. Packages: On Linux, install the relevant packages:

apt install git-remote-gcrypt gnupg


2. Github repository: Create a private repository in github. I created an example public repository here though you might want to create a private repository.

export PROJECT=username/reponame.git

3. Create gpg keys: if you don't already have one using

gpg --full-generate-key

Remember the passphrase used here.  If you lose/forget this passphrase, you will not be able to decrypt this repository, ever.  The keyring is usually stored in .gnupg/pubring.kbx 


List the keys, and write down the key-id:

gpg --list-keys

export KEY_ID=<what you got above>

For example, my KEY_ID is BAB59DAD24A79C69D4D3E5451482830DA6C99CAA.

4. Configure git: Go over to your existing git repository (or initialize one, and then add files to it)

Specify this ID as the one that you will encrypt with:

git config --global user.signingkey $KEY_ID

And as the participant allowed to contribute to this project

git config remote.origin.gcrypt-participants $KEY_ID


5. Remote: Add the upstream remote like this:

git remote add origin gcrypt::git@github.com:$PROJECT

git push origin master


That should prompt you for your gpg password you entered when creating your key.  Now, you have a git repository that is hosted at github, and the contents are encrypted.  This is an example of what you should see.  At this point, the repository could be private or public, since nobody can read the contents unless they have your GPG key.


6. Clone: To clone this repository on another machine, remember to add gcrypt:: before the git@github.com, and the new machine should have both the ssh keys (to clone a private repository) and the gnupg keys (to decrypt the contents of the repository)

git clone gcrypt::git@github.com:$PROJECT

For example, I do:

git clone gcrypt::git@github.com:youngelf/example-encrypted-repository.git

Done right, it should request the gpg password for the private key, and show you this output from gpg

gpg: Good signature from "Your name <email@example.com>"


7. git pull, git add, git push

At this point, this is a normal git repository, you can use git commands.  I find it more convenient to use the git clone'd directory, as it sets the configuration for branch.master.merge and branch.master.remote correctly.