コンテンツにスキップ

WSL 上の Herdr で Windows OpenSSH と 1Password SSH Agent を使う

Windows 上の 1Password SSH Agent に SSH 鍵を置き、WSL から Windows OpenSSH のssh.exeを使っている環境で、Herdr のherdr --remote <host>からも同じ認証経路を使えるようにしました。herdr --remote <host>は、SSH でリモートホストへ接続して Herdr の remote session を開くコマンドです。

対象は 2026-09-28 時点の Herdr と WSL2 で、次の環境で検証しました。

  • WSL2: 6.18.33.2-microsoft-standard-WSL2
  • Windows OpenSSH: OpenSSH_for_Windows_9.5p2
  • 前提: Windows 側で 1Password SSH Agent を有効化し、ssh.exe workboxで接続先ホストworkboxへ接続できる

1Password で Windows Hello を有効にしている場合、SSH 鍵の利用承認も Windows 側で完結します。

Herdr から Windows の SSH Agent を使えない

WSL では Windows の実行ファイルを直接起動できます。そのため、通常のシェル操作だけなら次の alias でもssh.exeを利用できます。

alias ssh=/mnt/c/Windows/System32/OpenSSH/ssh.exe

しかし、これでは Herdr に効きません。Herdr はシェルを介さず、PATH からsshという実行ファイルを直接起動するためです。herdr --remote workboxを実行すると alias ではなく Linux 側の/usr/bin/sshが選ばれ、Windows 上の 1Password SSH Agent を利用できません。

そこで、alias ではなく PATH 上のssh自体をラッパーへ差し替えることにしました。

PATH 上のsshを Windows OpenSSH へ差し替える

私の開発環境では、dotfiles の~/setup/dotfiles/binを/usr/binより前に PATH へ追加しています。このディレクトリにsshというラッパーを置き、WSL では Windows OpenSSH を、それ以外の環境では本来のsshを実行します。

実装の中心部分は次のとおりです。

#!/usr/bin/env bash
set -uo pipefail

windows_ssh="${SSH_WRAPPER_WINDOWS_SSH:-/mnt/c/Windows/System32/OpenSSH/ssh.exe}"
binfmt_dir="${SSH_WRAPPER_BINFMT_DIR:-/proc/sys/fs/binfmt_misc}"

wsl_interop_enabled() {
  local entry
  for entry in "${binfmt_dir}"/WSLInterop*; do
    [[ -e "${entry}" ]] && return 0
  done
  return 1
}

if wsl_interop_enabled; then
  if [[ -f "${windows_ssh}" && -x "${windows_ssh}" ]]; then
    unset SSH_AUTH_SOCK
    exec "${windows_ssh}" "$@"
  fi

  if [[ -d "${windows_ssh%/*/*}" ]]; then
    echo "ssh: ${windows_ssh} を実行できないため、Linux の ssh を使います" >&2
  fi
fi

self="${BASH_SOURCE[0]}"
IFS=: read -r -a path_entries <<<"${PATH}:"

for dir in "${path_entries[@]}"; do
  candidate="${dir:-.}/ssh"
  if [[ -f "${candidate}" && -x "${candidate}" && ! "${candidate}" -ef "${self}" ]]; then
    exec "${candidate}" "$@"
  fi
done

echo "ssh: PATH に本来の ssh が見つかりません" >&2
exit 127

単に/mnt/c/Windows/System32/OpenSSH/ssh.exeを呼ぶだけではなく、WSL interop が有効かをWSLInterop*の登録から判定しています。WSL 以外では PATH 上の次のsshを探索するため、同じ dotfiles を macOS や通常の Linux でも利用できます。

SSH_AUTH_SOCKは Windows OpenSSH を起動する直前に削除します。通常の WSL 環境では、Linux 側のSSH_AUTH_SOCKが Windows プロセスへ渡ることはありません。それでも削除するのは、WSLENVなどで明示的に渡している環境でも Windows 側の Agent を確実に使わせるためです。

また、ラッパー自身を PATH から再び見つけて無限再帰しないよう、-efで同じファイルを除外しています。Linux の OpenSSH を明示的に使いたい場合は/usr/bin/sshを直接実行できます。

実際の実装はNishikoh/dotfiles#34にあります。

Herdr の SSH 管理を無効にする

ラッパーを置くだけでは、herdr --remoteが正常に動きません。Herdr はデフォルトで SSH 接続用の一時設定を生成し、Linux と macOS では接続を再利用するための control socket も作成します。

その状態で Windows のssh.exeを起動すると、Herdr が生成した Linux 側のパスが-Fや-Sに渡ります。

ssh.exe -F /home/user/.../config -S /home/user/.../ctl ...

Windows OpenSSH はこれらを Windows のファイルや socket として扱えないため、WSL からssh.exeを使う場合は Herdr の SSH 管理を無効にします。

~/.config/herdr/config.tomlに次を追加します。

[remote]
manage_ssh_config = false

これで Herdr は生成した SSH config や control socket を使わず、PATH 上のsshを通常の OpenSSH クライアントとして起動します。そのsshが先ほどのラッパーに解決されるため、実際の接続は Windows OpenSSH が担当します。

この変更により、読み込む SSH config も WSL 側の~/.ssh/configではなく Windows 側の%USERPROFILE%\.ssh\configに変わります。Herdr が通常追加する keepalive も無効になるため、必要なら Windows 側の SSH config に次のように設定します。

1
2
3
Host *
    ServerAliveInterval 15
    ServerAliveCountMax 4

最終的な接続経路は次のようになります。

herdr --remote workbox
        |
        v
~/setup/dotfiles/bin/ssh
        |
        v
C:\Windows\System32\OpenSSH\ssh.exe
        |
        +-- %USERPROFILE%\.ssh\config
        |
        +-- 1Password SSH Agent
        |
        v
     workbox

Herdr や WSL に秘密鍵を置く必要はなく、SSH の認証は Windows 側へ集約できます。

動作を検証する

まず PATH 上でラッパーが選ばれることを確認します。

command -v ssh
ssh -V

検証環境では次の Windows OpenSSH が起動しました。

OpenSSH_for_Windows_9.5p2, LibreSSL 3.8.2

次に通常の SSH 接続を確認します。

ssh workbox

ここで Windows 上の 1Password SSH Agent が使われることを確認した後、Herdr から同じホストへ接続します。

herdr --remote workbox

2026-09-28 の WSL2 実機では、この構成で Herdr の remote session へ接続できました。

ラッパーには、ネットワークへ接続しないテストも用意しました。確認している主な項目は次のとおりです。

  • Windows OpenSSH と Linux OpenSSH の振り分け
  • SSH_AUTH_SOCK
  • 引数と終了コード
  • 再帰防止
  • PATH の空要素
  • WSL 上のコンテナ

Herdr は Linux リモートへ自身のバイナリを SSH の stdin 経由で送るため、ラッパーが標準入力を壊さないことも必要です。テストでは 1 MiB のランダムなバイナリを Windows OpenSSH 側と Linux OpenSSH 側の両経路へ渡し、入力と出力が一致することを確認しました。

まとめ

WSL 上の Herdr から Windows の 1Password SSH Agent を使うには、Agent の socket を WSL へ転送するのではなく、Windows OpenSSH 自体を Herdr から起動する構成にすると単純です。

Herdr はシェルの alias を参照しないため、ssh.exeの alias ではなく PATH 上のsshをラッパーへ差し替えます。また、Herdr が Linux 用に生成する SSH config と control socket は Windows OpenSSH と互換性がないため、remote.manage_ssh_config = falseが必要です。

この構成では SSH config、秘密鍵、1Password SSH Agent を Windows 側へ集約しつつ、Herdr 本体は WSL 上で動かせます。Windows OpenSSH を利用しない環境ではラッパーが通常のsshへフォールバックするため、dotfiles の共通設定も維持できます。

参考