This post describes a tool (git-crypt), a set of practices and principles (e.g., Castle Approach to security, a.k.a Security in Depth principle) for increasing the protection for data inside a (private) git repository.

Introduction

After better, safer alternatives have been exhausted, sometimes we desire to save secret data into a git repository. A manual way to do this would be to encrypt/decrypt information using GPG (see this guide), but there is a better way to do this: git-crypt.

What is git-crypt?

Git crypt is a wrapper on top of GPG, that enables transparent encryption. It creates a GPG-secured vault.

From their project site:

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.

Only an authorized user can grant permission to other users. Otherwise, the security would be pointless, as you could add yourself to any vault.

Git-crypt: How do I use it

I usually do the separation that the git-crypt author is talking about: selected parts of my repository are secret (therefore need to be encrypted).

I usually choose a descriptive name for this folder, preferring to reveal “keys” as my folder name, rather than using Security through Obscurity for a folder name “src/test/resources/selenium” (just an example).

Setting it up

Set up the git repo:

cd repo
git-crypt init

Specify which folders/files need to be encrypted, as git-filters:

$ cat .gitattributes
keys filter=git-crypt diff=git-crypt

Add the authorized users (identified by their GPG key):

git-crypt add-gpg-user USER_ID

Using it

  • Clone the repo
  • Unlock the vault: git-crypt unlock
  • Make changes and commit them
  • Push
  • This leaves the vault open in your computer, but not the remote. You can close it with git-crypt lock. Leaving it closed or open does not make a difference, if an attacker can just issue a command for unlocking it (without any further protection)

Common workflows

  • Developer machines: Create the vault, add yourself as trusted user. Request the public keys from your team members, add the user keys to the vault.
  • Continuous Integration (CI) machines: add a common GPG key for the jenkins/CI executors. Authorize it in the repo.

Security

git-crypt is using GPG underneath, so the security should be the one provided by GPG, except for possible defects in the git-crypt glue.

From the project site:

git-crypt is more secure than other transparent git encryption systems. git-crypt encrypts files using AES-256 in CTR mode with a synthetic IV derived from the SHA-1 HMAC of the file. This mode of operation provides semantic security under deterministic chosen-plaintext attack. That means that although the encryption is deterministic (which is required so git can distinguish when a file has and hasn’t changed), it leaks no information beyond whether two files are identical or not. […]

Limitations & Gotchas

Using a public repository breaks the “Security at Depth” principle.

You have to be careful when adding the key to the vault: you could expose your key email (e.g., me@mydomain.com). This is an entrypoint for phishing attacks.

It is visible (for an unauthorized user) that we are using git-crypt, based on the evidence left in the .gitattributes file:

git-crypt does not encrypt file names, commit messages, symlink targets, gitlinks, or other metadata.

Other security concerns, from the project site:

git-crypt relies on git filters, which were not designed with encryption in mind. As such, git-crypt is not the best tool for encrypting most or all of the files in a repository. Where git-crypt really shines is where most of your repository is public, but you have a few files (perhaps private keys named *.key, or a file with API credentials) which you need to encrypt. For encrypting an entire repository, consider using a system like git-remote-gcrypt instead. (Note: no endorsement is made of git-remote-gcrypt’s security).

git-crypt does not hide when a file does or doesn’t change, the length of a file, or the fact that two files are identical.

Files encrypted with git-crypt are not compressible. Even the smallest change to an encrypted file requires git to store the entire changed file, instead of just a delta.

Although git-crypt protects individual file contents with a SHA-1 HMAC, git-crypt cannot be used securely unless the entire repository is protected against tampering (an attacker who can mutate your repository can alter your .gitattributes file to disable encryption). If necessary, use git features such as signed tags instead of relying solely on git-crypt for integrity.

The diff changes when the vault is open vs closed. When it is open, the file contents is in “plain” format (i.e., decrypted). Therefore, you can see the diff. When the vault is closed, you can not see an effective diff, as the cypher text changes, but the human eye cannot distinguish the contents.

Extras

There are times when we need to use secrets in our application. It might be for environment configuration (e.g., database credentials, services we depend on) or for application configuration.

Ideally, this information should be present elsewhere (separated from the application source code):

  • Principle of least privilege: administrators have access to secrets, but not to code; while developers have access to code but not to secrets (they can have access to pre-prod secrets)
  • The pace of change for these are different, therefore following the Single Responsibility Principle (SRP) in SOLID

Principles

We are following the following principles from “Security Principles we live by” (Howard02):

  • Use Defense in Depth
  • Never Depend on Security Through Obscurity Alone

About defense in depth:

The idea behind defense in depth is to manage risk with diverse defensive strategies, so that if one layer of defense turns out to be inadequate, another layer of defense will hopefully prevent a full breach. – (Howard02)

About security through obscurity:

Always assume that an attacker knows everything that you know — assume the attacker has access to all source code and all designs. Even if this is not true, it is trivially easy for an attacker to determine obscured information. […] Obscurity is a useful defense, so long as it is not your only defense. In other words, it’s quite valid to use obscurity as a small part of an overall defense in depth strategy. – (Howard02)

References & Links

Appendix

The “Security Principles we live by”

This is the complete list of security principles explained in “Writing Secure Code”, by Howard and LeBlanc:

  • Learn from Mistakes
  • Minimize Your Attack Surface
  • Employ Secure Defaults
  • Use Defense in Depth
  • Use Least Privilege
  • Backward Compatibility Will Always Give You Grief
  • Assume External Systems Are Insecure
  • Plan on Failure
  • Fail to a Secure Mode
  • Remember That Security Features != Secure Features
  • Never Depend on Security Through Obscurity Alone
  • Don’t Mix Code and Data
  • Fix Security Issues Correctly