GPG 키로 github commit에 서명하기
Git에서는 user.name
과 user.email
을 통해 커밋의 사용자 정보를 표시합니다. 하지만 이 내용은 마음만 먹으면 아무 사용자나 적을 수 있는 내용이라 여러 사람들의 기여가 담겨있는 원격 저장소에는 이를 검증하기 어렵습니다. 따라서 GPG에서 생성한 비대칭 암호화 방식의 키를 이용해 github 계정과 연동하는 서명을 커밋에 새겨 커밋의 사용자가 해당 github 계정의 사용자임을 검증할 수 있습니다.
GPG(GNU Privacy Guard)는 PGP의 오픈소스 구현체로 통신 보안을 위한 도구입니다. 이번 포스트에는 GPG 공개키와 개인키를 생성하고, github에 공개키를 알려준 뒤 개인키로 서명된 커밋을 github 원격 저장소에 push해 github가 공개키로 서명을 검증하는 과정을 실습하려 합니다.
실습 환경
- Windows 11 23H2 (x86/64)
- PowerShell 7.4.1
- Git 2.43.0
- GNU Privacy Guard 2.4.3
실습을 진행하기 위해서는 github 계정에 로컬의 SSH 공개키가 등록되어있어야 하고, 이를 통해 로컬 저장소가 원격 저장소에 연결되어있어야 합니다. SSH 키를 생성하고 공개키를 계정에 등록하는 방법에 대해서는 다음 포스트의 “SSH 키를 이용해 Github 연결” 항목을 참조할 수 있습니다.
GNU Privacy Guard 설치하기
Windows와 Mac 운영체제의 경우 GPG를 별도로 설치해야 합니다. Linux의 경우 기본으로 설치되어 있습니다. Windows 11에서는 PowerShell에서 winget 패키지 관리자를 이용해 설치할 수 있습니다.
# GNU Privacy Guard 설치
> winget install --id GnuPG.GnuPG
GPG 키 생성하기
GPG 키를 생성하는 명령어를 입력합니다.
# GPG키 생성
> gpg --full-generate-key
명령어 입력 후에는 키에 관한 사용자 설정을 묻는 질문들이 나옵니다. 키의 암호화 방식과 사용자 정보를 묻는 질문들로, 이번 실습에서는 Ed25519 암호화 방식을 사용하는 키를 생성하려고 합니다. 각 질문에 선택한 선택지는 다음과 같습니다.
- 키의 종류를 묻는 질문에 (9) ECC (sign and encrypt)
- 암호화 알고리즘에 사용할 타원 곡선을 묻는 질문에 (1) Curve 25519
- 키의 유효 기간을 묻는 질문에 (0) 유효 기간 없음
유효 기간을 설정하면 보안의 수준이 더 올라가는 대신 유효 기간 만료마다 기간을 갱신해주어야 합니다.
키의 암호화 방식을 확정한 이후에는 사용자의 이름과 이메일을 입력하는 질문이 나옵니다. 여기에 입력하는 사용자 정보는 git 설정 당시 입력된 사용자 정보와 일치해야 합니다. 또한 github 사용자 설정에 등록된 이메일과도 일치해야 하며 일치하지 않은 경우 이메일 설정에서 새 이메일을 등록해야 합니다.
# Git 설정에 입력된 사용자 정보 확인하기
> git config --list
...
user.name=<이름>
user.email=<이메일>
...
# Git 사용자 정보 입력/변경하기(덮어씌움).
# 기존 사용자 정보로 커밋한 경우 사용자 정보가 변경되지 않습니다.
> git config --global user.name <이름>
> git config --global user.email <이메일>
사용자 이름과 이메일, 코멘트(생략 가능)을 입력하고 나면 비밀번호를 입력하는 팝업 창이 나옵니다. 서명을 포함한 커밋시 해당 비밀번호가 필요합니다.
생성된 키 정보를 불러오기 위해서는 다음의 명령어를 입력합니다.
# GPG 키 목록 조회
> gpg --list-keys
------------------------------------------------
pub ed25519 2024-01-25 [SC]
{GPG ID}
uid [ultimate] {이름} <{이메일}>
sub cv25519 2024-01-25 [E]
GPG 키 연결하기
Git과 연결하기
Windows의 git 프로그램에서는 별다른 설정이 없으면 gpg의 기본 디렉터리를 <홈 디렉터리>\.gnupg
로 인식합니다. 하지만 gpg --version
명령어를 통해 본 gpg의 기본 디렉터리는 <홈 디렉터리>\AppData\Roaming\gnupg
로 인식되므로 GNUPGHOME
환경 변수에 이 경로를 지정해 gpg의 홈 디렉터리를 지정해줍니다.
커밋할 때 서명에 사용할 GPG 키의 ID를 git에게 알려줘야 합니다. gpg --list-keys
명령어를 통해 보여지는 GPG 키의 ID를 git 설정의 user.signingkey
항목에 지정합니다.
# GPG 키 목록 조회
> gpg --list-keys
------------------------------------------------
pub ed25519 2024-01-25 [SC]
{GPG ID}
uid [ultimate] {이름} <{이메일}>
sub cv25519 2024-01-25 [E]
# Git에 서명을 위해 사용할 GPG 키의 ID 등록하기
> git config --global user.signingkey {GPG ID}
다음으로 git에게 gpg.exe 실행 파일의 절대 경로를 알려줍니다. Windows 환경에서 커밋하는 경우, windows 방식의 파일 경로 표시 방법과 linux 방식의 파일 경로 표시 방법이 달라 해당 설정이 없을 경우 git에서 서명과 함께 커밋할 때 “Invalid value passed to IPC” 오류를 출력합니다.
# gpg 실행 파일의 절대 경로 등록하기
> git config --global gpg.program <gpg 실행 파일의 절대 경로>
# Example
> git config --global gpg.program "C:\Program Files (x86)\gnupg\bin\gpg.exe"
Github와 연결하기
GPG 키를 github와 연결하기 위해서는 github에 암호화된 GPG 키의 공개키를 알려주어야 합니다. 암호화된 공개키를 추출하는 명령어는 다음과 같습니다. 터미널에 출력된 키를 전부 복사합니다.
# 암호화된 공개키 추출하기
> gpg --armor --export {이메일}
-----BEGIN PGP PUBLIC KEY BLOCK-----
{ ...
암호화된 공개키
... }
-----END PGP PUBLIC KEY BLOCK-----
Github의 SSH 및 GPG 키 설정 화면에서 새 GPG 키 추가 버튼을 클릭합니다.
이름을 지정하고 Key 항목에 복사해두었던 GPG 키의 암호화된 공개키를 붙여넣습니다.
GPG 키 추가 버튼을 클릭해 등록을 완료하면 github에 등록된 GPG 키를 확인할 수 있습니다.
Commit에 서명하기
서명과 함께 커밋하기 위해서 커밋 명령어에 -S
플래그를 함께 사용합니다. 커밋마다 -S
플래그를 사용하는 것이 번거롭다면, git 설정의 commit.gpgsign
항목에 true
값을 주어 플래그 없이 항상 서명하는 것을 기본값으로 둘 수 있습니다.
# 서명과 함께 커밋하기
> git commit -S -m 'commit message'
# 특정 repo에 커밋할 때 -S 플래그 없이 항상 서명하는 것을 기본값으로 하기
# 해당 repo로 이동 후 명령어 입력
> git config commit.gpgsign true
# 모든 repo에 커밋할 때 -S 플래그 없이 항상 서명하는 것을 기본값으로 하기
> git config --global commit.gpgsign true
서명과 함께 커밋할 때는 앞서 GPG 키를 생성할 때 지정한 키의 비밀번호를 입력하는 팝업 창이 나옵니다. 비밀번호를 입력하고 확인을 누르면 커밋에 서명이 담기게 됩니다.
로그에서 이전 커밋의 서명 내역을 확인하려면 다음의 명령어를 입력합니다.
# 서명과 함께 git 로그 확인하기
> git log --show-signature
24. 06. 27. 수정
이후에도 종종 서명을 포함한 커밋 진행마다 다음의 오류 출력하며 커밋이 진행되지 않은 경험을 했습니다.
gpg: can't connect to the gpg-agent: IPC connect call failed
gpg: keydb_search failed: No agent running
이는
C:\Program Files (x86)\gnupg\bin
에 위치한gpg-agent.exe
프로그램이 실행 중이지 않아 발생한 문제로 터미널에서gpg-agent --daemon
명령어로 프로그램을 실행한 뒤, 새 터미널 탭에서gpg-connect-agent reloadagent /bye
명령어로 새로 고침하여OK
출력값을 받고 다시 커밋을 진행하여 해결했습니다.
서명된 커밋을 github에 push하기
SSH 및 GPG 키 설정 화면에 로컬의 SSH 키와 GPG 키가 모두 등록되어 있다면 로컬 저장소에서 원격 저장소로 push할 때 github repo에도 자동으로 서명이 등록됩니다.
# 원격 저장소 목록 확인하기
> git remote -v
# 로컬의 main 브랜치를 origin 원격 저장소(Github repo)의 main 브랜치에 push 하기
> git push origin main
Github 계정 아이디는 로컬의 git과 GPG 키에 등록된 사용자 이름과 다르지만, 세 계정/키가 같은 이메일을 공유하고 있으므로 github가 이를 확인하고 제 github 계정 명의로 커밋이 등록 되었음을 확인할 수 있습니다.
마무리
Github에 서명이 담긴 커밋이 등록될 때의 이점으로는 무엇보다도 직접 로컬에서 원격 저장소로 직접 push 넣은 기여 내역도 내 github 계정 명의의 기여로 인정 받을 수 있다는 점입니다(그로 인해 포도알이 색칠되는 것도!). 이전에는 기여 내역을 인정 받기 위해 pull request를 요청하고 내 github 계정이 squash나 rebase 하는 방법으로 기여를 묻히기 위해 우회했었는데, 이제는 다른 우회 방법 없이 로컬에서 작업한 내 기여가 내 github 계정의 기여로 인정받을 수 있게 되었습니다. 앞으로 pull request의 검증이 필요 없는 개인 단위 repo에서는 부담 없이 push할 수 있게 되었습니다.
Linux 환경에서 처음으로 실습하고 블로그 작성을 위해 windows에서 다시 실습했는데, linux와 windows의 환경 차이로 인해 실습의 어려움이 있었습니다. 특히 MinGW64 기반으로 작성된 windows 버전의 gpg가 windows 파일 디렉터리 형식을 읽지 못해 생기는 오류가 있었습니다. 여러 블로그와 stack overflow의 도움으로 환경 변수와 git config 부분을 수정해 문제를 해결할 수 있었습니다. 참고자료에 도움이 되었던 포스트들을 공유합니다.
참고자료
- “커밋 확인 정보”. Github Docs. https://docs.github.com/ko/authentication/managing-commit-signature-verification/about-commit-signature-verification.
- somni. “Git GPG 서명 설정 후 커밋 시 개인 키 없음 오류 해결”. 솜니.로그. 2022년 11월 27일. https://log.somni.one/git-no-secret-key-after-setup-gpg/.
- Jamie Phan. “IPC Error on GPG Agent with Git on Windows”. Stack overflow. 2021년 8월 10일. https://stackoverflow.com/questions/68721294/ipc-error-on-gpg-agent-with-git-on-windows/.
- jeyraof. “GPG(GNU PG)를 이용해 git 커밋에 서명하는 방법”. 44bits. 2021년 2월 15일. https://www.44bits.io/ko/post/add-signing-key-to-git-commit-by-gpg.