SSH proxy コマンドの使い方について

ある機器へSSHアクセスする際、他のサーバ（jump server）を経由しないといけない場合は、SSHのproxyコマンドは有効である。簡単な環境でその使い方について説明する。

# 環境

- OS X: Mojave
- Docker desktop ver 2.0.0.3

# 環境構築

仮に以下のようなな環境ある。ユーザが `target server` へアクセスしたい。もしくは、targetサーバとscpでファイル交換したい。しかし、セキュリティ制限によって、ユーザから直接に`target server`へアクセスするのは許可されていない。かならず`proxy server`を経由する。一番シンプルなのは、順次にproxyサーバへログインしてから、targetサーバへログインして、作業さうる

毎回２段ログインすると大変である。より簡単な方法はSSHのproxyコンマンドを使うことである。簡単にSSH proxyコマンドを説明するために、以下のNWをdockerイメージを使い説明する。

```
+-------------+   +--------------+   +---------------+
|  ユーザ      +---+ proxy server +---+ target server |
+-------------+   +--------------+   +---------------+
```

# Dockerイメージ
まず、簡単に環境をつくるため、sshサーバを動くdockerイメージを作成する。

以下のDockerfileを準備する。

```dockerfile
FROM centos:centos7

# OpenSSH サーバをインストールする
RUN yum -y install openssh-server openssh-clients

# root でログインできるようにする
RUN sed -ri 's/^#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config

# root のパスワードを 設定
RUN echo 'rootpassword!' | passwd --stdin root

# 使わないにしてもここに公開鍵を登録しておかないとログインできない
RUN ssh-keygen -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -N "" -f /etc/ssh/ssh_host_ecdsa_key
RUN ssh-keygen -t ed25519 -N '' -f /etc/ssh/ssh_host_ed25519_key

# sshd の使うポートを公開する
EXPOSE 22

# sshd を起動する
CMD ["/usr/sbin/sshd", "-D"]
```
必要に応じて `rootpassword!`を変更し、Dockerfileと同じフォルダーでイメージを作成する。

```shell-session
$ docker build -t centos7-sshd .
```
成功すると、以下のようなイメージが出来上がる。

```shell-session
bash-3.2# docker images centos7-sshd
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos7-sshd        latest              d9c6d7216802        22 hours ago        299MB
```

このイメージを使い、２つコンテナーを起動させる。なお、`proxyサーバ` を従来のport 22の代わりに、20022を待ち受けるようにした。

```shell-session
$ docker run -d  --hostname centos7-sshd-proxy  -p 20022:22 --name centos7-sshd-proxy centos7-sshd:latest
$ docker run -d  --hostname centos7-sshd-target --name centos7-sshd-target centos7-sshd:latest
```

ここで２つsshサーバのコンテナが動くようになる。次回、コンテナーを起動したいときは簡単に`start`でできる。

```shell-session
$ docker start centos7-sshd-proxy centos7-sshd-target
```


# 2段ログイン
前節で作った２つのコンテナのSSH portは以下のようになる。

```
+-------------+            +--------------+        +---------------+
|  ユーザ      +----(20022)-+ proxy server +---(22)-+ target server |
+-------------+            +--------------+        +---------------+
```

ユーザがホストから127.0.0.2:20022へ `proxyサーバ`へアクセスできる。

```shell-session
$ ssh -p 20022 root@127.0.0.1
Enter passphrase for key '/Users/<省略>/.ssh/id_rsa':
root@127.0.0.1's password:
X11 forwarding request failed on channel 0
Last login: Mon May 20 11:33:29 2019 from gateway
```

更に、そこからport 22で`targetサーバ`へSSHログインできる。ここで、`proxy`から`target`へアクセスする際、docker内部のNWを使う。そのIPは以下のように確認できる

```
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' centos7-sshd-target
172.17.0.3
```

このIPを使い、`target`へSSHをしてみる

```shell-session
[root@centos7-sshd-proxy ~]# ssh root@127.17.0.3
<省略>
root@127.17.0.3's password:
Last login: Mon May 20 11:40:34 2019 from gateway
[root@centos7-sshd-proxy ~]#
```
proxyサーバを経由してtargetへログインする環境を構築して、確認できた。

# proxyコマンド
上のように２段ログインより、proxyコマンドを使うとこより、直接にtargetへログインすることができる。

```shell-session
bash-3.2# ssh -o ProxyCommand='ssh -p 20022 -W %h:%p root@127.0.0.1' root@172.17.0.3
root@127.0.0.1's password:
root@172.17.0.3's password:
Last login: Mon May 20 11:47:38 2019 from 172.17.0.2
[root@centos7-sshd-target ~]#
```
パスワードが２回に聞かれ、１回目はproxyサーバのもので、２回目はtargetのものである。proxyコマンドは以下のようなフォーマットになる。

```shell
ssh -o ProxyCommand='ssh -l root -p 20022 -W %h:%p <proxyユーザ>@<proxyサーバ>' <targetユーザ>@<targetアドレス>
```

# もうちょっと遊ぶ
とりあえず、やりたいことはできた。しかし、よく`%h:%p` はデフォルトホスト名とデフォルトポートだと説明されるが、少し意味わからない。ちょっといじってみた

```shell-session
bash-3.2# ssh -o ProxyCommand='ssh -p 20022 -W 172.17.0.3:22 root@127.0.0.1' xxx
root@127.0.0.1's password:
root@xxx's password:
Last login: Mon May 20 11:57:13 2019 from 172.17.0.2
[root@centos7-sshd-target ~]#
```
これで、proxy経由でtargetへログインできた。それに、途中でなぞのの`root@xxx's password:` 表示になっている。もうちょっと調べてみる。

まず、`-W` についてsshのmanは以下のように書いてある

```
-W ホスト :ポート
クライアントの標準入力と標準出力を、安全な通信路を通してホスト のポート 上に接続します。このオプションは、-N ,-T ,ExitOnForwardFailureおよびClearAllForwardingsを暗黙のうちに含んでいますが、これらは設定ファイルまたは-o オプションにより上書きすることができます。
```

`-W`はフォワードの設定するものである。今回の目的であれば、proxyサーバへログインした後、全てinput/output は %h:%p へフォワードされている。すなわち、ユーザからの操作はすべてtargetへフォワードされている。なお、`%h`,`%p`はProxyCommand中の特別意味を持っている。`%h`はProxyCommandの後（本来接続したい）のホストで、`%p`はその接続の時にポート番号である。`%h`は明示的に書かれている場合、ホストはあまり意味がもっていなくなる（上の`xxx`)


sshログインと同様に、`scp`とProxyコマンドを使い、`targetサーバ｀とフィアルやりとりも可能

```shell-session
$ scp -o ProxyCommand='ssh -p 20022 -W %h:%p root@127.0.0.1' test.txt root@172.17.0.3:/tmp/
```

# まとめ
簡単にsshサーバのdockerイメージをサクセスおよびそのイメージを使い、sshのproxyコマンドの追加たを説明した。

# 参考

- [CentOS7にDockerインストール → SSHでログインできるコンテナを作成](https://kishaku-kangen.blogspot.com/2017/09/centos7docker-ssh.html)
- [[robotframework] jupyterhub dockerとrobotframeworkのdockerイメージを作成方法](https://qiita.com/bachng/items/f3bc4ecd0f2beb3acaf0)