WSL2からDevcontainerへのSSH Agent転送

## 概要

VSCodeのDevcontainer機能を使うと、開発環境をコンテナ化して、プロジェクトごとに独立した環境を構築できます。しかし、コンテナ内でGit操作を行う際に、SSH鍵の取り扱いが課題となります。SSH Agent転送により、コンテナ内でGit操作などを行う際に、ホストOS側のSSH鍵を安全に利用でき、毎回パスフレーズを入力する手間を省けます。

WSL2上のDockerによるDevcontainerからgithubする際にホストOSの設定を流用したかったことと、思いのほか手間取ったため、備忘も兼ねて、WSL2上で動作するSSH Agentを、Devcontainer内で動作するコンテナに転送する手順を共有します。

## 前提条件

* Windows 11
* WSL2がインストール済みであり、ディストリビューションとしてUbuntu 22.04が使用されていること
* WSL2にDockerがインストール済みであること
* VSCodeがインストール済みであること
* VSCodeのRemote - Containers拡張機能と、必要に応じてRemote - SSH拡張機能がインストール済みであること
* WSL2でSSH Agentが起動していること

## 手順

1.  **WSL2側のSSH設定 (github.comへの接続)**

    github.comへ接続するための設定を`~/.ssh/config`に追記します。

    ```
    Host github.com
        HostName github.com
        User git
        IdentityFile ~/.ssh/id_ed25519
    ```

    設定後、以下のコマンドで接続を確認します。

    ```
    ssh -T github.com
    ```

2.  **devcontainer.jsonの作成**

    プロジェクトのルートディレクトリに`.devcontainer`ディレクトリを作成し、その中に`devcontainer.json`というファイルを作成します。

    ```json
    {
        "name": "team-llms-chat-dev",
        "image": "node:20",
        "extensions": [
            "dbaeumer.vscode-eslint"
        ],
        "mounts": [
            "source=${localEnv:SSH_AUTH_SOCK},target=${localEnv:SSH_AUTH_SOCK},type=bind"
        ],
        "forwardPorts": [
            22,
            3000
        ],
        "remoteEnv": {
            "SSH_AUTH_SOCK": "${localEnv:SSH_AUTH_SOCK}"
        }
    }
    ```

    * `name`: Devcontainerの名前を指定します。
    * `image`: 使用するDockerイメージを指定します。
    * `extensions`: インストールするVSCode拡張機能を指定します。
    * `mounts`: ホストのディレクトリやファイルをコンテナにマウントする設定を記述します。ここでは、ホストOS側のSSH Agentソケットをコンテナ内にマウントすることで、コンテナ内からホストOS側のSSH鍵を利用できるようにしています。
    * `forwardPorts`: ホストOSからコンテナへポートフォワードする設定を記述します。例えば、コンテナ内でWebアプリケーションを開発している場合、この設定によってホストOSからコンテナ内のアプリケーションにアクセスできます。
    * `remoteEnv`: コンテナ内の環境変数を設定します。`SSH_AUTH_SOCK`に、ホスト側のSSH Agentソケットのパスを設定します。

3.  **Dockerfileの作成**

    Dockerfileは必要ありません。devcontainer.jsonの`image`で指定したDockerイメージが使用されます。必要に応じて、`devcontainer.json`と同じディレクトリにDockerfileを作成し、`devcontainer.json`で指定することも可能です。

4.  **WSL2側の設定**

    WSL2の`.bashrc`に以下を追記します。

    ```bash
    if [ -z "$SSH_AUTH_SOCK" ]; then
        # Check for a currently running instance of the agent
        RUNNING_AGENT="`ps -ax | grep 'ssh-agent -s' | grep -v grep | wc -l | tr -d '[:space:]'`"
        if [ "$RUNNING_AGENT" = "0" ]; then
            mkdir -p /tmp/ssh
            # Launch a new instance of the agent
            ssh-agent -s -a /tmp/ssh/agent.sock &> $HOME/.ssh/ssh-agent
            ssh-add ~/.ssh/id_ed25519
        fi
        eval `cat $HOME/.ssh/ssh-agent` >& /dev/null
    fi
    ```

5.  **コンテナを起動する**

    VSCodeでプロジェクトを開き、Remote-Containers拡張機能の「Reopen in Container」コマンドを実行します。

6.  **コンテナ内でSSH Agentの動作を確認する**

    コンテナ内のターミナルで、以下のコマンドを実行して、SSH Agentが動作していることを確認します。成功すると、登録されているSSH鍵の一覧が表示されます。

    ```bash
    ssh-add -l
    ```

    ホスト側のSSH鍵がリストに表示されれば、設定は成功です。

## まとめ

この手順で、WSL2上のSSH AgentをDevcontainer内のコンテナに転送し、コンテナ内からホスト側のSSH鍵を利用できるようになります。これにより、コンテナ内でのGit操作などが安全かつスムーズに行えるようになります。

## 参考文献

* [Remote-Containers Documentation](https://code.visualstudio.com/docs/remote/containers)
* [WSL2とDevcontainerでSSH Agentを共有する](https://zenn.dev/hocitron/articles/9e0f11c502d844)