Git
Chapters ▾ 2nd Edition

7.4 Git 도구 - 내 작업에 서명하기

내 작업에 서명하기

Git은 암호학적으로 안전하다. 하지만, 그냥 되는 건 아니다. 저장소에 아무나 접근하지 못하게 하고 진짜로 확인된 사람에게서만 커밋을 받으려면 GPG를 이용한다.

GPG 소개

우선 뭔가를 서명 하려면, GPG 설정도 하고 개인키도 설치해야 한다.

$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub   2048R/0A46826A 2014-06-04
uid                  Scott Chacon (Git signing key) <schacon@gmail.com>
sub   2048R/874529A9 2014-06-04

가진 키가 없으면 키를 새로 만들어야 한다. 키를 만들려면 gpg --genkey 명령을 실행한다.

$ gpg --gen-key

서명에 사용할 수 있는 개인키가 이미 있다면 Git 설정 중에 user.signingkey 로 설정해서 사용할 수 있다.

$ git config --global user.signingkey 0A46826A

설정하고 나면 이제 Git은 태그와 커밋에 서명할 때 등록한 키를 사용한다.

태그 서명하기

GPG 개인키 설정을 마쳤으면 새로 만드는 태그들에 서명할 수 있다. 서명하려면 -a 대신 -s 만 쓰면 된다.

$ git tag -s v1.5 -m 'my signed 1.5 tag'

You need a passphrase to unlock the secret key for
user: "Ben Straub <ben@straub.cc>"
2048-bit RSA key, ID 800430EB, created 2014-05-04

태그를 git show 명령으로 보면, GPG 서명이 붙어 있는 걸 볼 수 있다.

$ git show v1.5
tag v1.5
Tagger: Ben Straub <ben@straub.cc>
Date:   Sat May 3 20:29:41 2014 -0700

my signed 1.5 tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABAgAGBQJTZbQlAAoJEF0+sviABDDrZbQH/09PfE51KPVPlanr6q1v4/Ut
LQxfojUWiLQdg2ESJItkcuweYg+kc3HCyFejeDIBw9dpXt00rY26p05qrpnG+85b
hM1/PswpPLuBSr+oCIDj5GMC2r2iEKsfv2fJbNW8iWAXVLoWZRF8B0MfqX/YTMbm
ecorc4iXzQu7tupRihslbNkfvfciMnSDeSvzCpWAHl7h8Wj6hhqePmLm9lAYqnKp
8S5B/1SSQuEAjRZgI4IexpZoeKGVDptPHxLLS38fozsyi0QyDyzEgJxcJQVMXxVi
RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk=
=EFTF
-----END PGP SIGNATURE-----

commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

태그 확인하기

git tag -v <tag-name> 명령을 이용해 태그에 서명한 사람이 정말 그 사람이 맞는지 확인한다. 이 명령은 서명을 확인하기 위해 GPG를 사용한다. 확인 작업을 하려면 서명한 사람의 GPG 공개키를 키 관리 시스템에 등록해두어야 한다.

$ git tag -v v1.4.2.1
object 883653babd8ee7ea23e6a5c392bb739348b1eb61
type commit
tag v1.4.2.1
tagger Junio C Hamano <junkio@cox.net> 1158138501 -0700

GIT 1.4.2.1

Minor fixes since 1.4.2, including git-mv and git-http with alternates.
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Good signature from "Junio C Hamano <junkio@cox.net>"
gpg:                 aka "[jpeg image of size 1513]"
Primary key fingerprint: 3565 2A26 2040 E066 C9A7  4A7D C0C6 D9A4 F311 9B9A

서명한 사람의 공개키가 없으면 아래와 같은 메시지가 나타난다.

gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Can't check signature: public key not found
error: could not verify the tag 'v1.4.2.1'

커밋에 서명하기

최신 버전(v1.7.9 이상)의 Git은 커밋에도 서명할 수 있다. 커밋에 서명하고 싶으면 git commit 명령에 -S 옵션만 붙여주면 된다.

$ git commit -a -S -m 'signed commit'

You need a passphrase to unlock the secret key for
user: "Scott Chacon (Git signing key) <schacon@gmail.com>"
2048-bit RSA key, ID 0A46826A, created 2014-06-04

[master 5c3386c] signed commit
 4 files changed, 4 insertions(+), 24 deletions(-)
 rewrite Rakefile (100%)
 create mode 100644 lib/git.rb

서명을 확인하려면 git log 명령에 --show-signature 옵션을 붙여주자.

$ git log --show-signature -1
commit 5c3386cf54bba0a33a32da706aa52bc0155503c2
gpg: Signature made Wed Jun  4 19:49:17 2014 PDT using RSA key ID 0A46826A
gpg: Good signature from "Scott Chacon (Git signing key) <schacon@gmail.com>"
Author: Scott Chacon <schacon@gmail.com>
Date:   Wed Jun 4 19:49:17 2014 -0700

    signed commit

git log 로 출력한 로그에서 커밋에 대한 서명 정보를 알려면 %G? 포맷을 이용한다.

$ git log --pretty="format:%h %G? %aN  %s"

5c3386c G Scott Chacon  signed commit
ca82a6d N Scott Chacon  changed the version number
085bb3b N Scott Chacon  removed unnecessary test code
a11bef0 N Scott Chacon  first commit

위 로그에서 제일 최근 커밋만 올바르게 서명한 커밋이라는 것을 확인할 수 있다. 다른 커밋들은 서명하지 않았다.

1.8.3 버전 이후의 Git에서는 git merge`와 `git pull`에서 GPG 서명 정보를 이용해 Merge를 허용하지 않을 수 있다. `--verify-signatures 옵션으로 이 기능을 사용할 수 있다.

Merge 할 때 --verify-signatures 옵션을 붙이면 Merge 할 커밋 중 서명하지 않았거나 신뢰할 수 없는 사람이 서명한 커밋이 있으면 Merge 되지 않는다.

$ git merge --verify-signatures non-verify
fatal: Commit ab06180 does not have a GPG signature.

Merge 할 커밋 전부가 신뢰할 수 있는 사람에 의해 서명된 커밋이면 모든 서명을 출력하고 Merge를 수행한다.

$ git merge --verify-signatures signed-branch
Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key) <schacon@gmail.com>
Updating 5c3386c..13ad65e
Fast-forward
 README | 2 ++
 1 file changed, 2 insertions(+)

git merge 명령에도 -S 옵션을 붙일 수 있다. 이 옵션을 붙이면 Merge 커밋을 서명하겠다는 의미이다. 아래 예제에서 Merge 할 모든 커밋이 올바르게 서명됐는지 확인하고 Merge 커밋에도 서명을 하는 것을 보자.

$ git merge --verify-signatures -S  signed-branch
Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key) <schacon@gmail.com>

You need a passphrase to unlock the secret key for
user: "Scott Chacon (Git signing key) <schacon@gmail.com>"
2048-bit RSA key, ID 0A46826A, created 2014-06-04

Merge made by the 'recursive' strategy.
 README | 2 ++
 1 file changed, 2 insertions(+)

모두가 서명하게 하려면

태그와 커밋에 서명하는 것은 멋지지만 실제로 서명 기능을 사용하려면 팀의 모든 사람이 서명 기능을 이해하고 사용해야만 한다. 만약 그렇지 않으면 팀원들에게 커밋을 어떻게 서명된 커밋으로 재생성하는지 가르치느라 세월을 보내게 될 것이다. 반드시 작업에 적용하기 전에 GPG 서명 기능을 이해하고 이 기능이 가지는 장점을 완전히 파악하고 있어야만 한다.