Featured image of post Re: ぼくの考えた最強の
 GPG Key 環境for Windows 11

Re: ぼくの考えた最強の GPG Key 環境for Windows 11

Summary

2024年に GPG Key のセットアップを実施した

2025年年末に再度環境整理を実施したのでそのあたりを更新する。

2024年の妥協ポイント

本当に混沌としていたため、 SSH 環境が整うだけで満足してしまい、 GPG の利用を環境を跨いですることはなかった。これが心残りであった。想定されるケースとしては極小であるが Git 署名も SSH 鍵で実施することになり、 Yubikey の仕様上 PIN の timeout を設定出来ず設定する場合は 15秒固定、タッチ必須にすると git fetch などのタイミングでも必須になり VSCode などを使っている時はストレスが大きく SSH 鍵の cache とタッチは無効化していた。攻撃者からみれば、これは格好のブツであり私になりすまして Git 署名を出来てしまう状況である。。

そのため、今回 Git 署名を GPG Key の署名鍵に変更するために Windows, WSL2, Remote Linux で GPG Key が使える環境を整備したのでそれについてブログに残す。

調べた限り、実現している人が見つからずほぼ1ヶ月こればかりやっているノイローゼになりそうな状況であったw 混沌としている Windows + GPG Key の解消に少しでもなれば嬉しい。

構成

前回の構成がこちらである。
gpg-agent が 2.4 以降で対応した NamedPipe と pageant_shm のおかげで agent を一本化出来てこれは利便が良かった。当時はメンテンナンスなどの透明性が見なかったため npiperelay.exe の利用はせず wsl2-ssh-agent を利用することにしていた。

graph LR subgraph Windows 11 subgraph YubiKey A1(PIV) A2(GPG) end subgraph KeePassXC A3(Private Key) end subgraph gpg-agent G1(NamedPipe) G2(pageant_shm) end subgraph Clients C1(Windows OpenSSH) C3(Tera Term,WinSCP) end subgraph WSL2 C2(wsl2-ssh-agent) end end subgraph Remote R1(ssh-agent) end YubiKey --> gpg-agent KeePassXC --> gpg-agent G1 --> C1 G1 --> C2 G2 --> C3 C1 --> R1

今回はもう少し複雑になるため、 npiperelay.exe を活用することになった。
変更になった箇所が、オレンジの箇所。

wsl2-ssh-agent は問題なく機能していたが SSH/GPG で参照するプロトコル違いで経由する仕組みを変更すると面倒だったため npiperelay.exe に統一する。

graph LR classDef update fill:#ffa23e subgraph Windows 11 subgraph YubiKey A1(PIV) A2(GPG) end subgraph KeePassXC A3(Private Key) end subgraph gpg-agent G1(NamedPipe) G2(pageant_shm) G3(S.gpg-agent.extra):::update G4(S.gpg-agent):::update end subgraph Clients C1(Windows OpenSSH) C3(Tera Term,WinSCP) C5(gpg-bridge) subgraph "Gpg4Win(GnuPG)" C6(gpg\.exe):::update end subgraph "Win32-OpenSSH" C7(scp\.exe):::update C8(ssh\.exe):::update C9(ssh-keygen\.exe):::update end end subgraph WSL2 C2(ssh-agent.socket %t/ssh/agent.sock) C4(gpg-agent.socket S.gpg-agent S.gpg-agent.extra) end end subgraph Remote R1(Forward sock) R2(gpg-agent.socket S.gpg-agent S.gpg-agent.extra) end YubiKey -- OpenGPG --> gpg-agent KeePassXC -- SSH --> gpg-agent G1 -- SSH --> C1 G1 -- npiperelay.exe ssh-agent.socket --> C2:::update G1 -- SSH --> C7 G1 -- SSH --> C8 G1 -- SSH --> C9 G2 -- SSH --> C3 G3 -- npiperelay.exe gpg-agent.socket --> C4:::update G4 --> C6 C1 -- SSH AgentForward --> R1 G2 -- GPG --> C5:::update C5 -- SSH RemoteForward --> R2:::update

Yubikey の設定

  • タッチポリシー
    • 署名鍵 (Signature): On - YubiKeyのタッチが必要
    • 暗号化鍵 (Decryption): On - YubiKeyのタッチが必要
    • 認証鍵 (Authentication): Off - タッチ不要
  • PINポリシー
    • 署名時のPIN: Always (強制) - 署名操作は常にPIN入力が必要
    • KDF有効化: True - PIN強化機能が有効
  • PIN試行回数
    • User PIN残回数: 5回
    • Reset Code残回数: 99回
    • Admin PIN残回数: 10回
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
PS C:\Users\naa0yama> ykman openpgp info
PIN tries remaining:        5
Reset code tries remaining: 99
Admin PIN tries remaining:  10
Require PIN for signature:  Always
KDF enabled:                True

PS C:\Users\naa0yama> gpg --card-status
Reader ...........: Yubico YubiKey OTP FIDO CCID 0
Signature PIN ....: 強制
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 5 99 10
Signature counter : 28
KDF setting ......: on
UIF setting ......: Sign=on Decrypt=on Auth=off

gpg.exe, ssh.exe(Windows)

通常利用では何ら問題なく使えます。 これはほんとに GunPG 2.4 で入った機能のおかげだと思います。
署名に関しても、鍵の import と信頼が完了してれば echo "test" | gpg --clearsign -vv で署名が確認できるはずです。

問題になるが Git Bash や Git for Windows を使う場合です。
通常設定で使う場合は Git に含まれる MinGW 内の gpg コマンドが使われせっかく使える Windows 側は参照しれくれません。これを回避するには .gitconfig に Git Bash で説明する設定を入れれば署名できるようになる

ssh-agent(Windows)

Windows 11 -> WSL2 の ssh-agent は以前と同様に、 NamedPipe を経由して ssh-agent に提供することで forward を実現できる。これはよく利用される方法なので深くは言及しない

gpg-agent(Windows)

GPG Key も SSH の混沌と変わらず、通常 *nix なら domain socket を追加通信ため SSH RemoteForward でソケット同士を繋いでやれば終わりだが Gpg4Win に含まれる gpg-agent では特殊な方法を利用しており libassuan というらしい。 albertony/npiperelay 版では -a オプションを付けることで作用できるのでこれを利用して Windows 側の S.gpg-agent.extra と通信させることで gpg-agent を使えるようにする。

面倒なので

面倒なので、自分が数年開発用に WSL2 を GitHub Action で生成して Import すればすぐ使える環境にスクリプト郡をまとめて配置した。

やってることは、ここにあるスクリプトでやっているので興味アレば読んでみてください。

セットアップ

devtool-wsl2 を使う場合のセットアップを備忘録とし記載

まずは GitHub に記載の通り PowerShell を実行して、 WSL2 のイメージを展開します。

1
powershell -ExecutionPolicy Unrestricted -Command "Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/naa0yama/devtool-wsl2/main/devtool.ps1' -OutFile 'devtool.ps1'; .\devtool.ps1"

展開されると %USERPROFILE%/.local/bin にスクリプトが展開されるます。そして Ctrl+R で shell:startup を開けばスタートアップフォルダーに起動用ショートカットが追加されるのでこれを一度ダブルクリックして10-15秒待つとタスクトレイに現れると思います。

これで gpg-agent と gpg-bridge が起動して待機状態になります。
鍵が刺さっている時、刺さってない時、PIN要求時でタスクトレイのアイコンは変化するのでわかりやすく、通知で PIN/タッチの要求を気づけるようにしています。

パッケージ周り

以前の記事でも触れているが Windows 11 に付属する OpenSSH が古いため不具合や新機能を使えるようにするためにアップデートする

1
2
3
4
5
6
7
8
9
#
# 管理者権限プロンプトを立ち上げて作業
#

> powershell.exe
> winget install Git.Git
> winget install GnuPG.GnuPG
> winget install GnuPG.Gpg4win
> winget install Microsoft.OpenSSH.Preview

なお、不具合対策で現在は pin している
時間がある時に検証してから、強制アップデートを行っている

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#
# 管理者権限プロンプトを立ち上げて作業
#

> powershell.exe
> winget pin add GnuPG.GnuPG
> winget pin add GnuPG.Gpg4win
> winget pin add Microsoft.OpenSSH.Preview

> winget pin list
名前              ID                        バージョン ソース ピンの種類
------------------------------------------------------------------------
GNU Privacy Guard GnuPG.GnuPG               2.4.8      winget Pinning
OpenSSH           Microsoft.OpenSSH.Preview 10.0.0.0   winget Pinning
Gpg4win (4.4.1)   GnuPG.Gpg4win             4.4.1      winget Pinning
Note
再起動後、 新しくインストールした OpenSSH の ssh-agent と sshd が起動しているので これの自動起動を停止、しサービスを停止する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
# 管理者権限プロンプトを立ち上げて作業
#

> Get-Service | Where-Object {$_.Name -match '(CertPropSvc|SCardSvr|ssh-agent|sshd)'} | Select Status, Name, StartType, DisplayName

 Status Name        StartType DisplayName
 ------ ----        --------- -----------
Stopped CertPropSvc Automatic Certificate Propagation
Running SCardSvr    Automatic Smart Card
Stopped ssh-agent   Automatic OpenSSH Authentication Agent
Stopped sshd        Automatic OpenSSH SSH Server


# 自動起動の無効化
> Set-Service -Name "CertPropSvc" -StartupType Disabled
> Stop-Service -Name "CertPropSvc"

> Set-Service -Name "ssh-agent" -StartupType Disabled
> Stop-Service -Name "ssh-agent"

> Set-Service -Name "sshd" -StartupType Disabled
> Stop-Service -Name "sshd"

SCardSvr のみ自動起動で、他は Disabled になっていれば問題ありません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#
# 管理者権限プロンプトを立ち上げて作業
#

# 起動設定確認
> Get-Service | Where-Object {$_.Name -match '(CertPropSvc|SCardSvr|ssh-agent|sshd)'} | Select Status, Name, StartType, DisplayName
 Status Name        StartType DisplayName
 ------ ----        --------- -----------
Stopped CertPropSvc  Disabled Certificate Propagation
Stopped SCardSvr    Automatic Smart Card
Stopped ssh-agent    Disabled OpenSSH Authentication Agent
Stopped sshd         Disabled OpenSSH SSH Server

Git Bash

~/.gitconfig に GPG 周りの設定を追加する必要がある。

下記のスクリプトでは読み込んでいる GPG 鍵の中で署名用鍵の ID を Git コマンドにセットするようにしている

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
$lines = gpg --with-colons --with-keygrip --list-secret-keys
$uid = $null
$subkey = $null
$keygrip = $null
$captureNext = $false

foreach ($line in $lines) {
    $fields = $line -split ':'
    
    if ($fields[0] -eq 'uid') {
        $uid = $fields[9]
    }

    if ($fields[0] -eq 'ssb' -and $fields[11] -match 's') {
        $captureNext = $true
        $subkey = $($fields[4])
        Write-Host "Found signing subkey: $($fields[4])" -ForegroundColor Cyan
    }
    elseif ($captureNext -and $fields[0] -eq 'grp') {
        $keygrip = $fields[9]
        Write-Host "Extracted keygrip: $keygrip" -ForegroundColor Cyan
        break
    }
}

if (-not $keygrip) {
    Write-Host "Error: Signing key keygrip not found" -ForegroundColor Red
    exit 1
}

Write-Host "Find Subkey=$subkey" -ForegroundColor Green

# ユーザー情報
git config --global user.email "9667078+naa0yama@users.noreply.github.com"
git config --global user.name "Naoki Aoyama"
git config --global user.signingkey "$subkey"
git config --global user.useConfigOnly true

# SSH署名設定
git config --global gpg.format openpgp
git config --global commit.gpgsign true
git config --global tag.gpgSign true
Windows Only

下記の設定は WSL2 で使うと上手く利用出来ない可能性が高いので設定を入れた後はコメントアウトするか、ファイルを分けて Include の運用が良いかもしれない

1
2
3
4
5
6
7
# Windows only
git config --global core.sshCommand "C:/Program Files/OpenSSH/ssh.exe"
git config --global gpg.program "C:/Program Files (x86)/GnuPG/bin/gpg.exe"
git config --global gpg.ssh.program "C:/Program Files/OpenSSH/ssh-keygen.exe"

git config --global core.autocrlf true
git config --global core.safecrlf true
.gitconfig 参考
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
> cat .gitconfig
[gpg]
        program = C:/Program Files (x86)/GnuPG/bin/gpg.exe
        format = openpgp
[user]
        email = 9667078+naa0yama@users.noreply.github.com
        name = Naoki Aoyama
        signingkey = 77SXXXXXXXXXXXXX
        useConfigOnly = true
[commit]
        gpgsign = true
[tag]
        gpgSign = true
[core]
        sshCommand = C:/Program Files/OpenSSH/ssh.exe
        autocrlf = true
        safecrlf = true
[gpg "ssh"]
        program = C:/Program Files/OpenSSH/ssh-keygen.exe

ここまで設定すれば Git for Windows で署名できるはずであるテストしよう

Git Bash テスト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
$testDir = Join-Path $env:TEMP "git-sign-test-$(Get-Date -Format 'yyyyMMddHHmmss')"
New-Item -ItemType Directory -Path $testDir
Set-Location $testDir

# 1. Gitリポジトリの初期化
git init

$env:GIT_TRACE = 1
Get-Date -Format "yyyyMMddHHmmss" | Out-File -FilePath README.md -Encoding utf8
git add README.md
git commit -m "test sign commit $(Get-Date -Format 'yyyyMMddHHmmss')"
$env:GIT_TRACE = $null

# 3. 署名の検証
Write-Host "`n=== コミットログ ===" -ForegroundColor Green
git log --show-signature -1

Write-Host "`n=== 詳細な署名検証 ===" -ForegroundColor Green
git verify-commit HEAD

Write-Host "`n=== コミット情報 ===" -ForegroundColor Green
git log --pretty=fuller -1

GPG Key で署名された場合下記のようにログが出力される

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
> # 1. Gitリポジトリの初期化
> git init
Initialized empty Git repository in C:/Users/naa0yama/AppData/Local/Temp/git-sign-test-20260111234746/.git/

> $env:GIT_TRACE = 1
> Get-Date -Format "yyyyMMddHHmmss" | Out-File -FilePath README.md -Encoding utf8
> git add README.md
23:47:46.753889 exec-cmd.c:266          trace: resolved executable dir: C:/Program Files/Git/mingw64/bin
23:47:46.761591 git.c:502               trace: built-in: git add README.md

> git commit -m "test sign commit $(Get-Date -Format 'yyyyMMddHHmmss')"
23:47:46.792894 exec-cmd.c:266          trace: resolved executable dir: C:/Program Files/Git/mingw64/bin
23:47:46.800682 git.c:502               trace: built-in: git commit -m 'test sign commit 20260111234746'
23:47:46.805357 run-command.c:674       trace: run_command: 'C:/Program Files (x86)/GnuPG/bin/gpg.exe' --status-fd=2 -bsau 77SXXXXXXXXXXXXX
23:47:46.805357 run-command.c:935       trace: start_command: 'C:/Program Files (x86)/GnuPG/bin/gpg.exe' --status-fd=2 -bsau 77SXXXXXXXXXXXXX
23:48:07.796229 run-command.c:674       trace: run_command: git maintenance run --auto --no-quiet --detach
23:48:07.796229 run-command.c:935       trace: start_command: git maintenance run --auto --no-quiet --detach
23:48:07.805587 exec-cmd.c:266          trace: resolved executable dir: C:/Program Files/Git/mingw64/libexec/git-core
23:48:07.810260 git.c:502               trace: built-in: git maintenance run --auto --no-quiet --detach
[master (root-commit) c18aa17] test sign commit 20260111234746
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

> $env:GIT_TRACE = $null

> # 3. 署名の検証
=== コミットログ ===
> git log --show-signature -1
commit c18aa174b0101f8bab593fee6d20a9507d390cd3 (HEAD -> master)
gpg: Signature made 01/11/26 23:47:46 <93><8C><8B><9E> (<95>W<8F><80><8E><9E>)^M
gpg:                using EDDSA key XXXXXXXXXXXXXXXXXXXXXXXX77SXXXXXXXXXXXXX^M
gpg: Good signature from "Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>" [ultimate]^M
Author: Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
Date:   Sun Jan 11 23:47:46 2026 +0900

    test sign commit 20260111234746

=== 詳細な署名検証 ===
> git verify-commit HEAD
gpg: Signature made 01/11/26 23:47:46 ���� (W����)
gpg:                using EDDSA key XXXXXXXXXXXXXXXXXXXXXXXX77SXXXXXXXXXXXXX
gpg: Good signature from "Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>" [ultimate]
>

=== コミット情報 ===
> git log --pretty=fuller -1
commit c18aa174b0101f8bab593fee6d20a9507d390cd3 (HEAD -> master)
Author:     Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
AuthorDate: Sun Jan 11 23:47:46 2026 +0900
Commit:     Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
CommitDate: Sun Jan 11 23:47:46 2026 +0900

    test sign commit 20260111234746

ここで、コミットログと署名検証の場所で git config --global user.signingkey で末尾が一致するはずです。
一致しない場合は gpg-card -q list の 鍵ハッシュとにらめっこするとどの鍵だったかわかると思います。

1
2
3
4
5
# 4. 後片付け
Write-Host "`n=== クリーンアップ ===" -ForegroundColor Yellow
Set-Location $env:TEMP
Remove-Item -Recurse -Force $testDir
Write-Host "テストディレクトリを削除しました: $testDir" -ForegroundColor Green

GitHub

GPG 署名鍵の Export から

1
2
3
4
5
6
7
8
9
> gpg --list-secret-keys --keyid-format=long
[keyboxd]
---------
sec#  nistp521/XXXXXXXXXXXXXXXX 2024-09-13 [C]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid                 [  究極  ] Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
ssb>  cv25519/DCXXXXXXXXXXXXXX 2024-09-13 [E]
ssb>  ed25519/77SXXXXXXXXXXXXX 2024-09-13 [S]
ssb>  ed25519/E3XXXXXXXXXXXXXX 2024-09-13 [A]

鍵ID で gpg --armor --export して登録すれば良い簡単

1
2
3
4
5
6
> gpg --armor --export 77SXXXXXXXXXXXXX
-----BEGIN PGP PUBLIC KEY BLOCK-----

...(snip)...

-----END PGP PUBLIC KEY BLOCK-----

Vigilant mode

あとは画面下部の署名検証モードを有効化すると署名されている Commit は Verified が付きます。

Verified 例

Note

以前に SSH Key で Signing Key としていたり、 GPG Key を削除する必要が出ても、検証済みの Verified バッチの状態には影響が無いようです。そのため私は SSH 署名を削除して GPG Key に統一しました。

WSL2

devtool-wsl2 はセットアップ済みのため、 Shell にログインできればすぐに使える状態のハズです。

1
2
3
# SSH 鍵の転送
> $ ssh-add -l
256 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX cardno:XX_XXX_XXX (ED25519)

GPG は公開鍵を Import しないと使えないので渡しの場合は Keybase に置いてるのでこちらからダウンロードして信頼させます

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
$ curl https://keybase.io/naa0yama/pgp_keys.asc | gpg --import
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1806  100  1806    0     0   1813      0 --:--:-- --:--:-- --:--:--  1813
gpg: key 794676DEF45A4D7F: public key "Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1

$ gpg -k
/home/user/.gnupg/pubring.kbx
-----------------------------
pub   nistp521 2024-09-13 [C]
      65284A0A9205C52EBC16BBCF794676DEF45A4D7F
uid           [ unknown] Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
sub   cv25519 2024-09-13 [E]
sub   ed25519 2024-09-13 [S]
sub   ed25519 2024-09-13 [A]

$ gpg --edit-key 65284A0A9205C52EBC16BBCF794676DEF45A4D7F
gpg (GnuPG) 2.4.4; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: problem with fast path key listing: Forbidden - ignored
Secret subkeys are available.

pub  nistp521/794676DEF45A4D7F
     created: 2024-09-13  expires: never       usage: C
     trust: unknown       validity: unknown
ssb  cv25519/DC4B3ABE96273336
     created: 2024-09-13  expires: never       usage: E
     card-no: 0006 12013632
ssb  ed25519/A088666E808857DD
     created: 2024-09-13  expires: never       usage: S
     card-no: 0006 12013632
ssb  ed25519/E3E95623632A1EF2
     created: 2024-09-13  expires: never       usage: A
     card-no: 0006 12013632
[ unknown] (1). Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>

gpg> trust
pub  nistp521/794676DEF45A4D7F
     created: 2024-09-13  expires: never       usage: C
     trust: unknown       validity: unknown
ssb  cv25519/DC4B3ABE96273336
     created: 2024-09-13  expires: never       usage: E
     card-no: 0006 12013632
ssb  ed25519/A088666E808857DD
     created: 2024-09-13  expires: never       usage: S
     card-no: 0006 12013632
ssb  ed25519/E3E95623632A1EF2
     created: 2024-09-13  expires: never       usage: A
     card-no: 0006 12013632
[ unknown] (1). Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

pub  nistp521/794676DEF45A4D7F
     created: 2024-09-13  expires: never       usage: C
     trust: ultimate      validity: unknown
ssb  cv25519/DC4B3ABE96273336
     created: 2024-09-13  expires: never       usage: E
     card-no: 0006 12013632
ssb  ed25519/A088666E808857DD
     created: 2024-09-13  expires: never       usage: S
     card-no: 0006 12013632
ssb  ed25519/E3E95623632A1EF2
     created: 2024-09-13  expires: never       usage: A
     card-no: 0006 12013632
[ unknown] (1). Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.

gpg> q

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ gpg -k
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
/home/user/.gnupg/pubring.kbx
-----------------------------
pub   nistp521 2024-09-13 [C]
      65284A0A9205C52EBC16BBCF794676DEF45A4D7F
uid           [ultimate] Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
sub   cv25519 2024-09-13 [E]
sub   ed25519 2024-09-13 [S]
sub   ed25519 2024-09-13 [A]

これで信頼状態になったので署名テストをする、今回は 単純な GPG Key が使えるかのテスト
正しく設定できていれば、 PIN 入力画面が立ち上がるはずです。その後タッチすると署名され下記のように出力されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ echo "test" | gpg --clearsign -vv
gpg: enabled compatibility flags:
gpg: connection to the agent is in restricted mode
gpg: using subkey A088666E808857DD instead of primary key 794676DEF45A4D7F
gpg: writing to stdout
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

test
gpg: EDDSA/SHA512 signature from: "A088666E808857DD Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>"
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQQAtOsEtRBNAQHqhwWgiGZugIhX3QUCaWPF+AAKCRCgiGZugIhX
3YE+AQChiY37XSX5AgYDyXReKDfl7RAkkD1m9uasbV+bA6RzEwD/Xvs2lp77rHLv
vp2Sa/tDo4xnWnGAIljoXQtSTTOKpgA=
=/BY4
-----END PGP SIGNATURE-----

Remote SSH

Remote SSH はいくつか設定が必要で最近の Linux ではデフォルトで gpg-agent.socket などが設定されているため gpg などがソケットアクセスすると自動で gpg-agent を立ち上げるなど普段は便利だけど、今回のような転送時は困るので無効化する必要があった。 WSL2 に設定する setup.sh に追加してあるのでこれを実行すれば準備完了する。

  • gpg.confno-autostart を追加
  • systemctl –user mask
    • gpg-agent.service
    • gpg-agent.socket
    • gpg-agent-ssh.socket
    • gpg-agent-extra.socket
    • gpg-agent-browser.socket
  • systemctl –user units を作成
    • gpg-agent.socket
    • gpg-socket-cleanup.service
      • これを作ることで、ログイン時に自動で sock を片付け Remote Linux の sshd n AllowAgentForwarding yes を追加する設定をしなくて済む
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
curl -sfSL https://raw.githubusercontent.com/naa0yama/devtool-wsl2/refs/heads/main/scripts/bin/setup.sh | bash
============================================
 GPG/SSH Agent Tools Setup (Remote)
============================================

[INFO] Configuring GPG...
[INFO] gpg.conf: 'no-autostart' already set
[INFO] gpg-agent systemd units: masked
[INFO] Installing systemd user units (Remote)...
Created symlink /home/naa0yama/.config/systemd/user/default.target.wants/gpg-socket-cleanup.service → /home/naa0yama/.config/systemd/user/gpg-socket-cleanup.service.
[INFO] systemd units: installed
[INFO] Installing shell configuration...
[INFO] Created: /home/naa0yama/.bashrc.d/22-gpg-agent.sh

============================================
 Setup complete!
============================================

To re-run setup: rm /home/naa0yama/.cache/devtool-setup.lock

Remote Linux で uid=1000 の場合 Windows 側の .ssh/config ではこのように記載する

1
2
3
4
5
6
Host remote-host
  HostName 192.0.2.1
  ForwardAgent yes
  User naa0yama
  RemoteForward /run/user/1000/gnupg/S.gpg-agent 127.0.0.1:4321
  # StreamLocalBindUnlink yes は書かない (systemd で処理)
Note

Windows 11 -> Remote Linux -> Target の ssh -A をする場合 Remote Linux 上でも AllowAgentForwarding yes が必要だが、 OpenSSH の標準設定として yes のため設定だけ確認してやることはない。

1
sudo sshd -T | grep -i allowagentforwarding

これで新規セッションでログインした後で署名コマンドを試すと署名できるはずである。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ echo "test" | gpg --clearsign -vv
gpg: enabled compatibility flags:
gpg: connection to the agent is in restricted mode
gpg: using subkey A088666E808857DD instead of primary key 794676DEF45A4D7F
gpg: writing to stdout
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

test
gpg: EDDSA/SHA512 signature from: "A088666E808857DD Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>"
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQQAtOsEtRBNAQHqhwWgiGZugIhX3QUCaWPMLQAKCRCgiGZugIhX
3UtWAQDbet0nBn5Ac6Mj3bgCBWHpBXyorTE5bK3gW4clJI7ErgD8DXukp10ebDWB
Dbg8jqn7TLpP7b+42RyyHD90S9qjzAA=
=/8vp
-----END PGP SIGNATURE-----

VSCode

VSCode には下記の設定をするとよい。いくつか好みがあるので解説する

  • ssh-agent

    • Host 側の SSH_AUTH_SOCK か NamedPipe(\\.\pipe\openssh-ssh-agent) を検知
    • コンテナ内に /tmp/vscode-ssh-auth-*.sock を作って転送する
  • gpg-agent

    • VSCode が gpgconf --list-dir agent-extra-socket を実行して gpg-agent の Extra socket パスを確認
    • コンテナ内に ~/.gnupg/S.gpg-agent を作って転送する
  • remote.SSH.useExecServer

    • true (デフォルト)
      • 軽量な制御サーバーを先にブートストラップしてから VS Code Server を起動
      • Remote 上で devcontainer を開くのに必要(devcontainer over SSH)
      • Remote 上で WSL を開くのに必要(WSL over SSH)
    • false
      • 一部の環境で Exec Server が正しく動作しない場合
      • ポートフォワーディングに問題がある場合
  • remote.SSH.useLocalServer

    • true (デフォルト)
      • Windows 11 上で接続を多重化して管理するため既存接続がある場合はそれを利用する
      • SSH の ControlMaster に相当する
    • false
      • 各 VSCode ウィンドウで独立した SSH 接続にする
      • 個人的にはこちらで安定しているので変更している
  • SSH_AUTH_SOCK の古いソケットを維持しないようにする。

    • terminal.integrated.persistentSessionReviveProcess
    • terminal.integrated.enablePersistentSessions
.vscode/settings.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "git.enableCommitSigning": true, //                                Enables commit signing with GPG, X.509, or SSH
  "git.alwaysSignOff": true, //                                      Controls the signoff flag for all commits.

  // ssh-agent を WSL2 や devcontainer で使うための回避策
  "remote.SSH.enableAgentForwarding": true, //                       SSH -A の転送を有効化
  "remote.SSH.useExecServer": true, //                               従来の接続方式を利用する
  "remote.SSH.useLocalServer": false, //                             Window 間で別々の接続にする
  "remote.SSH.remoteServerListenOnSocket": true, //                  Socket Listen を有効化
  "terminal.integrated.persistentSessionReviveProcess": "never", //  ターミナルの復元、再作成を行わない
  "terminal.integrated.enablePersistentSessions": false //           ターミナルセッション履歴を保持しない
}

参考情報

Hugo で構築されています。
テーマ StackJimmy によって設計されています。