Summary ¶
上記で、 Windows 11 環境にひと通り環境構築したわけですが ssh-agent を利用して開発環境用に Remote のサーバーに ForwardAgent で転送して使うと ssh-add -l
など挙動をした時にハングアップしてしまい対策に困っていた。まだ完全とはいかないが少なくても以前よりは安定した状態にできたのでこちらにまとめる。
OpenSSH のバージョンアップ ¶
Windows 10 から OpenSSH が付属している。
がこれは、皆さんがよく使っている Linux に付属する OpenSSH と違い Microsoft が Windows 用に実装した OpenSSH である。これの利点は混沌としている、 Windows の SSH 環境で使えるように実装されており NamedPipe を利用して ssh-agent 機能が提供できるようになっている。
ここまではいいのだが、 Windows 11 付属の OpenSSH は version 8.6p1, LibreSSL 3.4.3
となっているため Ubuntu 22.04 などと合わせて使ったり WSL2 上に Ubuntu 22.04 を立てて使う場合最新版までの間に追加された拡張命令が来た瞬間に応答を停止するなど事象がある。
そのため、個人的にはアップデートをおすすめする。
また今回の version は共存できるが、 Shell の Path 順序での判定で気持ち悪いので標準付属の物はアンインストールしてしまうことにした。
OpenSSH 8.6p のアンインストール ¶
1
2
| > ssh -V
OpenSSH_for_Windows_8.6p1, LibreSSL 3.4.3
|
Note
PowerShell 7 だとうまくいかず、下記のエラーを吐きます
1
| Get-WindowsCapability: クラスが登録されていません
|
そのため、明示的に powershell.exe
を呼び出し実行とします
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
| #
# 管理者権限プロンプトを立ち上げて作業
#
> powershell.exe
> Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Name : OpenSSH.Client~~~~0.0.1.0
State : Installed
Name : OpenSSH.Server~~~~0.0.1.0
State : NotPresent
> Remove-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Path :
Online : True
RestartNeeded : True
> Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Name : OpenSSH.Client~~~~0.0.1.0
State : UninstallPending
Name : OpenSSH.Server~~~~0.0.1.0
State : NotPresent
|
OpenSSH 9.5p のインストール ¶
winget
でインストールをおすすめする。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| > winget search openssh
名前 ID バージョン 一致 ソース
------------------------------------------------------------------
SSHells dzonder.sshells 0.1.4 Tag: openssh winget
OpenSSH Beta Microsoft.OpenSSH.Beta 9.5.0.0 winget
> winget install Microsoft.OpenSSH.Beta
見つかりました OpenSSH Beta [Microsoft.OpenSSH.Beta] バージョン 9.5.0.0
このアプリケーションは所有者からライセンス供与されます。
Microsoft はサードパーティのパッケージに対して責任を負わず、ライセンスも付与しません。
ダウンロード中 https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.5.0.0p1-Beta/OpenSSH-Win64-v9.5.0.0.msi
██████████████████████████████ 5.47 MB / 5.47 MB
インストーラーハッシュが正常に検証されました
パッケージのインストールを開始しています...
インストールが完了しました
|
これで標準付属のやつはアンインストールされ 9.5p がインストールされた状態になるはずのためアンインストールが出来ているか確認する
1
2
3
4
5
6
7
8
9
10
11
12
| #
# 管理者権限プロンプトを立ち上げて作業
#
> powershell.exe
> Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Name : OpenSSH.Client~~~~0.0.1.0
State : NotPresent
Name : OpenSSH.Server~~~~0.0.1.0
State : NotPresent
|
Note
再起動後、 新しくインストールした OpenSSH 9.5.0.0 の 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
| #
# 管理者権限プロンプトを立ち上げて作業
#
> 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
|
gpg-agent 設定 ¶
$env:APPDATA\gnupg\gpg-agent.conf
に gpg-agent.conf を作成します。
この時 enable-win32-openssh-support
を追加することで Windows 搭載の OpenSSH からも利用することができるようになります。
enable-ssh-support
は Windows では機能しないため、記載する必要はありません
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| $confContent = @"
# Ref: https://www.gnupg.org/documentation/manuals/gnupg/Agent-Options.html
###+++--- GPGConf ---+++###
enable-putty-support
enable-win32-openssh-support
###+++--- GPGConf ---+++###
# GPGConf edited this configuration file.
# It will disable options before this marked block, but it will
# never change anything below these lines.
"@
New-Item "$env:APPDATA\gnupg" -ItemType Directory
Set-Content -Path $env:APPDATA\gnupg\gpg-agent.conf -Value $confContent
|
Scdaemon 設定 ¶
PC/SC(Personal Computer/Smart Card) を gpg-agent で使う場合 PC/SC を専有する設定になっているようなので、共有するように変更し gpg-agent に内蔵されている CCID ドライバーを無効化し Windows 標準の Smart Card サービスを使うように設定します。
YubiKey のデバイス名 ¶
YubiKey の Device Name が Series 4, 5 で名前が違うらしいため、自身の利用する YubiKey を刺して確認する
私の、 YubiKey 5 NFC は Yubico YubiKey
でしたのでこちらを後で使います。
1
2
3
| > Get-PnpDevice -Class SoftwareDevice | Where-Object {$_.FriendlyName -like "*YubiKey*"} | `
Select-Object -ExpandProperty FriendlyName
Yubico YubiKey OTP+FIDO+CCID 0
|
設定ファイルの書き出し ¶
Yubico から設定記事が出ているので、これを参考にする
pcsc-shared
を設定すると gpg-agent による PIN Cache がされず、毎回入力しなければならないので設定しない。
1
2
3
4
5
6
7
8
9
10
11
12
| $confContent = @"
# Ref: https://www.gnupg.org/documentation/manuals/gnupg/Scdaemon-Options.html
###+++--- ScdaemonConf ---+++###
disable-ccid
reader-port Yubico YubiKey
###+++--- ScdaemonConf ---+++###
"@
New-Item "$env:APPDATA\gnupg" -ItemType Directory
Set-Content -Path "$env:APPDATA\gnupg\scdaemon.conf" -Value $confContent
|
テスト ¶
設定を変更したら下記コマンドで gpg-agent を再起動しましょう
1
2
3
4
5
6
7
8
| # 設定の再読み込み
gpgconf --reload
# gpg-agent をすべて強制終了
gpg-connect-agent killagent /bye
# gpg-agent 1次起動 & debug
gpg-agent --daemon --verbose
|
YubiKey にアクセスできるか?
を確認して、 YubiKey に設定してある公開鍵をダウンロードして配置します。
正しく動けば、公開鍵がインポートされます。
1
2
3
4
5
6
7
8
9
10
11
| > gpg --card-edit
gpg: keybox'C:\\Users\\naa0yama\\AppData\\Roaming\\gnupg\\pubring.kbx'が作成されました
gpg/card> fetch
gpg: 鍵を'https://keybase.io/naa0yama/pgp_keys.asc'から要求
gpg: C:\\Users\\naa0yama\\AppData\\Roaming\\gnupg\\trustdb.gpg: 信用データベースができました
gpg: 鍵794676DEF45A4D7F: 公開鍵"Naoki Aoyama <[email protected]>"をインポートしました
gpg: 処理数の合計: 1
gpg: インポート: 1
gpg/card> q
|
インポートされた鍵を確認してみます。
下記のように鍵が見えれば問題ありません、信頼しておきましょう
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
| > gpg -k
C:\Users\naa0yama\AppData\Roaming\gnupg\pubring.kbx
---------------------------------------------------
pub nistp521 2024-09-13 [C]
65284A0A9205C52EBC16BBCF794676DEF45A4D7F
uid [ 不明 ] 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-edit <KEYID>
gpg> trust
1 = 知らない、または何とも言えない
2 = 信用し ない
3 = まぁまぁ信用する
4 = 充分に信用する
5 = 究極的に信用する
m = メーン・メニューに戻る
あなたの決定は? 5
本当にこの鍵を究極的に信用しますか? (y/N) y
[ 不明 ] (1). Naoki Aoyama <9667078+naa0yama@users.noreply.github.com>
プログラムを再起動するまで、表示された鍵の有効性は正しくないかもしれない、
ということを念頭においてください。
gpg> q
> gpg -k
gpg: 信用データベースの検査
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: 深さ: 0 有効性: 1 署名: 0 信用: 0-, 0q, 0n, 0m, 0f, 1u
C:\Users\naa0yama\AppData\Roaming\gnupg\pubring.kbx
---------------------------------------------------
pub nistp521 2024-09-13 [C]
65284A0A9205C52EBC16BBCF794676DEF45A4D7F
uid [ 究極 ] 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]
|
1
2
3
4
5
| # 起動して各 agent が started になっていることを確認する
> gpg-agent --daemon --verbose
gpg-agent[24196]: gpg-agent (GnuPG) 2.4.5 started
gpg-agent[24196]: putty message loop thread started
gpg-agent[24196]: Win32-OpenSSH thread started
|
上記を実施したあとに別タブで ssh-add -l
を実行すると下記のよう表示される。
表示を確認でしたら一度 gpg-agent
を終了する
1
2
3
4
| # 下記のように cardno:XX_XXX_XXX の表記がある鍵が2つ見えるはず
> ssh-add -l
256 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX cardno:XX_XXX_XXX (ED25519)
2048 SHA256:/XXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXX cardno:XX_XXX_XXX (RSA)
|
スタートアップ登録 ¶
スタートアップに登録する
gpg-connect-agent.vbs
という名前でスタートアップフォルダーに VBS スクリプトを作成して自動起動するようにしておく、クリックする事に一度全て終了させて起動するようにしているのがトラブル回避とこだわりポイント。
1
2
3
4
5
6
7
8
| $confContent = @"
Set objWShell = CreateObject("Wscript.Shell")
objWShell.run "gpg-connect-agent killagent /bye", vbHide
WScript.Sleep 1000
objWShell.run "gpg-connect-agent /bye", vbHide
"@
Set-Content -Path "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\gpg-connect-agent.vbs" -Value $confContent
|
登録したスタートアップを Win
+ R
を実行し shell:startup
にある作成した gpg-connect-agent.vbs
を起動する。
gpg-agent
が稼働していることを確認
1
2
3
4
5
| > Get-Process -Name 'gpg-agent'
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
17 3.86 12.85 0.16 1668 1 gpg-agent
|
Windows Terminal に戻って ssh-add -l
を実行すると先程実行した時と同様に鍵が2つ見える
1
2
3
| > ssh-add -l
256 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX cardno:XX_XXX_XXX (ED25519)
2048 SHA256:/XXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXX cardno:XX_XXX_XXX (RSA)
|
Git 設定 ¶
SSH Signing keys を利用するように設定します。
git config --global user.signingkey $confContent
は 刺さっているカードの公開鍵を利用するようにしています <SSH 公開鍵の中身>
1
2
3
4
5
6
7
8
9
10
11
12
| $confContent = (ssh-add -L | Select-String -Pattern '^(ssh-ed25519\s.*)\s' | % {"$($_.matches.groups[1])"})
git config --global user.email 9667078+naa0yama@users.noreply.github.com
git config --global user.name "Naoki Aoyama"
git config --global user.signingkey $confContent
git config --global commit.gpgsign true
git config --global fetch.prune true
git config --global gpg.format ssh
git config --global merge.ff false
git config --global pull.ff only
git config --global push.autoSetupRemote true
|
Git for Windows を入れてない場合は下記のように .gitconfig
を作成することで代用します
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
| $confContent = (ssh-add -L | Select-String -Pattern '^(ssh-ed25519\s.*)\s' | % {"$($_.matches.groups[1])"})
$gitconfigContent = @"
[user]
email = [email protected]
name = Naoki Aoyama
signingkey = $confContent
[commit]
gpgsign = true
[fetch]
prune = true
[gpg]
format = ssh
[merge]
ff = false
[pull]
ff = only
[push]
autoSetupRemote = true
"@
$gitconfigContent
|
OpenSSH ¶
OpenSSH Client ¶
ssh-add -l
を実行して鍵が見える場合はなにもしなくても利用できるはずです。
もうファイルで鍵を置く必要はありません。
Server 側 ¶
踏み台サーバー上でも ssh-agent を使いたい場合は sshd に設定の追加が必要です
/etc/ssh/sshd_config
1
| AllowAgentForwarding yes
|
追加後 sshd を再起動して設定の反映を確認します
1
2
3
4
5
6
| > systemctl restart sshd
> sshd -T | grep allow
allowtcpforwarding yes
allowagentforwarding yes
allowstreamlocalforwarding yes
|
Tera Term(Pageant) ¶
通常の方法でログイン方式の選択に「Pageantを使う」を選択すればよい

WSL2(OpenSSH -> wsl2-ssh-agent) ¶
事前に wsl2-ssh-agent を導入すれば何もしなくても WSL2 内から鍵を利用できるはずです。
私は WSL2 をヘビーに使うので下記のレポジトリで管理しています。
1
2
3
4
5
6
| user@hostname:~$ env | grep SSH_
SSH_AUTH_SOCK=/home/user/.ssh/wsl2-ssh-agent.sock
user@hostname:~$ ssh-add -l
256 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX cardno:XX_XXX_XXX (ED25519)
2048 SHA256:/XXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXX cardno:XX_XXX_XXX (RSA)
|
VSCode ¶
VSCode で下記の2つを設定しておくと Commit 時に署名を強制できる。
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,
"remote.SSH.useLocalServer": false, // Window 間で別々の接続にする
"remote.SSH.useExecServer": false, // 従来の接続方式を利用する
"remote.SSH.remoteServerListenOnSocket": true, // Socket Listen を有効化
"terminal.integrated.persistentSessionReviveProcess": "never", // ターミナルの復元、再作成を行わない.
"terminal.integrated.enablePersistentSessions": false // ターミナルセッション履歴を保持しない
}
|
remote*
, と terminal*
は WSL2 上で ssh-agent を使う場合うまく SOCK を引き継げない事象になることがあるので追記している。