1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

age で暗号化ファイルを git 管理(git-secret からの移行)

1
Posted at

暗号化したファイルを git 管理する際に、これまで git-secret を使ってきたリポジトリがあります。

git secret を使うには GPG (GnuPG) が必要で、環境整備に少々手間がかかるし、少々の知識も必要です。私も、PC を買い替えたときには、毎回手順を忘れてる。

そこで、『もともと SSH 鍵を運用している』かつ『GPG までは必要ないが平文テキストは残せない』という環境において、age を使って git secret に近いことをできる構成を考えてみました。

本提案は、ローカル環境だけでなくて、GitHub Actions などの CI/CD 環境にも応用できそう。

トークンなどたくさんの secret が増えてくると、それらを CI に登録管理するのは面倒になってくるけど、secret には SSH 鍵 1 本だけを登録しておけば、あとは CI でもローカルと同じ手順で復号できるようになる。トークンを rotate する時も、github の画面にアクセスせずに、git commit 1回で済む。CI の secret 管理とローカルの secret 管理を同じ仕組みに集約できる。

git-secret との比較

観点 git-secret 本提案
必要ツール gpg, git-secret age, (npm)
鍵の流用 GPG 鍵を新規作成・配布 既存の SSH 鍵をそのまま使える
recipients ユーザの追加 git secret tell [email] .age-keys に1行追記
recipients の git 履歴 .gitsecret/keys/pubring.kbx バイナリなので diff が見えない .age-keys はテキストなので diff で確認できる
github からの公開鍵入手 https://github.com/[user].gpg https://github.com/[user].keys
暗号化対象ファイルの追加 git secret add [file] .age-paths に1行追記
対象ファイルの git 履歴 .gitsecret/paths/mapping.cfg (平文のSHA付) .age-paths (◯ ファイル名のみ)
暗号化したファイルの拡張子 *.secret *.age
暗号化の実行 git secret hide npm run age:hide
複合化の実行 git secret reveal npm run age:reveal

既に SSH 鍵を運用しているなら、追加で GPG やほかの暗号化ツールの管理に悩まずに済む、というのがシンプルなメリットです。

package.json の scripts

下記の age:hideage:reveal を package.json に登録する。

{
  "scripts": {
    "age:hide":   "grep '^[^#]' .age-paths | while read -r f; do age -R .age-keys -o \"${f}.age\" \"$f\" && echo hidden: $f; done",
    "age:reveal": "identity=$(ls ~/.ssh/id_ed25519 2>/dev/null || echo ~/.ssh/id_rsa) && grep '^[^#]' .age-paths | while read -r f; do age -d -i \"$identity\" -o \"$f\" \"${f}.age\" && echo revealed: $f; done"
  }
}

ここで、暗号化・復号化コマンドの実行時に npm を使うのは、Node.js のプロジェクトだからです。単に age を起動しているだけなので、Makefile 他の手段でもよい。

構成ファイルの差

git secret hide の場合

project/
├── .gitignore              # 平文ファイルを ignore する
├── .gitsecret/
│   ├── keys/
│   │   ├── pubring.kbx     # バイナリ(公開鍵を格納)
│   │   ├── trustdb.gpg     # バイナリ
│   │   └── random_seed     # バイナリ
│   └── paths/
│       └── mapping.cfg     # 暗号化対象ファイル一覧(ファイル名+平文のハッシュ値)
├── secret.txt              # 平文 (gitignored)
└── secret.txt.secret       # 暗号化版 (commit 対象)

主役は .gitsecret/keys/pubring.kbx (GPG キーリング) で、これがバイナリかつ実装依存。

npm run age:hide の場合

project/
├── .gitignore              # 平文ファイルを ignore する
├── .age-keys               # recipients (SSH 公開鍵リスト)
├── .age-paths              # 暗号化対象ファイル一覧(ファイル名のみ)
├── package.json            # age:hide / age:reveal scripts
├── secret.txt              # 平文 (gitignored)
└── secret.txt.age          # 暗号化版 (commit 対象)

.age-keys.age-paths はどちらも cat で中身が読めるし、コメントも書ける。また、git diff で差分確認できるのが安心。

.age-keys の中身

暗号化ファイルを復号化できるユーザの SSH 公開鍵のリスト。コメント可。
公開鍵は、GitHub ユーザなら https://github.com/[user].keys から取得できる。

# age recipients
# このリポジトリの secrets を復号できる SSH 公開鍵

# Alice (workstation)
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxxxxxx alice@workstation

# Bob (laptop)
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIyyyyyyy bob@laptop

# CI
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIzzzzzzz ci-runner

.gitsecret/keys/ との対比になるので、.age-keys というファイル名にしています。
あるいは、git-secret 環境との関連がなければ、age の引数 -R 由来で .age-recipients` にしてもよいかも。

.age-paths の中身

暗号化したいファイルのパスを並べるだけ。コメント可。

# 暗号化したいファイルを追記して npm run age:hide
config/credentials.json
secret/api-token.txt
.env

運用フロー

初期化

# 自分の秘密鍵で開けられるように、自分の公開鍵を登録
cat ~/.ssh/id_ed25519.pub >> .age-keys

# 対象ファイルの登録
ls .env secret/credentials.json >> .age-paths

# 対象ファイルの git 除外
ls .env secret/credentials.json >> .gitignore

# 対象ファイルの暗号化
npm run age:hide

# git 登録
git add .age-keys .age-paths .env.age secret/credentials.json.age
git commit -m "secret: 初期暗号化"

recipients (人やマシン) を追加

curl -sS https://github.com/[user].keys >> .age-keys
npm run age:hide       # 全ファイル再暗号化
git add .age-keys *.age
git commit -m "secret: new-user を recipients に追加"

平文を編集して再暗号化

npm run age:reveal     # *.age → 平文 復号
vi .env
npm run age:hide       # 平文 → *.age 再暗号化
git add *.age
git commit -m "secret: .env を更新"

別マシン (.age-keys 登録済) で復号

git pull
npm run age:reveal     # 手元の ~/.ssh/id_ed25519 で復号

まとめ

  • .age-keys (recipients リスト) と .age-paths (対象ファイルリスト) の テキスト 2 ファイル だけで git-secret 相当のことを実現
  • 既存の SSH 公開鍵をそのまま recipients に使えるので、新規 GPG 鍵を作る必要がない
  • npm run age:hide / age:reveal の 2 つで運用が完結
  • recipients・対象ファイルリストはテキストなので、diff がテキストで読める
  • ローカル開発と CI 環境の secret 管理を、SSH 鍵で統合して、履歴管理できる

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?