1Passwordのssh-agent機能をWSL2でも利用する

かつては下に説明したやり方が必要でしたが、今はもう少しシンプルなやり方で WSL2 から Windows 側にインストールした 1Password が提供するssh-agent機能を使えるようになりました。

- [Use the 1Password SSH agent with WSL](https://developer.1password.com/docs/ssh/integrations/wsl/)

日本語での更新記事はこちら: [1Password の ssh-agent 機能を WSL/WSL2 でも利用する(2023/12版)](https://qiita.com/mfunaki/items/1d0987bb32f12051b8e1)

# はじめに
1Passwordのバージョン8では、SSH Keyの管理機能(エントリごとにpublic key, fingerprint, 秘密鍵を管理)、および、ssh-agent機能が導入されました。

これにより、例えばGitHubにSSH接続する際に、コマンドラインで`ssh-keygen`した後、`ssh-add`で生成された秘密鍵を追加、public keyはGitHubのウェブ画面から追加といった一連の作業をしなくても、1Passwordがいい感じに管理してくれます。

macOSでの設定例はclassmethodさんのDeveloperIOでt_o_dさんが(爆速で)共有くださっています。

- [Github等で利用するSSH keyの作成及び管理を1Passwordで行う](https://dev.classmethod.jp/articles/1password-git-ssh/)

Windowsに関しても、マニュアル(英語)どおりにやっていけば普通にできるのですが、WSLサポートに関しては、[ドキュメント](https://developer.1password.com/docs/ssh/agent/compatibility#git-for-windows)上も(公式には現時点では未サポートだけど)`npiperelay`と`socat`を使えばできるよ的な扱いなので、実際にやってみました。
![スクリーンショット 2022-04-09 084532.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/532a7fd2-b495-c94a-c6a3-b6071f7957ab.png)

# Windows側でのセットアップ
## 1Password 8のインストール、設定
まずは、1Passwordのバージョン8とご利用のブラウザで1Passwordプラグインをインストールする必要があります。[1Passwordのサイト](https://1password.com/jp/downloads/windows/)からWindows用のバージョン8のインストーラーを取得し、インストールを進め、ログインまで済ませてしまいましょう。

ログインが完了したら、1PasswordのSettings(設定)に追加されたDeveloper(開発者)メニューで、1Password SSH Agentでは Use the SSH agent (1PasswordのSSH agentを使用する)をチェックしておきます。SSHログインが必要なさまざまなサービスを使用し、かつ1PasswordのSSH agentを利用したいというのであれば、Display key names when authorizing connection(接続認証時にキー名を表示する)をチェックしておくとよいでしょう。

![スクリーンショット 2022-04-09 075038.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/11c70c33-3272-0d4e-3f0c-82798e66bf6d.png)

また、General(一般)メニューにある Keep 1Password in the notification area (1Passwordを通知エリアに保持する)をチェックすることで、1Password、および1Passwordが提供する ssh agent を常駐させておくことができますので、こちらも忘れずに設定しておきましょう。


## Windows Helloによるサインインの設定
次に、設定 > アカウント > サインイン オプション でサインイン時にWindows Helloを使う設定にします。顔認証や指紋認証に対応したPCであれば、GitHubへのpushも顔パス、指パスでできるようになります(未対応のPCでもPINベースの認証で対応可能です)。

![スクリーンショット 2022-04-09 090040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/033af4b0-c56e-c7cb-acb5-ee7c3e42d3ad.png)

## OpenSSH クライアントのインストール
次に、(WSL側ではなく)Windows側でOpenSSH クライアントをインストールする必要があります(つまり、Windows上ではMicrosoft謹製のSSH関連コマンドを使用する)。設定 > アプリ > オプション機能 から オプション機能を追加する を選択し、OpenSSH クライアントをインストールしてください。

![スクリーンショット 2022-04-09 080321.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/9d85dd7f-63ac-e81d-2b86-dbda56519c42.png)

忘れてはいけないのが、クライアントインストール時にOpenSSH クライアントに含まれるSSH agentも合わせてインストールされ、有効化されてしまうので、こちらは無効化しておきます。

Windowsキー + R で ファイル名を指定して実行 を表示し、`services.msc`でサービス一覧が表示されるので、OpenSSH Authentication Agentのスタートアップの種類を「無効」にしておきます。

![スクリーンショット 2022-04-09 081002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/810540fb-b7a3-f0cb-9c6e-4afbc15157b5.png)

ここまで設定したら、Windows をいったん再起動しておきましょう。

# GitHubでのSSHキー設定
次に、GitHubを例にとって、1PasswordでのSSHキー管理を見ていきましょう。

## SSHキー(秘密鍵・公開鍵)の作成・設定
ブラウザでGitHubサイトにアクセスし、Settings(設定)からSSH and GPG keys(SSHキーとGPGキー)を選択します。次に、New SSH key(新規SSHキー)ボタンをクリックすると、(1Passwordプラグインにより)SSHキーの作成...が表示されます。

![スクリーンショット 2022-04-09 075145.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/401205d3-cad7-4c07-f9e4-783cfe1e0de9.png)

SSHキーの作成...をクリックすると、SSHキーの作成と入力画面が出てきますので、Key Type(キー種別)を選択し、作成と入力ボタンをクリックします。

![スクリーンショット 2022-04-09 075219.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/14c86e77-9d33-f911-efb4-804614d9c1d7.png)

すると、秘密鍵が生成され1Passwordに格納され、秘密鍵に対応するPublic Key(公開鍵)がブラウザ画面上でGitHubに設定されます。

![スクリーンショット 2022-04-09 075328.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/d810fcdf-f7b4-cba8-b9f7-b339da73ef0c.png)

生成されたキーペアは1PasswordのSSH Keysカテゴリから参照可能です。

![スクリーンショット 2022-04-09 075414.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/af2e5a0b-0772-9f1d-4b9c-0dd59cb411c0.png)

# Windows側での設定・動作確認
ここまで完了したら、実際にWindows上で動作確認を進めていきましょう。

## 設定(core.sshCommand)
まずは、`git`コマンド実行時にSSHプロトコルを使用するのであれば、1Passwordのssh agentと連携するための設定を行います。([ドキュメント](https://developer.1password.com/docs/ssh/get-started#step-4-configure-your-ssh-or-git-client))
```shell
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"
```
## 動作確認
次に(おなじみの)`ssh -T git@github.com`をコマンドプロンプトに入力し、キーがGitHub側、ローカル側に正しく設定されているか確認します。正しく設定されていれば、(必要に応じ)Windows Helloでの認証画面が表示されるので、顔や指紋、PINコードなどで認証します。

![スクリーンショット 2022-04-09 082118.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/9349936b-ea9f-6ba7-dfb2-9f68f53f8ae2.png)

正しく設定されていれば、いつもの`Hi XXXXX! You've successfully authenticated, but GitHub does not provide shell access.`メッセージが表示されます。

正確には、ここで`git`コマンドでGitHubにアクセスしなければ、前述の core.sshCommand 設定の動作確認にはならないわけですが、先に進めていきましょう。

# WSL2側での設定・動作確認
さて、冒頭でお話しした`npiperelay`と`socat`を使ったWSL2側での1Password 8のssh agent連携に移りましょう。

## socatのインストール
まず、`socat`ですが、Ubuntu環境であれば`sudo apt install socat`でインストール可能です。その他の環境でも適宜、インストールしてみてください。

![スクリーンショット 2022-04-09 082353.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/89e75dea-f36d-2632-1c3d-ef9d02a7cacf.png)

## npiperelayのインストール
ssh agentはWindowsの名前付きパイプを使って通信を行いますが、`npiperelay`コマンドは、その名の通りnamed pipe(名前付きパイプ)をrelay(転送)することで、WSL2側からWindows上で動作するssh agentとの通信を可能にします。

GitHub上の[こちら](https://github.com/jstarks/npiperelay/releases)で配布されているので、npiperelay_windows_amd64.zip ファイルをダウンロードした後、ZIPファイルに含まれる npiperelay.exe ファイルをパスの通った場所にコピーしておきます(私はWSL2から呼び出せれば充分ということで、WSL2側の /usr/local/bin ディレクトリにコピーしました)。

## 動作確認
(この項の記述は、[Forwarding SSH Agent requests from WSL to Windows](https://stuartleeks.com/posts/wsl-ssh-key-forward-to-windows)の内容をほぼ引き写しています)
WSL2の画面から、まずは次の２行を実行します。
```shell-session
export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock
socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork &
```
次に、Windowsの場合と同様に `ssh -T git@github.com` を実行して、You've successfully authenticatedメッセージが出ることを確認します。

ここまで問題なくできていれば、前述の２行を毎回手作業で入力しなくても良いように(複数起動しないように)、以下の記述を`./.bash_profile`や`~/.bashrc`に追加しておきます。

```shell
# Configure ssh forwarding
export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock
# need `ps -ww` to get non-truncated command for matching
# use square brackets to generate a regex match for the process we want but that doesn't match the grep command running it!
ALREADY_RUNNING=$(ps -auxww | grep -q "[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent"; echo $?)
if [[ $ALREADY_RUNNING != "0" ]]; then
    if [[ -S $SSH_AUTH_SOCK ]]; then
        # not expecting the socket to exist as the forwarding command isn't running (http://www.tldp.org/LDP/abs/html/fto.html)
        echo "removing previous socket..."
        rm $SSH_AUTH_SOCK
    fi
    echo "Starting SSH-Agent relay..."
    # setsid to force new session to keep running
    # set socat to listen on $SSH_AUTH_SOCK and forward to npiperelay which then forwards to openssh-ssh-agent on windows
    (setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork &) >/dev/null 2>&1
fi
```

# おわりに
パスワードの保存やワンタイム パスコードの生成をWindowsにせよ macOSにせよ、OSの機能として備える中、1Passwordが管理対象を広げたり、CLIによる他ツールとの連携、また個人ベース、組織ベースのアカウントを共存など、さまざまな形で「あってうれしい」違いを提供し続けてくださることに感謝します。本機能の提供、ありがとうございました。