Introduction
git-cipher
is a utility script for encrypting sensitive files for storage in a
public Git repo.
Usage
git cipher encrypt [FILES...] # encrypts files
git cipher decrypt [FILES...] # decrypts files
git cipher log [FILES...] # shows log with (plaintext) diffs
git cipher help
Installation
git-cipher
is a single Ruby script with no major dependencies beyond
Ruby, Git, and
GnuPG. As such, it can be run directly from the repo:
git clone https://github.com/wincent/git-cipher.git
Alternatively, you can install the Gem:
gem install git-cipher
Note: If you install the git-cipher
executable somewhere in your $PATH
,
Git will treat it as a subcommand, which means you can invoke it as git cipher
. Otherwise, you will have to provide the full path to the git-cipher
executable.
To install the external prerequisites, use your preferred method. For example, on OS X you might choose to use Homebrew:
brew install git gnupg gpg-agent
Configuration
Selecting a key for encryption and decryption
There are three ways to override the default signing key (which is
[email protected]
and probably not useful to anybody other than me):
GPG_USER
environment variable
1. Set the [email protected] git cipher decrypt
# or alternatively:
export [email protected]
git cipher decrypt
git-config
to set cipher.gpguser
2. Use git config cipher.gpguser [email protected] # per-repo
git config --global cipher.gpguser [email protected] # globally
DEFAULT_GPG_USER
in the git-cipher
source
3. Edit This last may be appropriate if you've installed by cloning the Git repo.
Architecture
This section describes the background and rationale for the design of
git-cipher
.
git-cipher
was originally developed within the context of an
Ansible-powered configuration repo. Some
of the files contained sensitive information so I couldn't commit them to the
repo as plaintext, but I did still want to version control them, so needed to
encrypt them prior to committing.
At the time (prior to version 1.5) Ansible didn't have the Vault feature
(equivalent to Chef's encrypted data bags), so the git-cipher
was developed.
When the Vault feature did arrive, I decided to continue using git-cipher
because I liked the convenience of being able to work using my normal editor and
Ansible workflow (Vault requires you to edit files through the ansible-vault
command, and pass special arguments to ansible-playbook
when running
playbooks).
git-cipher
stores encrypted versions of sensitive files in the Git repo with
an .encrypted
file extension. Before running Ansible commands, we decrypt the
necessary files with git cipher decrypt
. This works well because Ansible
doesn't employ a client-server architecture like Chef or Puppet; it suffices to
have the decrypted files available on the local machine where the repo is
checked out and the commands are run.
The plain-text versions of the encrypted files should be ignored via the
gitignore mechanism (although that is only a recommendation and git-cipher
does nothing to enforce the policy, beyond printing a warning when it sees that
the plaintext version of an encrypted file is not being ignored).
This approach compares to using git encrypt
as recommended in "An
example of provisioning and deployment with
Ansible".
There are a couple of problems with that approach; one is that it uses
"deterministic
encryption" in the name of
convenience, while noting that it is insecure. Additionally, a lengthy thread
on the Git mailing
list argues that
this is an abuse of the clean/smudge filtering system.
We use semantically secure GPG encryption and make use of timestamp
comparisons to avoid unnecessary churn (in other words, we only update the
encrypted version of a file if the plain text version is newer). Note that we
effectively trust the local system's integrity, relying on filesystem
encryption, filesystem permissions, and the general security of the system to
keep the plain-text safe. Also note that, like the clean/smudge filtering, we
are effectively forgoing some of the niceties that Git offers (compression,
meaningful diffs etc) in exchange for security. (But note: you can also split
your encrypted content across smaller individual files and then pull the values
from those files into a template, preserving the ability to get meaningful diffs
of the template files themselves. The log
subcommand also goes some way
towards providing visualization of change over time in encrypted files.)
Although git-cipher
can be obtained as a RubyGem, the executable itself is,
by-design, a single file. This is to reduce the dependency footprint, making it
more suitable for use in boot-strapped environments (which might not have
RubyGems installed yet).
Tips
You may see prompts like the following, depending on the trust level of your signing key:
It is NOT certain that the key belongs to the person named
in the user ID. If you *really* know what you are doing,
you may answer the next question with yes.
You can avoid these prompts by setting the trust level to "ultimate" like this:
gpg --edit-key [email protected] # or $GPG_USER
> trust
> quit
Author
git-cipher
was hacked together by Greg Hurrell ([email protected]).
Development
This is minimal, currently with no tests, no Bundler, no Rakefile. To cut a new release, update the version number in the gemspec and:
git tag -s 0.2 -m "0.2 release"
git push --follow-tags origin master
gem build git-cipher.gemspec
gem push git-cipher-0.2.gem
License
git-cipher
is licensed under the MIT license. See the LICENSE.txt
file in
the git-cipher
repo for more details.