Photo of Danny Berger
Secure Git Repositories
Post |

I use private repositories on GitHub, but I still don't feel quite comfortable pushing sensitive data like passwords, keys, and account information. Typically that information ends up just sitting on my local machine or in my head ready for me to pull up as needed. It would be much better if that information was a bit more fault tolerant and, even better, if I could follow similar workflows as the rest of my application code.

After some research I discovered gist 873637 which discusses using git's clean and smudge filters to pass files through openssl for decryption and encryption. The result is git's indexes only containing encrypted file contents in base64. Soon I found shadowhand/git-encrypt.

Initial Setup

First, I did a one-time install of shadowhand/git-encrypt on my machine:

$ git clone git:// /usr/local/git-encrypt
$ chmod +x /usr/local/git-encrypt/gitcrypt
$ ln -s /usr/local/git-encrypt/gitcrypt /usr/local/bin/gitcrypt

Next, I created a new repo and use gitcrypt init to set things up:

$ mkdir fort-knox && cd !$
$ git init
Initialized empty Git repository in /private/tmp/fort-knox/.git/
$ gitcrypt init
Generate a random salt? [Y/n] Y
Generate a random password? [Y/n]Y
What encryption cipher do you want to use? [aes-256-ecb] 

This configuration will be stored:

salt:   7d9f6cc1512aa2b5
pass:   EAC8405A-DD64-43A3-A17F-EB28195B4B1E
cipher: aes-256-ecb

Does this look right? [Y/n] Y
Do you want to use .git/info/attributes? [Y/n] n
What files do you want encrypted? [*] 

Now I just have to be sure to securely keep the salt and pass elsewhere for the next time I setup this repo. Other than that, it's ready for me to use like any other git repository.

A Practical Bit

Since I won't frequently be setting up this repository, it'd probably be best if I could keep a reminder about what I'll need to do. So I update .gitattributes to exclude itself and README from encryption:

* filter=encrypt diff=encrypt
README -filter -diff
.gitattributes -filter -diff


And include the necessary commands and reference in README:


    git clone fort-knox && cd !$
    gitcrypt init #
    git reset --hard HEAD

So, my first commit looks like:

$ git add .
$ git commit -m 'initial commit'
[master (root-commit) 1077d71] initial commit
 2 files changed, 7 insertions(+)
 create mode 100644 .gitattributes
 create mode 100644 README

Under the Hood

Originally I was a bit curious and wanted to verify that it's doing what I thought. So I created a simple test file:

$ date > top-secret.txt
$ cat top-secret.txt 
Mon Jan  7 15:11:22 MST 2013
$ git add top-secret.txt
$ git commit -m 'top secret information'
[master dd2272a] top secret information
 1 file changed, 1 insertion(+)
 create mode 100644 top-secret.txt

After committing I can look at the raw index data to see what's actually being stored:

$ git ls-tree HEAD
100644 blob 6a9e000e136a20858f65188f849d0bffed48a685	.gitattributes
100644 blob 2221766ff8694dffa1e11ea5d0e7acd213e22d90	README
100644 blob e847f7c05236ac1111a0f5495da87fec188d5420	top-secret.txt
$ git cat-file -p 2221766ff8694dffa1e11ea5d0e7acd213e22d90

    git clone fort-knox && cd !$
    gitcrypt init #
    git reset --hard HEAD
$ git cat-file -p e847f7c05236ac1111a0f5495da87fec188d5420

As expected, README is readable, but top-secret.txt is not. I can manually verify my secret data is still there by decoding it with my key:

$ git cat-file -p e847f7c05236ac1111a0f5495da87fec188d5420 | openssl base64 -d -aes-256-ecb -k "EAC8405A-DD64-43A3-A17F-EB28195B4B1E"
Mon Jan  7 15:11:22 MST 2013


With gitcrypt I can work with a repository and enjoy extra security on top of the redundancy and version control that git provides. The only difference from my regular repos is I can't really view my files from (with the convenient exception of README).