Gitの初期設定で自分の名前やメールアドレスを入力するわけですが、特に認証などが入るわけではないので簡単に他人になりすましが出来てしまいます。そこで確かに自分がコミットまたはタグを付けたことを証明するために、署名を付けることができます。
GitHubを眺めていると見かける、コミットログの横に「Verified」バッジが表示されているのがそれです。
例えばプルリクを受け取った人が、なりすましを行った悪意のある第三者から送られてきたかどうか判断する手助けになるというわけですね。また同様にコミットやタグが改ざんされているかも検知することができます。
準備
署名を行うためのGnuPGをインストール、実際にGPG鍵を作成します。秘密鍵と公開鍵ができますので、公開鍵の方をGitHubに登録するという手順で進行します。
よく「GPG」か「PGP」なのか分からなくなりますw GNUであることを思い出せるかが鍵ですねw
あ、書き忘れてましたがここでは macOS Catalina 10.15.7 で作業をしていきます。
GPGのインストール
macOSの場合はHomeBrewで一発です。
$ brew install gpg
今回はGPG 2.3.2が入りました。
$ gpg --version gpg (GnuPG) 2.3.2 libgcrypt 1.9.4 Copyright (C) 2021 Free Software Foundation, Inc. License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
GPG鍵の生成
では早速鍵の作成を行います。gpg --gen-key
コマンドを実行すると名前とメールアドレスを聞かれますので適当に入力、アルファベットのオー(O)を入力します。
$ gpg --gen-key (略) 本名: Makito Katsube 電子メール・アドレス: katsubemakito@gmail.com 次のユーザIDを選択しました: "Makito Katsube <katsubemakito@gmail.com>" 名前(N)、電子メール(E)の変更、またはOK(O)か終了(Q)? O
次にこの鍵にパスフレーズ(パスワード)の設定を求められます。入力した内容は絶対に忘れないよう必ずメモを取ってください。もし忘れても誰も助けてくれません。
ここまでエラーなど表示されていなければ無事に秘密鍵が作成されています。
GPG公開鍵をエクスポート
GitHubへ登録するための公開鍵を出力します。
まずは現在のPC内に保管されているGPG鍵の一覧を表示してみます。この中の「286AF〜」の部分が鍵のIDになるので、これをメモします。
$ gpg -k pub ed25519 2021-09-24 [SC] [有効期限: 2023-09-24] 286AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF uid [ 究極 ] Makito Katsube <katsubemakito@gmail.com> sub cv25519 2021-09-24 [E] [有効期限: 2023-09-24]
鍵のIDを指定してエクスポートします。
$ gpg -a --export 286AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF > katsube_gpg.pub
GitHubへ公開鍵を保存
先ほど出力した公開鍵をクリップボードに持ってきます。macOSの場合はpbcopyコマンドが便利ですね。
$ cat katsube_gpg.pub | pbcopy
ではGitHub上で操作をしていきます。まずはGitHubの右上のメニューから「Settings」をクリック。
左メニューから「SSH & GPG keys」をクリック。
「New GPG key」ボタンをクリック
するとテキストエリアが表示されますので、クリップボードに入っている公開鍵をそのままペーストし送信ボタンを押せば完了です。簡単ですね。
GitにGPG関連の設定を追加
最後に.gitconfigの設定を行います。
署名するのに先ほどインストールしたGPGを指定、またどの署名を使うのか鍵のIDも指定します。
$ git config --global gpg.program gpg $ git config --global user.signingkey 286AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
すべてのコミットやタグに署名を付けるなら以下のコマンドも実行します。後から無効にしたい場合はtrueの箇所をfalseにしてもう一度実行するか、テキストエディタなどで.gitconfigを直接編集し該当の箇所を削除します。
$ git config --global commit.gpgsign true $ git config --global tag.gpgsign true
実際に試してみる
コミット
いつもどおりcommitするところに-S
オプションを付けるだけです。.gitconfigで常に署名するオプションを指定している場合はこのオプションも不要です。
$ git commit -S -m '1st commit' $ git push
GitHub上でcommitログを確認すると「Verified」バッチが付くようになりましたね。クリックするともう少し詳細な情報も表示されます。
タグ
タグの場合は-s
オプションを付けます。コミットとの時と異なり小文字である点に注意が必要です。こちらも.gitconfigで常に署名するオプションを指定している場合は指定不要です。
$ git tag -s v1.0 -m '1st version' $ git push --tags
こちらもGitHub上で確認すると「Verified」バッチが付くようになります。同様にクリックするともう少し詳細な情報も表示されます。
パスフレーズを毎回入力したくない
さすがに高頻度で聞かれるのは面倒ですよね。こちらのサイトを参考にさせていただき、PinentryというGnuPG製のソフトを導入します。
インストール
いつも通りbrewで一発です。
$ brew install pinentry-mac
設定ファイルを追加します。~/.gnupg
は最初にgpgをインストールした際に作成されています。
$ echo 'pinentry-program /opt/homebrew/bin/pinentry-mac' > ~/.gnupg/gpg-agent.conf
すでに起動中のプロセスがあるとうまく動かないので停止します。
$ gpgconf --kill gpg-agent
試してみる
適当な内容でファイルを編集しコミットすると、初回だけ以下のようなダイアログが表示されパスフレーズを聞かれます。パスフレーズを入力後に必ず「Save in Keychain」にチェックをした上でOKボタンをクリックします。
これで次回以降はパスフレーズを聞かれることが無くなります。実際にTerminalのウィンドウを閉じ、もう一度開いて試してみてください。またここではコミットで試していますがタグも同様に聞かれなくなります。
その他
git logで署名付きか確認
git logコマンドに--show-signatureオプションを付けると各コミットの署名の有無をチェックできます。
$ git log --show-signature 1f802290b72be948f8311ea871417cab985a57a4 commit 1f802290b72be948f8311ea871417cab985a57a4 (tag: v1.0) gpg: 金 9/24 18:03:28 2021 JSTに施された署名 gpg: EDDSA鍵286AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFを使用 gpg: "Makito Katsube <katsubemakito@gmail.com>"からの正しい署名 [究極] Author: Makito Katsube <katsubemakito@gmail.com> Date: Fri Sep 24 18:03:28 2021 +0900 1st commit
秘密鍵のバックアップ
PCは消耗品ですからいずれ壊れます。作業が一段落したら忘れる前に秘密鍵を失う前にバックアップを行っておいた方が安全ですね。パスフレーズの入力が必要です。
$ gpg --export-secret-keys --armor > gpg-private.keys
復旧する場合は以下のコマンドです。
$ gpg --import gpg-private.keys
fatal: failed to write commit object
当初、署名付きのコミットを行おうとすると以下のようなエラーが出てしまいました。
$ git commit -S -m '1st commit' error: gpg failed to sign the data fatal: failed to write commit object
Gitを通さずに直接GPGで署名してみると、具体的なエラー内容がわかったのでググって調べると、
$ echo "test" | gpg --clearsign gpg: 署名に失敗しました: Inappropriate ioctl for device gpg: [stdin]: clear-sign failed: Inappropriate ioctl for device
Terminal上で以下の環境変数を定義することで回避できました。忘れないうちに.zshrcへ転記しておきます。
$ export GPG_TTY=$(tty)
トラブルシューティング
エラー「Pinentryがありません」
ちょっと前に書かれた記事を参考にしながらPinentryをHomebrewでインストールした場合、以前とパスが変更になっているためPinentryが存在しないといった旨のエラーが出ます。
$ git commit -m 'foobar' error: gpg failed to sign the data: [GNUPG:] KEY_CONSIDERED FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 2 [GNUPG:] BEGIN_SIGNING H10 gpg: 署名に失敗しました: Pinentryがありません [GNUPG:] FAILURE sign 67108949 gpg: signing failed: Pinentryがありません
ちょっと前までは以下のコマンドを実行していましたが、
$ echo 'pinentry-program /usr/local/bin/pinentry-mac' > ~/.gnupg/gpg-agent.conf
現在は次のコマンドを実行します。現在のプロセスをKillするのも忘れずに。
$ echo 'pinentry-program /opt/homebrew/bin/pinentry-mac' > ~/.gnupg/gpg-agent.conf $ gpgconf --kill gpg-agent