Windows 環境で .ssh/config を活用したトンネリングの設定

# 記事の目的

元々Macで `.ssh/config` に設定をすることで簡単にsshトンネリングできるように設定して使っていたのですが、業務内容が変わったタイミングで作業PCをWindowsに移行した際、同じ手法でできないかと思って調べてみたらすんなりいけました。
ただ、Macではやり方をよく見かける `.ssh/config` を設定するやり方そのものズバリの説明記事がWindowsでは意外と見当たらなかったので社内共有の備忘録代わりにまとめました。

# 前提

環境は Windows10 Professional です。 
2020/12/22 に購入したマシンで、おそらく別途ソフトウェアのインストールなどは不要だと思うのですが、社内の別部署で初期セットアップをしてもらっている端末のため、もしかしたらOpenSSHが必要かもしれません。（多分最近のWindowsならプリインストールされていると思うのでデフォルトで使えるはず） 
以下の記事でファイルの内容を記述している部分については、全て `.ssh/config` ファイルの中身を指しています。

# やりたいこと

portfowarding いわゆるトンネリングを行います。 
踏み台サーバを経由して、インターネットに直接ポートを開けていない対象サーバに接続するというやつですね。 
想定する接続対象サーバがLinuxの場合とWindowsの場合に分けてご説明します。

## 対象サーバがLinuxの場合

最終的に接続する対象サーバがLinuxの場合には、踏み台となるサーバと接続対象サーバの2つのサーバの設定を記述します。

### 踏み台サーバ

まず、踏み台用サーバの記述が以下のようになります。

~~~config
Host           TNS-HOSTNAME
  HostName       100.100.100.100
  User           LINUX-USERNAME
  IdentityFile   ~/.ssh/TNS-KEYFILE.pem
  IdentitiesOnly yes
~~~

各設定内容は以下の通り。
> `TNS-HOSTNAME = 踏み台サーバを識別するための任意のホスト名`
`100.100.100.100 = 踏み台サーバのグローバルIPアドレス`
`LINUX-USERNAME = 踏み台サーバにログインするためのユーザー名`
`TNS-KEYFILE.pem = 踏み台サーバ用の鍵ファイル`

### 接続先サーバ（Linux）

続いて、接続先サーバの設定を記述します。

~~~config
Host           SV-HOSTNAME
  HostName       10.10.10.10
  Port           22
  User           LINUX-USERNAME
  IdentityFile    ~/.ssh/SV-KEYFILE.pem
  ProxyCommand C:\Windows\System32\OpenSSH\ssh.exe -l %r -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null TNS-HOSTNAME -W %h:%p
  IdentitiesOnly yes
~~~

各設定内容は以下の通り。
> `SV-HOSTNAME = 接続先サーバを識別するための任意のホスト名`
`10.10.10.10 = 接続先サーバのローカルIPアドレス（踏み台サーバから見た接続先サーバのIPアドレス）`
`LINUX-USERNAME = 接続先サーバにログインするためのユーザー名`
`SV-KEYFILE.pem = 接続先サーバ用の鍵ファイル`
`TNS-HOSTNAME = 先に設定した、踏み台サーバのホスト名`

肝になるのは `ProxyCommand` の部分で、Macで使う場合はこの部分が `ProxyCommand   ssh -CW %h:%p mp-dev-tun` このような記述をしていました。
OpenSSHのインストーフォルフォルダや、鍵ファイルの置き場所などが異なる場合などは適宜パスは読み替えてください。

上記2つの設定を `.ssh/config` に記載したら、あとはWindows PowerShell ターミナルを再起動して `ssh SV-HOSTNAME` とコマンドを入力するだけで、接続先サーバに接続することができます。 

もしエラーが発生する場合は、まずは `ssh TNS-HOSTNAME` を実行して、踏み台サーバには接続できるかを確認してください。
接続できない場合、

* 踏み台サーバのグローバルIPは正しいか。
* 踏み台サーバの鍵ファイルの指定は正しいか。
* 踏み台サーバのユーザー名は正しいか。

などの問題と思われます。
踏み台サーバには接続できるけど、接続先サーバに接続できない場合は

* ローカルIPアドレスは正しいか。
* 接続先サーバの鍵ファイルの指定は正しいか。
* 接続先サーバのユーザー名は正しいか。

を確認していただければつながると思います。

どれを確認してみても間違っていない、という場合は、環境的に接続が拒否されているなどの可能性がありますので、ネットワークの管理者などに確認して、環境に誤りがないかなどを確認しましょう。

1つの踏み台サーバを使って複数の接続先に接続したい場合は、 **踏み台サーバの設定は共通で利用が可能なため、1度記載するだけで大丈夫です** 。
接続先サーバの設定部分をコピペして、 `ホスト名` `ローカルIP` `鍵ファイル` を書き換えれば他の接続先に繋げられるようになりますので便利です。


## 対象サーバがWindowsの場合

対象サーバがWindowsの場合は、Linuxの踏み台サーバの接続を使いローカルポートフォワードをしつつ、リモートデスクトップを使って接続する形になります。
そのため、踏み台サーバの設定内容が少し変わることになります。

### 踏み台サーバ

~~~config
Host           TNS-HOSTNAME
  HostName       100.100.100.100
  User           LINUX-USERNAME
  LocalForward   13389 10.10.10.10:3389
  IdentityFile   ~/.ssh/TNS-KEYFILE.pem
~~~

LocalFoward 以外の項目については先程の踏み台サーバの設定と何も変わりませんが、注意点としては、 **このときのTNS-HOSTNAMEは、先程設定した踏み台サーバのホスト名とは別の名前にしておいたほうがいいと思います** 。
LocalFowardに記載している内容の詳細は以下の通り。

> `13389 = 接続先サーバに通すための、ローカルPCの任意のポート`
`10.10.10.10 = 接続先サーバのローカルIPアドレス（踏み台サーバから見た接続先サーバのIPアドレス）`

このように記載をしたら、ターミナル上で `ssh TNS-HOSTNAME` を実行して、踏み台のLinuxサーバにログインした状態にしてください。

### 接続先サーバ

これからリモートデスクトップで接続をするわけですが、リモートデスクトップを利用している間は、上で踏み台サーバにログインしたターミナルは **閉じずに開いておいてください** 。 
ターミナルを閉じてしまうとローカルポートが閉じてしまうため接続が切れてしまいます。

リモートデスクトップでは以下のように指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45794/059815c9-fe0a-7c95-5a5a-59d0008f98c8.png)

ローカルポートを開けているため、接続先は `127.0.0.1` とし、 `:13389` のように、先程LocalFowardで指定した任意のポート番号をしていします。
この状態で「接続」を押すと、通常のリモートデスクトップのようにパスワードなどの資格情報を求められることになりますので入力してもらえれば、リモートデスクトップでつなぐことができます。

もしつながらない場合は

* ローカルIPアドレスは正しいか。
* 指定した任意のローカルポートは同じ番号を指定できているか。

などを確認してください。
それでもつながらない場合は先ほどと同様に、管理者に環境的な問題などを確認してみましょう。


Macの場合と比べて、鍵ファイルのパーミッションの設定などが不要なため、コマンドのオプション方法などがわかれば一度設定してしまえばより簡単に利用できます。 
私は `ProxyCommand` 部分にMacで使うコマンドをコメントで残しておいて、configファイルを移し替えればMacでもWindowsでも使える設定ファイルとして使っています。 

以上、特に目新しいこともないごく標準的なやり方ですが、 `.ssh/config` を使った簡単トンネリング接続の設定方法でした。