Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/vlaci/git-agecrypt


https://github.com/vlaci/git-agecrypt

Last synced: 29 days ago
JSON representation

Awesome Lists containing this project

README

        

# git-agecrypt

Git integration usable to store encrypted secrets in the git repository while having the plaintext available in the working tree. An alternative to [git-crypt](https://github.com/AGWA/git-crypt) using [age](https://age-encryption.org) instead of GPG.

Do not use this tool unless you understand the security implications. I am by no mean a security expert and this code hasn't been audited. Use at your own risk.

## Why should I use this?

Short answer: you probably shouldn't. Before considering this approach, take a look at [SOPS](https://github.com/mozilla/sops) and [Hashicorp Vault](https://www.vaultproject.io/) if they are better suited for the problem at hand. **They have a clear security advantage** over `git-agecrypt`.

The one use-case where it makes sense to use `git-agecrypt` instead is when you want to keep some files secret on a (potentially public) git remote, but you need to have the plaintext in the local working tree because you cannot hook into the above tools for your workflow. **Being lazy is not an excuse to use this software.**

I have written this to have a more portable and easy to set up alternative to `git-crypt`.

## Usage

1. First setup `git-agecrypt` integration for a repository:

```console
$ git-agecrypt init
```

This command configures the necessary hooks to encrypt and decrypt git objects and to generate clear-text output for `git diff`, `log` etc.

2. Next step is to configure rules to map encryption keys to file paths:

```console
$ git-agecrypt config add -r "$(cat ~/.ssh/id_ed25519.pub)" -p path/to/secret.1 path/to/secret.2
```

An arbitrary number of recipients (public keys) and files can be specified using a single command. Keys can be Age keys, ed25519 SSH keys or stubs generated by Age plugins, e.g. for keys stored on Yubikey PIV module. It is enough to have only one secret key to decrypt the files later.

Configuration is saved to `git-agecrypt.toml` file inside the root of the repository

3. After that, edit `.gitattributes` to actually use these filters. This is currently a manual step.

```gitattributes
path/to/secret.1 filter=git-agecrypt diff=git-agecrypt
path/to/secret.2 filter=git-agecrypt diff=git-agecrypt
```

Files can be specified in the same way as for `.gitignore` but keep in mind that filters are only applied for files, not directories, so that you need to write `/secrets/**` instead of `/secrets/` to encrypt each file under the `secrets` directory.

4. Finally, configure the locations of age identities (private keys) which can be used to decrypt files

```console
$ git-agecrypt config add -i ~/.ssh/id_ed25520
```

Location of secret keys are stored outside of version control in `.git/config` to support having them in different location for each checkout.

## Behind the scenes

This application hooks into git using [`smudge` `clean` and `textconv` filters](https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes). Issuing `git-agecrypt init` adds them to the repository local `.git/config`:

```gitconfig
[filter "git-agecrypt"]
required = true
smudge = /path/to/git-agecrypt smudge -f %f
clean = /path/to/git-agecrypt clean -f %f
[diff "git-agecrypt"]
textconv = /path/to/git-agecrypt textconv
```

These filters are assigned to repository files in `.gitattributes`. When configured, they are being called for each file when touching the index. Encryption is non-deterministic, so each time `git status`, `git add`, etc is run a new ciphertext would be generated. To circumvent this, a [blake3](https://github.com/BLAKE3-team/BLAKE3) hash is calculated for the plaintext and stored under `.git/git-agecrypt/` directory. While the hashes stored match with the file contents in the working tree, `git-agencrypt` loads the previous ciphertext from the index when git asks for it.

Encryption can work without access to private keys (what Age calls identities). In order to pull remote changes of encrypted files or to see plain diff of files, these have to be configured with `git-agecrypt config`. They are stored in `.git/config` conforming to standard git config format:

```gitconfig
[git-agecrypt "config"]
identity = /home/vlaci/.ssh/id_ed25519
identity = ...
```

## Limitations

The following limitations can be easily improved upon, but they are not blockers for my use-case.

- The application is started once for each file for every git operation. It can cause slowdown when the repository contains many encrypted files. A possible mitigation for this issue could be the implementation of the [long-running process protocol](https://github.com/git/git/blob/master/Documentation/technical/long-running-process-protocol.txt) but it is usable as it is for a couple of small files.

- During encryption/decryption the whole file is loaded into memory. This can cause issues when encrypting large files.