😺

Windows, WSL, DevContainerでコミットを署名する

2023/07/12に公開

はじめに

Windows, WSL, DevContainerの全てでコミットを署名するための101ガイドが見当たらなかったので作成してみました。

環境

  • WSL バージョン: 1.2.5.0
  • カーネル バージョン: 5.15.90.1
  • WSLg バージョン: 1.0.51
  • Windows バージョン: 10.0.19045.3086

手順

GPGの設定

  1. WindowsでGpg4winをインストールする
  2. WSLで
    3. gpgをインストールする
    ※ Ubuntuにはデフォルトで入っているようですが、下記のコマンドでgpgがインストールされているか確認できます
    $ gpg --version
    
    1. pinentryGUIを設定する
    $ echo pinentry-program /mnt/c/Program\ Files\ \(x86\)/Gpg4win/bin/pinentry.exe > ~/.gnupg/gpg-agent.conf
    
    /mnt/c/Program\ Files\ \(x86\)/Gpg4winはWindows側のGpg4winのインストールしたフォルダのWSLパスに適宜変更してください
    5. gpgエージェントを再起動する
    $ gpg-connect-agent reloadagent /bye
    

GPGキーの作成

この手順はWSLで実行しています
Windowsで実行しても構いませんが出力に違いがあるかもしれません

  1. 主鍵を作成する
$ gpg --expert --full-gen-key
gpg (GnuPG) 2.2.27; Copyright (C) 2021 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)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
  (14) Existing key from card
Your selection? 11

Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
Current allowed actions: Sign Certify

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S

Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
Current allowed actions: Certify

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q
Please select which elliptic curve you want:
   (1) Curve 25519
   (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
Your selection? 5
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

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

Real name: *****
Email address: *********************
Comment:
You selected this USER-ID:
    "***** <*********************>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /home/*****/.gnupg/trustdb.gpg: trustdb created
gpg: key CE36E3A2959377DA marked as ultimately trusted
gpg: directory '/home/*****/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/*****/.gnupg/openpgp-revocs.d/8FEFC39BCF353943BCF69DC4CE36E3A2959377DA.rev'
public and secret key created and signed.

pub   nistp521 2023-07-11 [C]
      8FEFC39BCF353943BCF69DC4CE36E3A2959377DA
uid                      ***** <*********************>

  1. 鍵IDはこの後、頻出するので変数に保存しておく
$ export KEYID=CE36E3A2959377DA
  1. 副鍵を作成する
$ gpg --expert --edit-key $KEYID
gpg (GnuPG) 2.2.27; Copyright (C) 2021 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.

Secret key is available.

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
sec  nistp521/CE36E3A2959377DA
     created: 2023-07-11  expires: never       usage: C
     trust: ultimate      validity: ultimate
[ultimate] (1). ***** <*********************>

gpg> addkey
Please select what kind of key you want:
   (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 (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Your selection? 12
Please select which elliptic curve you want:
   (1) Curve 25519
   (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
Your selection? 5
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  nistp521/CE36E3A2959377DA
     created: 2023-07-11  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  nistp521/632E4324CDDD7B5C
     created: 2023-07-11  expires: never       usage: E
[ultimate] (1). ***** <*********************>

gpg> addkey
Please select what kind of key you want:
   (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 (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Your selection? 10
Please select which elliptic curve you want:
   (1) Curve 25519
   (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
Your selection? 5
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  nistp521/CE36E3A2959377DA
     created: 2023-07-11  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  nistp521/632E4324CDDD7B5C
     created: 2023-07-11  expires: never       usage: E
ssb  nistp521/5FF8E08A99C4C345
     created: 2023-07-11  expires: never       usage: S
[ultimate] (1). ***** <*********************>

gpg> addkey
Please select what kind of key you want:
   (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 (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Your selection? 11

Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Sign

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S

Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions:

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A

Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Authenticate

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q
Please select which elliptic curve you want:
   (1) Curve 25519
   (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
Your selection? 5
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  nistp521/CE36E3A2959377DA
     created: 2023-07-11  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  nistp521/632E4324CDDD7B5C
     created: 2023-07-11  expires: never       usage: E
ssb  nistp521/5FF8E08A99C4C345
     created: 2023-07-11  expires: never       usage: S
ssb  nistp521/1E98F46B0E2AAF31
     created: 2023-07-11  expires: never       usage: A
[ultimate] (1). ***** <*********************>

gpg> q
Save changes? (y/N) y

主鍵の秘密鍵の削除

副鍵のみ残して主鍵はマシンから削除します。バックアップは必ず取りましょう。以降が手順です。

エクスポート

主鍵&副鍵全て

$ gpg -a -o mastersub.key --export-secret-keys $KEYID

副鍵のみ

$ gpg -a -o sub.key --export-secret-subkeys $KEYID

公開鍵のみ

$ gpg -a -o public.asc --export $KEYID

失効証明書

$ gpg -o revoke.asc --gen-revoke $KEYID

sec  nistp521/CE36E3A2959377DA 2023-07-11 ***** <*********************>

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? 1
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
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!

鍵を全て削除し、副鍵のみインポート

  1. 鍵を全て削除する
$ gpg --delete-secret-keys $KEYID
gpg (GnuPG) 2.2.27; Copyright (C) 2021 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.


sec  nistp521/CE36E3A2959377DA 2023-07-11 ***** <*********************>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y
  1. エクスポートした副鍵をインポートする
$ gpg --import sub.key
gpg: key CE36E3A2959377DA: "***** <*********************>" not changed
gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status
gpg: key CE36E3A2959377DA: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

この副鍵のインポートをWSLとWindowsの両方で行えばどちらでも同じ鍵を使用できます
WSL上で鍵をインポートしていればDevContainerにも反映されます(rebuild必須)

GitへGPGキーを伝える

  1. 以前異なるキーフォーマットで設定した場合は、設定をリセットしてデフォルトフォーマットのopengpgを使用する
$ git config --global --unset gpg.format
  1. 主鍵を設定する
$ git config --global user.signingkey $KEYID
  1. 【オプション】全てのコミットを署名するように設定する
$ git config --global commit.gpgsign true
  1. GPG_TTYを設定する
    zshを使用している場合
    $ if [ -r ~/.zshrc ]; then echo -e '\nexport GPG_TTY=$(tty)' >> ~/.zshrc; \
      else echo -e '\nexport GPG_TTY=$(tty)' >> ~/.zprofile; fi
    
    bashを使用している場合
    $ if [ -r ~/.bash_profile ]; then echo -e '\nexport GPG_TTY=$(tty)' >> ~/.bash_profile; \
      else echo -e '\nexport GPG_TTY=$(tty)' >> ~/.profile; fi
    

公開鍵をGitHubに追加する

  1. 公開鍵を表示する
$ gpg --armor --export $KEYID
  1. GPGキーをGitHubアカウントに追加する

参考

https://code.visualstudio.com/remote/advancedcontainers/sharing-git-credentials#_sharing-gpg-keys
https://christina04.hatenablog.com/entry/create-gpg-master-key-and-subkey
https://docs.github.com/ja/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key?platform=linux

Discussion