SSHを利用して遠隔のネットワークに接続する
先日ゼミ内のVPNサーバに障害が発生し,ゼミネットワーク内に設置した各種マシンへアクセスできない状況になった.
幸いにも外部ネットワークからアクセスできるSSHサーバが存在するため,そのサーバを踏み台にしてゼミネットワーク内のサービスにアクセスできた.
この際に調べた事項のまとめ.
既存技術をまとめ直しているだけであり,特に目新しい情報はないのであしからず.
前提
参考サイト
https://qiita.com/ymd_/items/5eb833ad757bd8b3e6c3 http://inaz2.hatenablog.com/entry/2013/04/30/221348
遠隔マシンへの多段SSH
遠隔ネットワーク内のマシンへSSHしたい場合,DMZのSSHサーバを中継サーバとして多段のSSHをすることになる.
以下説明のため,次のようなサーバ構成だと仮定する.
サーバ種別 | ホスト名 | サーバアドレス | ユーザ名 |
---|---|---|---|
クライアントマシン | client | client-machine | clientUser |
DMZのSSHサーバ | dmz | dmz-server | dmzUser |
目的の接続先 | remote | remote-server | remoteUser |
単純に考えるとまずはDMZのSSHサーバにSSHし,そこから目的サーバにSSHすれば良いように感じる.
しかしこの手法は煩雑なので,次のようにすることでコマンド一発で多段のSSHを実現できる.
$ ssh dmzUser@dmz-server -t ssh remoteUser@remote-server
これは,sshコマンドに任意のコマンドを渡すことでssh先でコマンドを実行できる機能を利用して,ssh先でsshコマンドを実行している.
このとき,ssh先でttyを利用するので -t
オプションを指定する必要がある.
毎度このコマンドを打つのは冗長なので,~/.ssh/config
に設定を加えることで簡便に多段のsshを実現できる.
Host 中継機のホスト名 HostName 中継機のサーバアドレス User 中継機のユーザ名 Host 目的サーバのホスト名 HostName 目的サーバのアドレス User 目的サーバのユーザ名 ProxyCommand ssh -W %h:%p dmzのホスト名
ホスト名はsshコマンドでの指定に用いる名前で好きにつけることができる.
サーバアドレスは名前解決ができるならばFQDNでもIPアドレスでも構わない.
このとき,ProxyCommandを実行するのは中継機であるため,目的サーバのHostNameは中継機から名前解決できる必要がある.
例示したサーバ構成であれば次のような例になる.
Host dmz HostName dmz-server User dmzUser Host remote HostName remote-server User remoteUser ProxyCommand ssh -W %h:%p dmz
なお, -W
オプションは,%h %p が 本来の接続先である目的接続先名のHostNameとそのポートに置換される.
つまるところ以下の書き換えなのだが,中継機の情報が変更されることを考えると -W
オプションが利用できると便利.
$ ssh dmzUser@dmz-server -t ssh remoteUser@remote-server
以上のように ~/.ssh/config
に記述することで以下のコマンドを実行することで多段のSSHが実現される.
$ ssh remote
SSHエージェントの中継(ssh agent forwarding)
クライアントマシンの秘密鍵を用いて目的サーバへ公開鍵認証したい場合,中継機にクライアントマシンの秘密鍵を設置してしまうと中継機のroot権限を持つユーザに秘密鍵を悪用される可能性があり危険である.
このとき,ssh agent forwardingを利用することで,中継機にクライアントマシンの秘密鍵を設置する必要がなくなる.
sshの公開鍵認証は電子署名の仕組みを利用して認証を行っているが,中継機が目的サーバにSSHする際に求められる署名をクライアントマシンに肩代わりしてもらうことによって実現する.SSHの公開鍵認証の仕組みについては次のサイトなどが参考になる.
https://qiita.com/angel_p_57/items/2e3f3f8661de32a0d432
サーバ側の設定
中継機のsshd_configに AllowAgentForwarding yes
と設定する必要がある.
https://www.freebsd.org/cgi/man.cgi?sshd_config(5) や https://euske.github.io/openssh-jman/ssh_config.html を見る限り,デフォルトでyesの設定になっている.
ssh-agentの起動
まずssh-agentを起動する必要がある.
詳細は次のサイトが参考になる.
https://qiita.com/isaoshimizu/items/84ac5a0b1d42b9d355cf
agent fowarding
agent fowarding を利用する際には中継機へのssh実行時に -A
オプションを渡す.
ssh -A dmzUser@dmz-server -t ssh remoteUser@remote-server
なお,sshコマンド実行時に-Aオプションの指定を省略したい場合は ~/.ssh/config
にて中継機に ForwardAgent yes
と設定すればよい.
Host dmz HostName dmz-server User dmzUser ForwardAgent yes Host remote HostName remote-server User remoteUser ProxyCommand ssh -W %h:%p dmz
sftp
sftpにて多段の接続を行う場合は以下のようなコマンドが利用できる.
$ sftp -o "ProxyCommand ssh dmzUser@dmz-server -W %h:%p" remoteUser@remote-server
なお,sftpはsshを利用して実行されるため, ~/.ssh/config
の設定が適応される.
そのため,上述した設定が施されている場合,以下のコマンドで多段のsftpが利用できる.
$ sftp remote
scp
scpにて多段の接続を行う場合は以下のようなコマンドが利用できる.なお,この例ではlocalからremoteへファイルを転送する.
$ scp -r -o "ProxyCommand ssh dmzUser@dmz-server -W %h:%p" /local/path remoteUser@remote-server:/remote/path
なお,scpはsshを利用して実行されるため, ~/.ssh/config
の設定が適応される.
そのため,上述した設定が施されている場合,以下のコマンドで多段のscpが利用できる.
$ scp -r -o /local/path remoteUser@remote-server:/remote/path
Port Forwarding
sshコマンドはオプションを与えることでポートフォワーディングが行え,proxyサーバとして利用できるようになる.
Local Port Forwarding
いわゆる普通の Port Forwarding.
$ ssh -L 8080:remote-server:80 dmzUser@dmz-server
と実行することで,クライアントマシンにてlocalhostの8080番ポートにアクセスすると中継機からremote-serverの80番ポートにアクセスしたことになる.
ただし,HTTPリクエスト中のHostヘッダは書き換えられない(この場合はそのままlocalhost:8080となる)ため,HTTPサーバ側でVirtualHostを利用している場合はうまく表示されない可能性がある.
これを解決するためには,/etc/hostsを使って,アクセスしたい先のホスト名を127.0.0.1に名前解決するようにする.
127.0.0.1 httpserver.remote-server.com
なお,sshコマンド実行時に接続先の制御端末が表示されるのを抑制したい場合は -fN
オプションが利用できる.
$ ssh -fNL 8080:remote-server:80 dmzUser@dmz-server
Remote Port Forwarding
firewallなどによって,中継機へssh接続できない場合に利用できる可能性がある.
この手法では,クライアントマシンにsshサーバを立て,中継機からクライアントマシンへssh可能である必要がある.
以下のようにすることで,remote-serverへのアクセスが全て禁止されている状態でも,remote-serverから外部に接続できるportが存在すればproxyとして利用できる.
- クライアントマシン上にSSHサーバを立て,中継機からssh可能な状態にする
- 中継機からクライアントマシンへSSHする
$ ssh -R 8080:remote-server:80 clientUser@client-machine
- クライアントマシンでのlocalhost:8080へのアクセスが中継機からのremote-server:80のアクセスとなる
なお,sshコマンド実行時に接続先の制御端末が表示されるのを抑制したい場合は -fN
オプションが利用できる.
$ ssh -fNR 8080:remote-server:80 clientUser@client-machine
Dynamic Port Forwarding
sshdサーバをSOCKS Proxyとして使うことができる. これにより,VirutalHostを使用しているHTTPサーバにアクセスしたり,手元のネットワークのファイアウォールを迂回することができる. 非常に便利.
client-machineから dmz-serverへ -Dオプションを指定して ssh接続することで,client-machine上では socks5://localhost:1080
がSOCKSプロキシとして利用できるようになり,利用した通信は dmzUser@dmz-server 経由のアクセスとなる.
$ ssh -D 1080 dmzUser@dmz-server
ここでproxyを socks5://localhost:1080
とすると名前解決はクライアントマシンで行う必要があるが, socks5h://localhost:1080
といった風に設定すると,proxyサーバ側で名前解決を行うようになる.
なお,sshコマンド実行時に接続先の制御端末が表示されるのを抑制したい場合は -fN
オプションが利用できる.
$ ssh -fND 1080 dmzUser@dmz-server