Technology

Gitで署名付きCommitsやtagを作る

signcommits

Git で署名付きCommitを行うメモ

GitHubとかでCommitを見てると、GnuPGで署名されたCommitや、

Signed-off-by: John Doe <johndoe@example.com>

で署名+GnuPGの署名のついたCommitがありますよね

やってみましょう

GnuPG

まずはGPGをOS X MarvericksにはGnuPGが入っていないため、インストール

(前のSnow Leopard/Lionには入ってたような気がしてたけど勘違いかも)

sudo port install gnupg2

前準備として.bashrcなどにgpg-agentと、TTYの設定をしておきます
(source .bashrcを忘れないように!)

#GnuPG2
pgrep -q gpg-agent || eval $(gpg-agent --daemon --write-env-file ${HOME}/.gpg-agent-info)
[ -f ${HOME}/.gpg-agent-info ] && source ${HOME}/.gpg-agent-info
export GPG_AGENT_INFO
export GPG_TTY=`tty`

鍵の生成

鍵が無いと始まらないので生成
昔鍵を無くしてREVOKEできなくて後悔したので2年でexpireするように作っておきます

[kota@MBP ~]$ gpg2 --gen-key
gpg (GnuPG) 2.0.22; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection?
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
        = key expires in n days
      w = key expires in n weeks
      m = key expires in n months
      y = key expires in n years
Key is valid for? (0) 2y
Key expires at 日  1/24 02:59:37 2016 JST
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: John Doe
Email address: johndoe@example.com
Comment: What You Need Is What You Get!!
You selected this USER-ID:
    "John Doe (What You Need Is What You Get!!) <johndoe@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
You need a Passphrase to protect your secret key.

鍵のIDをクリップボードにでもコピりましょう(この場合)5FE1D7EF

[kota@MBP ~]$ gpg2 --list-keys
/Users/kota/.gnupg/pubring.gpg
------------------------------
pub   4096R/5FE1D7EF 2014-01-23 [expires: 2016-01-23]
uid                  John Doe (What You Need Is What You Get!!!) <johndoe@example.com>
sub   4096R/8DDF7B60 2014-01-23 [expires: 2016-01-23]

公開鍵を鍵サーバーに送る(反映されるまでしばしかかります)

[kota@MBP ~]$ gpg2 --send-keys -v 5FE1D7EF
gpg: sending key 5FE1D7EF to hkp server keys.gnupg.net

登録されてるか調べるには?

[kota@MBP ~]$ gpg2 --search-keys johndoe@example.com
gpg: searching for "johndoe@example.com" from hkp server keys.gnupg.net
(1)	John Doe (lol) <johndoe@example.com>
	  1024 bit DSA key BCBD4058, created: 2013-10-27
(2)	John Doe <johndoe@example.com>
	  1024 bit DSA key A9034779, created: 2002-11-20
Keys 1-2 of 2 for "johndoe@example.com".  Enter number(s), N)ext, or Q)uit >

念のためrevoke keyも作っておきましょう
(万が一無くした時本当に残念です)

[kota@MBP ~]$ gpg2 --gen-revoke 5FE1D7EF > .gnupg/revoke.key

sec  4096R/5FE1D7EF 2014-01-23 John Doe (What You Need Is What You Get!!!) <johndoe@example.com>

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision?
Enter an optional description; end it with an empty line:
>
Reason for revocation: Key has been compromised
(No description given)
Is this okay? (y/N)
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision?
Enter an optional description; end it with an empty line:
>
Reason for revocation: Key has been compromised
(No description given)
Is this okay? (y/N) y

You need a passphrase to unlock the secret key for
user: "John Doe (What You Need Is What You Get!!!) <johndoe@example.com>"
4096-bit RSA key, ID 5FE1D7EF, created 2014-01-23

ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

Git+ GnuPGの設定

ここからやっとgitの設定

git config --global gpg.program gpg2
git config --global user.signingkey 5FE1D7EF

これで完了!GPG-signed Commitをしてみましょう
ダイアログが出てきてpassphraseの入力が求められるはず
(最初の.bashrcんとこでgpg-agentを立ち上げているので、一回passphraseを入れればgpg-agentを終了するまで再入力は不要です)

[kota@MPB ~]$ mkdir repo
[kota@MPB ~]$ cd repo/
[kota@MPB ~/repo]$ git init .
Initialized empty Git repository in /Users/kota/repo/.git/
[kota@MPB ~/repo]$ touch README.md
[kota@MPB ~/repo]$ git add README.md
[kota@MPB ~/repo]$ git commit -S -m 'Sign !!!'

You need a passphrase to unlock the secret key for
user: "John Doe <johndoe@example.com>"
4096-bit RSA key, ID 5FE1D7EF, created 2014-01-24
[master e5fc7b0] Sign !!!
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md

おまちかね、署名を検証してみましょう

[kota@MBP ~/repo]$ git log --show-signature HEAD
commit 5FE1D7EF
gpg: Signature made 金  1/24 03:19:35 2014 JST using RSA key ID 5FE1D7EF
gpg: Good signature from "John Doe <johndoe@example.com>"
Author: John Doe <johndoe@example.com>
Date:   Fri Jan 24 03:18:56 2014 +0900

    Sign !!!

gpg: の行が青色になっていれば検証に成功しています

Signed-off-by: も一緒につけて、tag v0.1を付けるならこんな感じでしょうか

git tag -s v0.1 -m 'Tag + Sign'
You need a passphrase to unlock the secret key for
user: "John Doe <johndoe@example.com>"
4096-bit RSA key, ID 5FE1D7EF, created 2014-01-12

tagの検証

[kota@MBP ~/repo]$ git tag --verify v0.1
object 6ba00ec668ad9472bc5d5eeeff9f1f9fac396110
type commit
tag v0.1
tagger John Doe <johndoe@example.com> 1390504243 +0900

Sign !!!
gpg: Signature made 金  1/24 04:10:43 2014 JST using RSA key ID 5FE1D7EF
gpg: Good signature from "John Doe <johndoe@example.com>"

Good signatureが表示されてますね!

公開リポジトリの署名を検証する

さて、とりあえず自分のtag/commitは検証できるのですが、このまま他人の公開鍵を入れてないので当然検証できません。
試しにLinusの署名を検証してみましょうw

Linusの公開鍵を探して取り込みます

[kota@MBP ~]$ gpg2 --search-keys "torvalds@linux-foundation.org"
gpg: searching for "torvalds@linux-foundation.org" from hkp server keys.gnupg.net
(1)	Linus Torvalds <torvalds@linux-foundation.org>
	  2048 bit RSA key 00411886, created: 2011-09-20
Keys 1-1 of 1 for "torvalds@linux-foundation.org".  Enter number(s), N)ext, or Q)uit > 1
gpg: requesting key 00411886 from hkp server keys.gnupg.net
gpg: key 00411886: public key "Linus Torvalds <torvalds@linux-foundation.org>" imported
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   2  signed:   1  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: depth: 1  valid:   1  signed:   0  trust: 1-, 0q, 0n, 0m, 0f, 0u
gpg: next trustdb check due at 2016-01-12
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

とりあえず今は彼を信頼しておきましょう
公開鍵に署名します

[kota@MBP ~]$ gpg2 --sign-key "Linus Torvalds"

pub 2048R/00411886 created: 2011-09-20 expires: never usage: SC
 trust: unknown validity: unknown
sub 2048R/012F54CA created: 2011-09-20 expires: never usage: E
[ unknown] (1). Linus Torvalds <torvalds@linux-foundation.org>

pub 2048R/00411886 created: 2011-09-20 expires: never usage: SC
 trust: unknown validity: unknown
 Primary key fingerprint: ABAF 11C6 5A29 70B1 30AB E3C4 79BE 3E43 0041 1886

Linus Torvalds <torvalds@linux-foundation.org>

Are you sure that you want to sign this key with your
key "Kota Shiratsuka <kota@insaneworks.co.jp>" (73FA2F86)

Really sign? (y/N) y

You need a passphrase to unlock the secret key for
user: "John Doe <johndoe@example.com>"
4096-bit RSA key, ID 5FE1D7EF, created 2014-01-12

Linuxのgit repoをcloneします。(本気で重いので注意)

[kota@MBP ~/Downloads]$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Cloning into 'linux'...
remote: Counting objects: 3371568, done.
remote: Compressing objects: 100% (509547/509547), done.
remote: Total 3371568 (delta 2837672), reused 3366608 (delta 2832943)
Receiving objects: 100% (3371568/3371568), 704.94 MiB | 3.88 MiB/s, done.
Resolving deltas: 100% (2837672/2837672), done.
Checking connectivity... done.
Checking out files: 100% (45290/45290), done.
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
[kota@MBP ~/Downloads]$ cd linux
[kota@MBP ~/Downloads/linux]$

Linux v3.13のtagにLinusの署名があるか確認するには、、?

[kota@MBP ~/Downloads/linux]$ git verify-tag v3.13
gpg: Signature made 月  1/20 11:40:23 2014 JST using RSA key ID 00411886
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   2  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: depth: 1  valid:   2  signed:   0  trust: 2-, 0q, 0n, 0m, 0f, 0u
gpg: next trustdb check due at 2016-01-12
gpg: Good signature from "Linus Torvalds <torvalds@linux-foundation.org>"

Good signatureがありますね!Linuxが署名しているとわかります。

これをどう使うか、、Linux Kernelほど巨大であればこのような仕組みは必須ですね。

小規模なプロジェクトでの有効活用はそうだな、、verifyしなきゃdeployが走らないシステムとか、、?ですかね?

ちょっと思いつかないですが、tagを打つ時は署名するのがよさげですね!

参考

A Git Horror Story: Repository Integrity With Signed Commits

Linux カーネルに変更を加えるための Howto

とあるエンジニアの備忘log: パッチを投稿しよう!

辞書で引けない技術英語 2006年08月

コメントを残す