Подписываем коммиты с помощью GPG

Чтобы проверить, что коммиты действительно получены из доверенного источника, в Git есть несколько способов подписать и проверить исходники, используя GPG.

· 6 минуты на чтение
Подписываем коммиты с помощью GPG

GPG (также известный как GnuPG) создавался как свободная альтернатива несвободному PGP. GPG используется для шифрования информации и предоставляет различные алгоритмы (RSA, DSA, AES и др.) для решения этой задачи.

Спонсор поста

Используемые версии

git: 2.39.0
gpg: 2.3.8

История изменения статьи

19.12.2022: Актуализировал версии ПО. Актуализировал инструкцию, сделал ее более подробной. Добавил информацию про создание дополнительных ключей и про подписание тегов.

Зачем подписывать коммиты?

По умолчанию в Git обязателен только механизм аутентификации, а авторизация не обязательна. Поэтому можно подписаться любым именем, и указать любой email. Никакой верификации при этом не происходит.

git config user.name 'Pete Houston'
git config user.email 'contact@petehouston.com'
Указываем любое имя и любую почту

Вспоминаем: Чем аутентификация отличается от авторизации?

Ключ SSH позволяет получить доступ к репозиторию. Чаще всего ключ используется, чтобы пушить в репозиторий. Это пример аутентификации. Ключ SSH открывает нам доступ к репозиторию, а дальше вы можете оставить коммит от имени любого автора.

Ключ GPG позволяет подписывать конкретный коммит или тег. Таким образом владелец ключа может доказать свое авторство. А настройки популярных GIT хостингов позволяет запретить публиковать коммиты без GPG подписи.

Таким образом любой человек может попробовать выдать свои коммиты за ваши, чтобы внедрить вредоносный код.

Чтобы проверить, что коммиты действительно получены из доверенного источника, в Git есть несколько способов подписать и проверить исходники, используя GPG.

Вот как это выглядит в GitHub

Подписанный коммит в GitHub

Настройка GPG

Если вы хотите подписать что-то, вам необходим настроенный GPG и персональный ключ.

Посмотреть список ключей можно следующей командой.

gpg --list-keys --keyid-format long

pub   ed25519/EFA62C59ACC854C1 2022-12-18 [SC] [   годен до: 2023-12-18]
831AAB443088938B8C4B1A99EFA62C59ACC854C1
uid               [  абсолютно ] Struchkov Mark (Key for git commit) <mark@struchkov.dev>
sub   cv25519/5E8003E311E63A37 2022-12-18 [E] [   годен до: 2023-12-18]

Создание нового ключа GPG

Генерируем новый ключ командой:

gpg --full-generate-key

Первым делом нам предложат выбрать тип создаваемого ключа

Выберите тип ключа:
   (1) RSA and RSA
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (9) ECC (sign and encrypt) *default*
  (10) ECC (только для подписи)
  (14) Existing key from card

Самый современный способ установлен по умолчанию (9). Также можно выбрать вариант (10). В нашем случае между ними не будет разницы.

Далее выбираем элептическую кривую. Также оставляем по умолчанию (1):

Выберите эллиптическую кривую:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256

Теперь устанавливаем срок действия ключа. Я обычно устанавливаю 1 год.

Выберите срок действия ключа.
         0 = не ограничен
      <n>  = срок действия ключа - n дней
      <n>w = срок действия ключа - n недель
      <n>m = срок действия ключа - n месяцев
      <n>y = срок действия ключа - n лет
Срок действия ключа? (0) 1y

После чего надо указать информацию о себе: ФИО, почту. В примечании можно указать зачем создается этот GPG ключ, чтобы потом не путаться.

Ваше полное имя: Struchkov Mark
Адрес электронной почты: mark@struchkov.dev
Примечание: Key for git commit
Вы выбрали следующий идентификатор пользователя:
    "Struchkov Mark (Key for git commit) <mark@struchkov.dev>"

Сменить (N)Имя, (C)Примечание, (E)Адрес; (O)Принять/(Q)Выход? O

Подтверждаем введеные данные. После чего необходимо придумать пароль для защиты GPG ключа.

Отлично, теперь у нас есть мастер ключ. Желтым я выделил его идентификатор, он нам еще пригодится.

pub   ed25519/EFA62C59ACC854C1 2022-12-18 [SC] [   годен до: 2023-12-18]
831AAB443088938B8C4B1A99EFA62C59ACC854C1
uid               [  абсолютно ] Struchkov Mark (Key for git commit) <mark@struchkov.dev>
sub   cv25519/5E8003E311E63A37 2022-12-18 [E] [   годен до: 2023-12-18]

Создание дополнительного ключа к основному

Мы создали так называемый мастер ключ. И можем использовать сразу его, а можем создать дополнительный ключ, который будет привязан к основному.

Делается это следующим образом

gpg --expert --edit-key EFA62C59ACC854C1
EFA62C59ACC854C1 идентификатор мастер ключа

Далее вы увидите консоль gpg>. Вводим туда команду addkey и выбираем тип ключа. Нам нужен ключ для подписи (10).

gpg> addkey

Выберите тип ключа:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (только для подписи)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Ваш выбор? 10

Далее снова выбор элиптической кривой. Оставляем значение по умолчанию:

Выберите эллиптическую кривую:
   (1) Curve 25519 *default*
   (2) Curve 448
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
Ваш выбор? 

Указываем срок действия для дополнительного ключа и подтверждаем данные.

После этого важно вызывать команду save, чтобы сохранить новый ключ.

gpg> save
$

Если вывести информацию о ключах, то можно увидеть новый доплнительный ключ.

pub   ed25519/EFA62C59ACC854C1 2022-12-18 [SC] [   годен до: 2023-12-18]
831AAB443088938B8C4B1A99EFA62C59ACC854C1
uid               [  абсолютно ] Struchkov Mark (Key for git commit) <mark@struchkov.dev>
sub   cv25519/5E8003E311E63A37 2022-12-18 [E] [   годен до: 2023-12-18]
sub   ed25519/D3018BE7BA428CA6 2022-12-18 [S] [   годен до: 2023-12-18]

Добавление ключа в Git

Установив параметр user.signingkey мы сообщаем гиту, что нужно использовать этот ключ по умолчанию для всех подписей.

$ git config --global user.signingkey D3018BE7BA428CA6

Индивидуально для репозитория можно указать другой GPG ключ.

$ git config --local user.signingkey 7BGC7M6M

Ручное добавление

Так же можно добавить ключ вручную в файл ~/.gitconfig в параметр signingkey.

Для глобальной настройки:

[user]
	name = uPagge
	email = spam@upagge.ru
	signingkey = D3018BE7BA428CA6
[commit]
	gpgsign = true
[core]
	autocrlf = input

Для индивидуальной настройки репозитория используется переменная signingkey в файле config, который лежит в папке .git.

[user]
	name = Стручков Марк
	email = mstruchkov@work.com
    signingkey = 7BGC7M6M

Добавление ключа в GitHub

На примере GitHub рассмотрим, как добавить GPG ключ на git хостинг. Это позволит получить галочку верифицированного коммита у хостинга. Суть добавления одна и та же, не важно GitHub это или GitLab, или Gitea.

Чтобы добавить ваш ключ в GitHub перейдите в Settings > SSH and GPG keys. Вас интересует кнопка “New GPG key”

Теперь необходимо получить публичный ключ из приватного. Для этого выполните команду:

gpg --armor --export your_privat_key_id

Скопируйте целиком полученное значение, вставьте его в поле и нажмите “Add GPG key”. Если все прошло успешно, то вы увидите ваш ключ в списке.

Также убедитесь, что указанный в ключе email добавлен в ваш аккаунт

Публикация открытого ключа

Это не обязательно, но в некоторых случаях необходимо сделать ваш ключ доступным и узнаваемым в Интернете.

Выполните эту команду:

gpg --send-keys 3AA5C34371567BD2
Не волнуйтесь, эта команда отправит только публичный ключ.

Однако, эта команда по какой-то причине работает не всегда. Тогда можно загрузить ключ вручную на один из сайтов, например на http://keyserver.ubuntu.com.

Для этого получаем публичный ключ командой:

gpg --armor --export your_privat_key_id
Рандомный блок

Подписание коммитов

Если вы хотите подписывать коммиты, а не только теги, вам нужно добавить -S к команде commit.

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

You need a passphrase to unlock the secret key for
user: "Scott Chacon (Git signing key) "
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:

git config --global commit.gpgsign true
Среда разработки IntelliJ IDEA автоматически подписывает все ваши коммиты, если вы установили глобальный ключ.

Чтобы увидеть и проверить эти подписи, существует также опция --show-signature для команды git log.

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) "
Author: Scott Chacon 
Date:   Wed Jun 4 19:49:17 2014 -0700

    Signed commit 

Подписание тегов

Дополнительно можно подписывать теги к коммитам. Делается это также добавлением флага -s:

git tag -s test

Дополнительно можно указать комментарий, который будет доступен для чтения при проверке подписи командой

git tag -v test
К сожалению, IntelliJ IDEA не поддерживает подписание тегов через свой GUI

Резюмирую

Подписывать теги и коммиты - это отличное решение. При использовании подписей в своем обычном рабочем процессе убедитесь, что все в вашей команде понимают, как это сделать. Если вы этого не сделаете, то в конечном итоге потратите много времени, помогая людям понять, как переписать свои коммиты с помощью подписанных версий.

Убедитесь, что вы понимаете GPG и преимущества подписания, прежде чем принимать это как часть стандартного рабочего процесса.

Struchkov Mark
Struchkov Mark
Задавайте вопросы, если что-то осталось не понятным👇