This post will present the way of encrypting selected data with git-crypt, allowing us to keep them safe, but also keep them in the repository.
Why bother?
Keeping all the files in the repository remove the hassle of storing them somewhere else and passing this knowledge between developers. It’s something done rather rarely and often requires digging between storages, when a new guy shows up in the team. But you can’t just have it all in the repository, it’s too dangerous!
Let’s take an example of an Android project. If the developer cared for security you won’t be able to take some non open source project and build it right away after you clone the repository. It will be probably missing keystore access information and it should miss the keystore file itself. There are several other informations that might have been kept away from the repository and are stored in some local-only files. Getting them in place requires onboarding from the developer that already has access and remembers the process, which can be the pain as you tend to forget things that you do for instance, once a year.
With git-crypt you’ll be able to say: Setup git-crypt. I’ll need your client-ID and email address and you’ll be ready to go.
This means, that having the access setup in place, all that new joiner will have to do it is simply git clone and nothing more.
How does it work?
Encryption isn’t anything new of course. git-crypt uses our beloved version control system to make the process almost transparent. Basically, you tell the git-crypt keep some files encrypted and when you push to the repository, they get encrypted on the fly. When you browse your remote git repository you can see the files, but the content will be entirely different. When you pull the repository, the process goes backwards. Selected files are decrypted and readable on your disk.
Once a new developer joins the project, he/she needs to setup the git-crypt and be added by someone already involved. I’ll describe the steps for both, a new joiner and an old member (I’ll call him admin for convenience). Instruction is for Mac users, but I’m sure it can be easily ported to any platform.
Get git-crypt
- Get a homebrew if you still don’t have it
- Install of encrypting selected data with git-crypt
brew install git-crypt
brew install gnupg
An admin – preparing your repo
- Enter your repo in the console
- Generate and commit a symmetric master key to automatically created .git-crypt folder.
- Add a copy of the master key, encrypted with your public GPG key (so that only you can decrypt it)
- Make sure that the files you want to encrypt are in the repository and are not gitignored
- Prepare the configuration file. Create
.gitattributes
file on the same level that files you want to encrypt - Add your changes to git. Don’t commit yet.
- List files for encryption
- Commit and push!
git-crypt init
git-crypt add-gpg-user --trusted your.email@domain.com
Here is an example of the configuration for 2 files:
# Files that are going to be encrypted
release-keystore.jks filter=git-crypt diff=git-crypt
# (I use gradle.properties to store credentials)
gradle.properties filter=git-crypt diff=git-crypt
# Making sure that .gitattributes is never encrypted. DON'T TOUCH THAT LINE AND ONE BELOW
.gitattributes !filter !diff
git add .
git-crypt status -e
If you did a commit before it might fail and ask you to do git-crypt status -f
first
git commit
git push
An admin – adding a new joiner
If you got the key-ID from the new joiner:
- Download new joiner public key
- Add new joiner user
gpg --keyserver hjttps://pgp.mit.edu --recv-key *new-joiner-key-ID*
git-crypt add-gpg-user --trusted newjoiner@email.com
If that fails you’ll need a ASCII version of public key from a new joiner.
Getting that is described in the new joiner section. This is how you add ASCII version of public key manually:
- Get a ASCII version of public key from new joiner and save it in some file
- Import the key from file
- Add new joiner user
Paste the whole thing you got from the previous command, with the —BEGIN…— and —END…— lines
gpg --import /path/to/file
git-crypt add-gpg-user --trusted newjoiner@email.com
A new joiner
- Generate a GPG key pair
- Get your hexadecimal key-ID
- Send your public key to the general server
- Send your key-ID and the email address you used for the key creation to the developer that will grant you rights
gpg --gen-key
Fill in the data you are be asked for.
gpg --list-keys
gpg --keyserver https://pgp.mit.edu/ --send-keys *your-key-ID*
If you failed to send your public key to the general server the described method, below you’ll find a workaround. Just skip points 5 and 6 in a favor of the workaround.
Sending your public key to the general server manually
- Get your ASCII version of public key
- Submit ASCII version of public key manually on the web page.
- Send your ASCII version of public key and the email address you used for the key creation to the developer that will grant you rights
gpg --export --armor *your-key-ID*
Paste the whole thing you got from the previous command, with the —BEGIN…— and —END…— lines
Selecting more files for encryption later
There is a tight process you need to stick to while adding new files to encryption later. Unfortunately, if you have files that you wanna secure, on different levels of a project, you’ll have to create a separate .gitattributes
file for each level
- Create
.gitattributes
file if necessary - Add a line for selected file in
.gitattributes
file of the same level git add .
git-crypt status -e
orgit-crypt status -f
if you did the commit beforegit commit
Switching machines
If you happen to change your workstation and not wanna be treated as a new joiner (although it’s possible if there is still some other machine that will grant the access) you can export your keys and then import them on the new machine.
Here is how to export the keys:
gpg --export *your key-ID* > path/to/public/key/backup/file
gpg --export-secret-keys *your key-ID* > path/to/secret/key/backup/file
You can import these files later:
gpg --import path/to/public/key/backup/file
gpg --import path/to/secret/key/backup/file
Fail-safe
Having git-crypt doesn’t mean you’re free from making a backup somewhere. If your project happens to be in a situation that all the developers are gone, then after some time it’s getting new joiners, there will be nobody to grant the access to them. One of the ways would be exporting keys from one of the developers working on the project as the previous section described, keep them somewhere safe and then import to the new developer’s machine when he/she shows up.
Zipping up
At first sight, the setup might seem even more hassle that well-known procedures. It was to me. But then, keeping everything in repository was tempting, and if that becomes popular procedure it will be much easier to remember.