git管理ファイルを透過的に暗号化するgit用フィルタを作った

この記事は[株式会社ネクスト(Lifull) Advent Calendar 2016](http://qiita.com/advent-calendar/2016/lifull)の8日目です。

最近社内でも一部で使われ始めてるgolangですが、遅ればせながら手を出してみました。
テストが書きづらいのはありますが、書いてて楽しいのでもっと色々試してしっかりかけるようになりたいと思える言語ですね。

そんなわけで今回はgolangの勉強も兼ねて、gitでファイルを透過的に暗号化・復号化するフィルタを作ったので、使い方について本記事にまとめたいと思います。（golangのコードは１行もでてきません。）
フィルタの用途としてはパスワードやシークレットキーなどをgitで管理したい場合を想定しています。

関連する内容として過去に以下のような記事を書いています。
[git管理対象のファイルを暗号化して利用する](http://qiita.com/ikeisuke/items/d7ee904d23745c758a7d)
[golangで書くunix domain socketを使ったserver/clientのサンプルコード](http://qiita.com/ikeisuke/items/f5eccc178ed388aac92f)


# 開発環境

```bash
$ uname -v
Darwin Kernel Version 16.1.0: Thu Oct 13 21:26:57 PDT 2016; root:xnu-3789.21.3~60/RELEASE_X86_64
$ go version
go version go1.7.4 darwin/amd64
$ git --version
git version 2.9.3 (Apple Git-75)
```


最新(2016/12/8現在)のAmazonLinuxでも動作確認しています

```bash
$ git --version
git version 2.7.4
$ cat /etc/os-release
NAME="Amazon Linux AMI"
VERSION="2016.09"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2016.09"
PRETTY_NAME="Amazon Linux AMI 2016.09"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2016.09:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
```

# Gitのフィルタについて

gitでは管理対象ファイルをstaging/checkoutする直前に特定のファイルにフィルタを適用する仕組みがあります。
このフィルタを使うと、改行コードをCRLFからLFに自動で変換してstagingしたり、画像ファイルのdiffを取る際に画像そのものを比較するのではなくExif情報を比較する、というようなことができます。
今回は、その機能を使って透過的に暗号化・復号化の処理を行っています

gitのフィルタについて詳しくは以下のリンクを参照してください。

[Git のカスタマイズ - Git の属性](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%81%AE%E5%B1%9E%E6%80%A7#filters_a)

# 利用方法

## 事前準備

以下の二つのリポジトリに分かれています。
### gitから呼ばれるフィルタ
https://github.com/ikeisuke/git-encrypt-kms
以下のようにcloneしてPATHを設定するだけです。

```bash
$ git clone https://github.com/ikeisuke/git-encrypt-kms
$ PATH=${PATH}:/path/to/git-encrypt-kms
```
### フィルタから利用される暗号化用キー管理・暗号化エージェント
https://github.com/ikeisuke/git-encrypt-agent/releases

アーカイブファイルをMac/Linux用に用意していますので対応したファイルをダウンロードしてPATHの通った場所に設置してください。
git-encrypt-kms内に設置しても構いません。

## KMSのキーの登録とアクセスキー、シークレットの端末へ登録

以下の対応を行います。

- 今回利用するためのKMSのキーを作成し、対象のIAM User/Roleに権限を付与する
- AWS Access Key ID, Secret Access Key を取得し設定する
  - EC2でIAM Roleを利用する場合には特に設定は不要
 
## フィルタ利用のための初期設定

<font color="red">暗号化・復号化に失敗するとファイルが空になったり、復号化できないファイルになってしまうことがあるので、これ以降のコマンドはgitリポジトリのデータを全てcommit or stashしリポジトリが綺麗な状態で行ってください。</font>

以下のコマンドを実行します。
「Input Specified key for AWS KMS」はデータキーを作成する初回のみ表示されます。

```bash
$ cd /path/to/repository
$ git checkout -b encrypt_secret_data
$ git encrypt --install
Input your aws profile []: [profilename]
Input region to use []: ap-northeast-1
Input Specified key for AWS KMS []: [kms-key-id]
```

```git encrypt --install``` は暗号化ファイルを含む各リポジトリに対して各ユーザーが行う必要があります。
また、新規にcloneし直した場合もフィルタの登録が一部削除される為、改めて実行する必要があります。

## フィルタ適用対象の登録

パスはリポジトリルートからの相対パスで登録します。

```bash
$ git add-pattern path/to/file
$ git add-pattern 'path/to/secret/*'
```

## 暗号化済みデータキーと属性管理ファイルのコミット

作成した暗号化済みのデータキーとフィルタ適用対象を管理するファイルをコミットします。

```bash
$ git add .gitattribute
$ git add .gitdatakey
$ git commit -m 'Add encryption data key and git attribute file'
```

※*を含む場合には必ず''で囲む必要がるので注意してください。

## 暗号化ファイルのコミット

すでにバージョン管理中のファイルを暗号化するためには一旦indexをリセットする必要があります。
また、新規の場合にはそのまま設置するだけで、対象ファイルに含まれていれば暗号化処理対象となります。

```bash
$ rm -rf .git/index
$ git reset
$ cp /path/to/secret/* secret/
$ git add .
$ git commit -m 'Add secret data'
```

## 暗号化と復号化の検証

暗号化・復号化は透過的に行われるため、そのままでは暗号化されたかどうかも確認できません。
別のディレクトリに今回のコミットをcloneして確認します。

```bash
$ cd /path/to/tmp
$ git clone /path/to/repository test
$ cd test
$ cat path/to/secret # 暗号化されている
$ git encrypt --install
$ git reset --hard
$ cat path/to/secret # 複合化されている
```

以上で、暗号化・複合化の設定・確認は終わりです。
これ以降は透過的に暗号化されるようになります。