署名付きタグって何?

Gitを使い始めて以来、ずっと飲み込めずに残っているのが、"署名付きタグ"という代物である。これ、どういうときに使うのだろうか?

あちらこちらのドキュメントを見ても、「署名もできて嬉しいね」としか書いていない。つまり、それが有益であることはたぶん一般的に自明のことなのである。が、恥ずかしながら俺はよくわからない。

よくよく考えて、なんとなく理解できたと思うので、メモしておきたい。

三種類のタグ

Gitでは、三種類のタグを作成できる。

  1. 軽量タグ
  2. 注釈付きタグ
  3. 署名付きタグ

"軽量タグ"は、CVSのタグのようなものである。特定のコミットにマークをつけるが、それだけ。

$ git tag v1.0

"注釈付きタグ"は、Subversionのタグのようなものである。タグをオブジェクトとして登録し、そこにコメントを含められる。

$ git tag -a v1.0 -m "バージョン1.0リリース。"

"署名付きタグ"は、"注釈付きタグ"に加えてGPG/PGPによる署名を施したものである。

$ git tag -s v1.0 -m "バージョン1.0リリース。"

"署名付きタグ"に対しては、検証を行える。つまり、タグ作成者の公開鍵を持っていれば、それが本当に"本人"なのかを確認できる。

$ git tag -v v1.0

さて、"軽量タグ"は、個人的な用途であれば便利だろう。そして、"注釈付きタグ"は一般的なタグとしての用途に使ってよい。しかし、"署名付きタグ"はどのような場面で使えばよいのだろう?これだけは既存のVCSバージョン管理システム)に類例がないので、意図がつかみづらいのだ。

署名

署名、つまりデジタル署名は、なりすましを防ぐための手段である。つまり、悪意ある人物が他人の名を騙ってコミットすることを防げる。*1

また、Gitにおけるあるコミットへの署名は、そのコミットから辿れる全てのファイルおよび全ての履歴への署名に等しい。Gitはそういう作りになっている。従って、あるコミットに署名付きタグがあれば、履歴全体が信頼できるものとなる。詳しくはGit ユーザマニュアル (バージョン 1.5.3 以降用)参照。

なぜ必要か

そういう理屈はわかっている。問題は、なぜ既存のVCSには同じような機能が存在しないのに、Gitでは存在するのか、である。単にGitが先進的だということなのか?

で、考えた。

リポジトリの認証は当てにならない

俺がひっかかったのは、「リポジトリで認証を済ませているだろうに、重ねて署名する必要あるの?」という点である。

例えば、Subversionのコミットにはこうした機能がない。というのも、Subversionリポジトリにコミットできているからには、そのリポジトリから事前に自分がアクセス権限を所有している正当なユーザであることを認められているはずだからだ。つまり、コミットできていること自体が、そのコミットが正当なユーザによる信頼できるものであることを証明している。

ところが、Gitのような分散型VCSでは、リポジトリは個人で所有する。これはユーザ設定からも明らかである。Subversionではユーザ情報をリポジトリ側に持つ。対するGitは、ユーザ情報を自分で設定する。つまり、自分が何者であるかなど騙り放題である。従って、コミットに記載されているユーザ名を信頼できない。

例えば、ある人物が厳重な防御を施してある公開サーバにidesakuというユーザでログインできているのであれば、それは俺自身だと思ってほぼ間違いないが、自分で立てたサーバにidesakuというアカウントを作ってログインできていると主張したところで、自分がidesakuであることの証明にはならない。これは当たり前のことである。

そのため、集中型VCSのように、リポジトリへの認証を持ってコミットを信頼することはできない。

コミットはリポジトリを渡り歩く

SubversionリポジトリrepoAにおけるr1000は、repoBにおけるr1000とは異なる。

GitのリポジトリrepoXにおけるコミット3b04533は、repoYにおける3b04533と同一である。

つまり、分散型VCSであるGitのコミットは特定のリポジトリに依存していない。push/pullであちらこちらのリポジトリに存在できる。従って、とあるリポジトリが信頼できるからといって、そこにある全てのコミットを無条件に信頼できるわけではない。そのコミットは元々は余所の信頼できないリポジトリで作成されたものかもしれないのだ。

従って、信頼はリポジトリに対してではなく、コミットに対して与えなければならない。

結論

集中型VCSであれば、リポジトリ自体の信頼を持ってその中のコミットもまた信頼できる。しかし分散型VCSではそうはいかないので、コミットに対して信頼を与える必要がある。それを支援する機能として"署名付きタグ"が存在する。

理屈の上では全てのコミットに対して信頼が必要なのだろうが、それは手間だしリポジトリのサイズも膨らむし、ということで任意のタイミングで特定のスナップショットとその履歴全体に一気に信頼を与える手段を提供している。

オープンソースのように不特定多数の人物が貢献するような開発環境だと、"署名付きタグ"は有効に機能する。しかし、受託開発のようなクローズドな環境であればおそらくその必要性は弱いので、"注釈付きタグ"で十分。

…ということだと思う。

これはGit同様の分散型VCS全てに言えることなので、他のVCSも同等の機能を持っているのでは、と思った。そこでとりあえずMercurialを当たってみたのだが、どうやらcoreには組み込まれていないが拡張機能として存在するようである。やはりGitだから、というより分散型VCSだから必要な機能であるようだ。

正しいかはわからないが、たぶんこういうことなんだろう。

*1:正しくは、コミットを後から検証できる。