# What is git-crypt
git-crypt
enables transparent encryption and decryption of files in a git repository. Files which you choose to protect are encrypted when committed, and decrypted when checked out.git-crypt
lets you freely share a repository containing a mix of public and private content.git-crypt
gracefully degrades, so developers without the secret key can still clone and commit to a repository with encrypted files. This lets you store your secret material (such as keys or passwords) in the same repository as your code, without requiring you to lock down your entire repository.
This post explain how to use it.
# Generate a GPG key
To crypt and decrypt content using git-crypt
, we need to a gpg key.
So let generate a key.
# Create a gpg config file
create a file gpg-config
with the following content
%echo Generating a basic OpenPGP key
Key-Type: default
Subkey-Type: default
Name-Real: My Name
Name-Email: myemail@domain.sub
# Do a commit here, so that we can later print "done" :-)
%commit
%echo done
You can change My Name
with your real name and myemail@domain.sub
by your email.
# Generate the key
run the following command, we will prompted to enter the key paraphrase.
$ gpg --batch --gen-key gpg-config
gpg: Generating a basic OpenPGP key
gpg: key D5B2C360EA7A893F marked as ultimately trusted
gpg: revocation certificate stored as '/home/******/.gnupg/openpgp-revocs.d/05AC305410E66882237F4991D5B2C360EA7A893F.rev'
gpg: done
You should have a new key
$ gpg --list-secret-keys
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: next trustdb check due at 2022-05-31
/home/******/.gnupg/pubring.kbx
---------------------------------
...
pub rsa3072 2020-06-01 [SC]
F6241BADF89F0BA297359D7F5A2954A9F2CAA211
uid [ultimate] My Name <myemail@domain.sub>
sub rsa3072 2020-06-01 [E]
# Install git-crypt
# Installing on Mac OS X
Using the brew package manager, simply run:
$ brew install git-crypt
# Installing on ubuntu
Using the apt
or apt-get
package manager, simply run:
$ sudo apt install git-crypt
# Use git-crypt
To demonstrate the usage of git-crypt
we will
- create a new local git repository
- configure git-crypt
- add a secret
- push modification
- clone a second version
- show that the secret is encrypted
- decrypt the secret
# Initialize a git repo with git-crypt
Let init a new git repository
$ mkdir /tmp/copy1 && cd /tmp/copy1
$ git init
Add an empty .gitattributes
file and commit it.
$ touch .gitattributes
$ git add .gitattributes
$ git commit -m "first commit"
We have a secret file to add, we don't want this secret to be readable by everyone having access to this repository, but we want to share and historise this secret with a group of special users. To do that we can use git-crypt
.
Here steps to activate git-crypt into this repository
git-crypt init
Tell git-crypt
to use the gpg key created above to encrypt secret.
if you changed
myemail@domain.sub
with your own email, so don't forget to use it here.
$ git-crypt add-gpg-user --trusted myemail@domain.sub
[master f7051b5] Add 1 git-crypt collaborator
2 files changed, 4 insertions(+)
create mode 100644 .git-crypt/.gitattributes
create mode 100644 .git-crypt/keys/default/0/F6241BADF89F0BA297359D7F5A2954A9F2CAA211.gpg
We can see that the git-crypt add-gpg-user
command has made an automatic commit.
$ git log --oneline
547458e (HEAD -> master) Add 1 git-crypt collaborator
c8b6e50 first commit
You should have this tree into the current folder
$ tree -a .
.
├── .git
...
...
│ ├── git-crypt
│ │ └── keys
│ │ └── default
...
...
├── .gitattributes
└── .git-crypt
├── .gitattributes
└── keys
└── default
└── 0
└── F6241BADF89F0BA297359D7F5A2954A9F2CAA211.gpg
Tell git-crypt
to decrypt encrypted files.
At this step there are nothing to decrypt, but we need to
unlock
to be able to add clear version of secrets.
git-crypt unlock
Create a new secret file.
$ echo "secret" > mysecret.txt
Tell git-crypt
that mysecret.txt
have to be encrypted
echo "mysecret.txt filter=git-crypt diff=git-crypt" >> .gitattributes
Check that git-crypt
take on consideration the content of .gitattributes
$ git-crypt status
encrypted: mysecret.txt
not encrypted: .git-crypt/.gitattributes
not encrypted: .git-crypt/keys/default/0/F6241BADF89F0BA297359D7F5A2954A9F2CAA211.gpg
not encrypted: .gitattributes
Check the content of the mysecret.txt
file
$ cat mysecret.txt
secret
It still readable this because of the git-crypt unlock
.
Let switch the repository to the encrypted version.
$ git-crypt lock
Check the content of the mysecret.txt
file
$ cat mysecret.txt
## some binary output, the encrypted version
To develop and use the repository we have to unlock the repository.
$ git-crypt unlock
Add and commit those changes
git add .gitattributes mysecret.txt
git commit -m "add my first secret"
# Add a second special user to the git repo with git-crypt
To share this git repository, and the secret part with an other user.
- You can share your gpg key.
To do that you can export the key
$ git-crypt unlock
$ git-crypt export-key /tmp/mykeyfile
Share the /tmp/mykeyfile
file with the other user. Using the following command it can decrypt secret.
$ git-crypt unlock /tmp/mykeyfile
But this is a poor method and it's bad practices to use the same key for all users. Let try a method with one key by user.
create a file gpg-config2
with the following content
%echo Generating a basic OpenPGP key
Key-Type: default
Subkey-Type: default
Name-Real: Second User
Name-Email: seconduser@domain.sub
# Do a commit here, so that we can later print "done" :-)
%commit
%echo done
and generate a new gpg key.
$ gpg --batch --gen-key gpg-config2
gpg: Generating a basic OpenPGP key
gpg: key 4D304D45B2F73BF4 marked as ultimately trusted
gpg: revocation certificate stored as '/home/******/.gnupg/openpgp-revocs.d/3E4A037337BE1CB34A3D6CF44D304D45B2F73BF4.rev'
gpg: done
Export the public key of the gpg key pair.
$ gpg --output /tmp/seconduser.gpg --armor --export seconduser@domain.sub
$ cat /tmp/seconduser.gpg
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQGNBF7U0AYBDADM1KmXY/zc3Y0fJifWKzsCVSsaJ2hMNQ1Fh2iZ0TY33xU/z6Fs
...
...
2A3NEtBDWMbPEqVJJzkh
=FKXx
-----END PGP PUBLIC KEY BLOCK-----
Share the seconduser.gpg
with the first user (the crypt admin).
To simulate what will happen into the first user side, we will remove the seconduser@domain.sub
from our gpg key store using the following command.
# delete the `seconduser@domain.sub` secret
$ gpg --list-secret | grep -B1 "seconduser@domain.sub" | grep -v uid | tr -d "[:blank:]" | xargs -I{} gpg --batch --delete-secret-keys {}
# delete the `seconduser@domain.sub` key
$ gpg --list-keys | grep -B1 "seconduser@domain.sub" | grep -v uid | tr -d "[:blank:]" | xargs -I{} gpg --batch --delete-key {}
$ gpg --list-keys | grep "seconduser@domain.sub"
# empty result
The first user
have to import the public key of the second user
$ gpg --import /tmp/seconduser.gpg
gpg: key 4D304D45B2F73BF4: public key "Second User <seconduser@domain.sub>" imported
gpg: key 8800324F3C0519E8: public key "Second User <seconduser@domain.sub>" imported
gpg: Total number processed: 2
gpg: imported: 2
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 2 signed: 1 trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: depth: 1 valid: 1 signed: 0 trust: 1-, 0q, 0n, 0m, 0f, 0u
gpg: next trustdb check due at 2022-05-31
The new key should be listed into GPG keys. But this key is marked as unknown
$ gpg --list-keys
/home/******/.gnupg/pubring.kbx
---------------------------------
pub rsa3072 2020-06-01 [SC]
F6241BADF89F0BA297359D7F5A2954A9F2CAA211
uid [ultimate] My Name <myemail@domain.sub>
sub rsa3072 2020-06-01 [E]
pub rsa3072 2020-06-01 [SC]
9C465BFA9B3DE508E036EF888800324F3C0519E8
uid [ unknown] Second User <seconduser@domain.sub>
sub rsa3072 2020-06-01 [E]
To make this key trusted the first user
have to
$ gpg --edit-key seconduser@domain.sub
# At the gpg> prompt
# Enter sign
# Enter save (which should exit the prompt)
you should have full
instead of unknown
$ gpg --list-keys
/home/melhabib/.gnupg/pubring.kbx
---------------------------------
pub rsa3072 2020-06-01 [SC]
F6241BADF89F0BA297359D7F5A2954A9F2CAA211
uid [ultimate] My Name <myemail@domain.sub>
sub rsa3072 2020-06-01 [E]
pub rsa3072 2020-06-01 [SC]
9C465BFA9B3DE508E036EF888800324F3C0519E8
uid [ full ] Second User <seconduser@domain.sub>
sub rsa3072 2020-06-01 [E]
$ cd /tmp/copy1
$ git-crypt unlock
$ git-crypt add-gpg-user --trusted seconduser@domain.sub
[master c4346de] Add 1 git-crypt collaborator
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 .git-crypt/keys/default/0/9C465BFA9B3DE508E036EF888800324F3C0519E8.gpg
- The first user have to Push auto-generated commit up to Git host
- The second user have to
- pull down the repository from Git host
- git-crypt unlock And files will be decrypted
# Clean GPG
If you don't want to keep test GPG key you can delete them using the following commands.
$ gpg --list-secret | grep -B1 "myemail@domain.sub" | grep -v uid | tr -d "[:blank:]" | xargs -I{} gpg --batch --delete-secret-keys {}
$ gpg --list-keys | grep -B1 "myemail@domain.sub" | grep -v uid | tr -d "[:blank:]" | xargs -I{} gpg --batch --delete-key {}
$ gpg --list-secret | grep -B1 "seconduser@domain.sub" | grep -v uid | tr -d "[:blank:]" | xargs -I{} gpg --batch --delete-secret-keys {}
$ gpg --list-keys | grep -B1 "seconduser@domain.sub" | grep -v uid | tr -d "[:blank:]" | xargs -I{} gpg --batch --delete-key {}