Linux踏み台サーバを10台経由してWindows Remote Desktop接続する

企業内システムでは、セキュリティ向上を目的として、システム開発者が開発サーバ等にアクセスするために踏み台サーバを経由しなければいけない場合がよくあります。これが様々な事情で多段構成になっていることがあり、接続するだけで非常に面倒なので、できるだけ簡単に多段の踏み台サーバを超える方法について検証してみたいと思いました。

## システム構成

下図のシステム環境で検証します。

![リモートデスクトップ接続環境システム構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315655/cd738d06-7a34-7c1f-9ec0-2cb5f3fff101.png)

ローカル端末からLinux踏み台サーバを10台(`hop01, hop02, ..., hop10`)を経由して、最終接続先のWindowsサーバ(`target`)にアクセスします。この検証環境のサーバ設定は、下表の通りです。

- 検証環境のサーバ設定

|サーバ名|IPアドレス|OSユーザ名|SSH認証方式|秘密鍵ファイル|
|:--|:--|:--|:--|:--|
|hop01|10.0.1.10/24|centos|鍵認証|hop01.pem|
|hop02|10.0.2.10/24|centos|鍵認証|hop02.pem|
|hop03|10.0.3.10/24|centos|鍵認証|hop03.pem|
|hop04|10.0.4.10/24|centos|鍵認証|hop04.pem|
|hop05|10.0.5.10/24|centos|鍵認証|hop05.pem|
|hop06|10.0.6.10/24|centos|鍵認証|hop06.pem|
|hop07|10.0.7.10/24|centos|鍵認証|hop07.pem|
|hop08|10.0.8.10/24|centos|鍵認証|hop08.pem|
|hop09|10.0.9.10/24|centos|鍵認証|hop09.pem|
|hop10|10.0.10.10/24|centos|鍵認証|hop10.pem|
|target|10.0.100.10/24|Administrator|パスワード認証|なし|

今回は、AWSで検証環境を構築しました。踏み台サーバのユーザ認証には鍵認証方式を利用します。各サーバは、その一つ前のサーバが所属するサブネットからのSSH接続のみを受け付けるように、各サーバに割り当てたセキュリティグループで制限しています。

- 目標

ローカル端末のコンソール上で`ssh target_rdp`とコマンドを叩くと、10台の踏み台サーバを経由したトンネル接続が確立され、ローカル端末(`ポート番号:13389`)から最終接続先(`ポート番号:3389`)へのリモートデスクトップ通信を可能にすることを目標にします。

## 環境設定

多段SSHポートフォワーディングを行う方法は、コマンドラインやGUIなど複数あると思いますが、今回は、[SSH_CONFIG](https://euske.github.io/openssh-jman/ssh_config.html)を利用して接続します。SSH_CONFIGを利用すると、SSHコマンドのパラメータ管理が非常に楽になります。

### ローカル端末の設定

今回はローカル端末のユーザ名は「USER」で統一しています。

- configファイルの設定

まず、新規ファイルを作成してSSH_CONFIGの設定内容を記述します。設定ファイルは、ファイル名を`config`として保存します。下記の設定では、最下部に定義している接続名(Host)の`target-rdp`を実行すると、多段SSHポートフォワーディングのトンネル接続が確立するように記載しています。

```:config
Host hop01-rdp
  HostName 10.0.1.10
  User centos
  IdentityFile ~/.ssh/hop01.pem
  LocalForward 13389 localhost:13389
  Port 22

Host hop02-rdp
  HostName 10.0.2.10
  User centos
  IdentityFile ~/.ssh/hop02.pem
  ProxyJump hop01-rdp
  LocalForward 13389 localhost:13389

Host hop03-rdp
  HostName 10.0.3.10
  User centos
  IdentityFile ~/.ssh/hop03.pem
  ProxyJump hop02-rdp
  LocalForward 13389 localhost:13389

Host hop04-rdp
  HostName 10.0.4.10
  User centos
  IdentityFile ~/.ssh/hop04.pem
  ProxyJump hop03-rdp
  LocalForward 13389 localhost:13389

Host hop05-rdp
  HostName 10.0.5.10
  User centos
  IdentityFile ~/.ssh/hop05.pem
  ProxyJump hop04-rdp
  LocalForward 13389 localhost:13389

Host hop06-rdp
  HostName 10.0.6.10
  User centos
  IdentityFile ~/.ssh/hop06.pem
  ProxyJump hop05-rdp
  LocalForward 13389 localhost:13389

Host hop07-rdp
  HostName 10.0.7.10
  User centos
  IdentityFile ~/.ssh/hop07.pem
  ProxyJump hop06-rdp
  LocalForward 13389 localhost:13389

Host hop08-rdp
  HostName 10.0.8.10
  User centos
  IdentityFile ~/.ssh/hop08.pem
  ProxyJump hop07-rdp
  LocalForward 13389 localhost:13389

Host hop09-rdp
  HostName 10.0.9.10
  User centos
  IdentityFile ~/.ssh/hop09.pem
  ProxyJump hop08-rdp
  LocalForward 13389 localhost:13389

Host target-rdp
  HostName 10.0.10.10
  IdentityFile ~/.ssh/hop10.pem
  user centos
  ProxyJump hop09-rdp
  LocalForward 13389 10.0.100.10:3389
```

- configファイルの配置

作成したconfigファイルを、ローカル端末の`C:\Users\USER\.ssh`に配置します。Windows 10は最初は`.ssh`フォルダは存在していないと思うので、新規に作成します。

- 秘密鍵ファイルの配置

踏み台サーバの接続に必要な秘密鍵ファイルを、任意の場所に配置します。このconfigファイルでは、秘密鍵ファイルのパスを設定する`IdentityFile`パラメータで`~/.ssh/`を指定しているので、秘密鍵ファイル(`hop01.pem, hop02.pem, ..., hop10.pem`)を`C:\Users\USER\.ssh\`下に配置しておきます。

### 実行結果

- トンネル接続の確立

あとは、コマンドプロンプトを起動して、`target-rdp`を指定してsshコマンドを実行するだけです。

```:cmd
C:\Users\USER>ssh target-rdp
CreateProcessW failed error:2
posix_spawn: No such file or directory
```
これｄ...、あれ、エラーが出る…。

- エラーの原因

エラーの原因を調べてみたところ、OpenSSH for Windowsのバージョンの問題のようです。OpenSSH for Windows 7.9(2019/1/11リリース)未満では、[このIssue](https://github.com/PowerShell/Win32-OpenSSH/issues/1185)に該当してこのエラーが出るそうなので、クライアント端末のOpenSSHのバージョンを確認してみます。

```:cmd
C:\Users\USER>ssh -V
OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5
```

ローカル端末のSSHのバージョンが古いままでした。残念ながら、Windows 10標準搭載のOpenSSH for Windowsクライアントは、2019年11月現在ではこれが最新版のようでした。

#### エラー回避方法

OpenSSHのエラー回避方法として、以下が考えられると思います。

1. OpenSSHクライアント(Windows 10標準)を利用する [未検証]
    - Windows 10標準のOpen SSHクライアントがバージョン7.9以降にアップデートされるまで待つ。
1. OpenSSHクライアント(PowerShell Githubリポジトリ)を利用する [未検証]
    - Windows 10標準のOpen SSHクライアントをアンインストールする
    - [PowerShell Githubリポジトリ](https://github.com/PowerShell/Win32-OpenSSH/releases)から最新バージョンのバイナリをダウンロードし、Windows 10に別途インストールする。
1. OpenSSHクライアント(Ubuntu on Windows)を利用する
    - Windows 10に[Ubuntu on Windows](https://www.microsoft.com/ja-jp/p/ubuntu/9nblggh4msv6)をインストールして、Ubuntu上からLinux版Open SSHを利用する。

今回は、3のUbuntu on Windowsを利用する方法で確認してみます。

## 再環境設定

### ローカル端末の設定

- Ubuntu on Windowsのインストール

幸運なことに、Windows 10ではLinux環境を無償で準備できます。Windows 10のLinux環境のインストール方法については、[こちらのリンク](https://qiita.com/Aruneko/items/c79810b0b015bebf30bb)等を参考にさせていただきました。早速、ローカル端末上にLinux環境をインストールします。

- OpenSSHクライアントのバージョン確認

Linux環境のインストール後に、Ubuntu on WindowsのコンソールからSSHコマンドのバージョンを確認してみます。

```bash:shell
root@USER:~# ssh -V
OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n  7 Dec 2017
```

OpenSSH_for_Windowsでなくなったので、これでOKです。

- configファイルの設定

Windows環境で作成したconfigファイルを、そのまま流用します。

- configファイルの配置

Windows環境のconfigファイルを、ユーザディレクトリ直下の.sshディレクトリ(ここでは`/root/.ssh/`)にコピーして配置します。最初は.sshディレクトリが存在しないため、始めに`mkdir`コマンドでディレクトリを作成します。

```bash:shell
root@USER cd ~
root@USER mkdir .ssh
root@USER cp /mnt/c/Users/USER/.ssh/config .ssh/config
```

- 秘密鍵ファイルの配置

Windows環境の秘密鍵ファイルも、同様にLinux環境にコピーして配置します。最後のコマンドの権限設定を忘れると、sshコマンド実行時に`Bad owner or permissions`のエラーが出ます。

```bash:shell
root@USER:~/.ssh# cd /mnt/c/Users/USER/.ssh/
root@USER:/mnt/c/Users/USER/.ssh# cp hop01.pem hop02.pem hop03.pem hop04.pem hop05.pem hop06.pem hop07.pem hop08.pem hop09.pem hop10.pem /root/.ssh/
root@USER chmod 600 .ssh/*
```

### 実行結果

準備が完了したので、再度SSHコマンドを実行してみます。

- トンネル接続の確立

```:shell
root@USER:~# ssh target-rdp
Last login: Fri Nov 30 00:00:00 2019 from ip-10-0-9-10.ap-northeast-1.compute.internal
[centos@ip-10-0-10-10 ~]$
```

これで、ローカル端末から接続先サーバへのトンネル接続が確立しました。

- Windows Remote Desktopの実行

ローカル端末から、13389番ポートでリモートデスクトップ接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315655/84641351-228a-64dc-44fb-70cae30eea5e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315655/5e6544b6-ac7d-b6c4-daf0-3a92575be6da.png)

成功しました！リモートデスクトップの通信性能としては、操作時に微妙にネットワーク遅延のようなものを感じなくはない(ミリ秒以下レベル？)ですが、まあ十分利用できるくらいの使用感でした。

- 結論

SSH_CONFIGは便利。

## 参考リンク
多段SSHポートフォワーディングについて、参考にさせていただきました。
https://qiita.com/yuuki4891/items/bfe5c1d201524c6d1827
https://swfz.hatenablog.com/entry/2017/09/08/020137