SSH: подключение в приватную сеть через Bastion и немного про Multiplexing

Автор: | 21/10/2017

Имеется сервер с доступом к порту 22 с домашнего IP – это будет rtfm-bastion.

За ним, в приватной сети, есть сервер баз данных, доступ к которому разрешён только с bastion хоста – это будет rtfm-db.

Задача: подключаться к серверу баз данных “напрямую”, без дополнительных команд на бастион-хосте (вообще это надо будет для Ansible, но можно использовать и в повседневной работе).

Т.е, вместо того, что подключаться на bastion, и потом на нём в консоли вызывать ssh user@rtfm-db – использовать одну команду с домашней машины.

Решение: SSH std i/o forwarding

По теме: C: libssh – пример SSH-“клиента” – посмотреть “изнутри” на процесс установления SSH-соединения и сессий в нём.

Настройка подключения к Bastion

Сначала – упростим подключение к bastion.

В ~/.ssh/config вносим:

Host rtfm-bastion
  Hostname rtfm.co.ua
  User setevoy
  IdentityFile /home/setevoy/.ssh/setevoy_main_priv_openssh

Сохраняем, проверяем:

[simterm]

09:40:49 [setevoy@setevoy-arch-home ~]  $ ssh rtfm-bastion
...
06:47:08 [setevoy@ip-172-31-43-63 ~]

[/simterm]

SSH Proxy – подключение к DB

Теперь – обновляем ~/.ssh/config на своей машине, добавляем подключение к rtfm-db через rtfmbastion:

Host rtfm-db
  Hostname 172.31.64.60
  User admin
  ProxyCommand ssh -W %h:%p rtfm-bastion
  IdentityFile /home/setevoy/Work/RTFM/Bitbucket/aws-credentials/rtfm-prod.pem

Тут 172.31.64.60 будет использоваться для подстановки в %h команды ProxyCommand, а -W указывает на форвадинг standard input/output.

Проверяем:

[simterm]

$ ssh rtfm-db
...
admin@ip-172-31-64-60:~$

[/simterm]

SSH Multiplexing

В настройках подключения к bastion – добавляем ControlMaster, ControlPath и ControlPersist:

Host rtfm-bastion
  Hostname rtfm.co.ua
  User setevoy
  IdentityFile /home/setevoy/.ssh/setevoy_main_priv_openssh
  ControlPath ~/.ssh/cm-%r@%h:%p
  ControlMaster auto
  ControlPersist 1m

Кратко – ControlMaster указывает ssh использовать уже имеющееся TCP соединение, если оно есть. ControlPath – путь к файлу сокета, а ControlPersist – поддерживать вторую открытую сессию, даже если первая сессия уже завершена.

Хороший обзор есть тут>>>.

Если не использовать ControlMaster, и в двух консолях открыть два подключения к rtfm-db – то мы будем иметь два отдельных TCP-соединения:

[simterm]

10:43:08 [setevoy@setevoy-arch-home ~]  $ sudo netstat -tanp | grep ssh 
tcp        0      0 192.168.1.102:51504     52.208.35.167:22        ESTABLISHED 3879/ssh 
tcp        0      0 192.168.1.102:51506     52.208.35.167:22        ESTABLISHED 3961/ssh

[/simterm]

Теперь – вернём ControlMaster, ControlPath и ControlPersist, закрываем соединения и открываем их заново, две штуки – проверяем соединения теперь (-t – отобразить только TCP):

[simterm]

$ sudo netstat -tanp | grep ssh
tcp        0      0 192.168.1.102:51050     52.208.35.167:22        ESTABLISHED 11587/ssh

[/simterm]

Используется только одно, а сессии устанавливаются через сокет, указанный в ControlPath:

[simterm]

$ sudo netstat -anp | grep ssh
tcp        0      0 192.168.1.102:51050     52.208.35.167:22        ESTABLISHED 11587/ssh
unix  2      [ ACC ]     STREAM     LISTENING     11026075 11614/ssh: /home/se  /home/setevoy/.ssh/[email protected]:22.Ij6tE5Qzr92bore3
unix  2      [ ACC ]     STREAM     LISTENING     18779    718/systemd          /run/user/1000/gnupg/S.gpg-agent.ssh
unix  3      [ ]         STREAM     CONNECTED     11026187 11859/ssh
unix  3      [ ]         STREAM     CONNECTED     11027227 11614/ssh: /home/se  /home/setevoy/.ssh/[email protected]:22.Ij6tE5Qzr92bore3
unix  3      [ ]         STREAM     CONNECTED     11026076 11587/ssh
unix  3      [ ]         STREAM     CONNECTED     11027131 11614/ssh: /home/se  /home/setevoy/.ssh/[email protected]:22.Ij6tE5Qzr92bore3

[/simterm]

В каталоге ~/.ssh на своей машине проверяем сокеты:

[simterm]

10:01:20 [setevoy@setevoy-arch-home ~]  $ ls -l .ssh/
total 60
srw------- 1 setevoy setevoy     0 Oct 21 10:01 [email protected]:22
10:01:58 [setevoy@setevoy-arch-home ~]  $ file .ssh/cm-setevoy\@rtfm.co.ua\:22
.ssh/[email protected]:22: socket

[/simterm]

Ну и время на открытие сессий.

Без ControlMaster – подключаемся и сразу выполняем exit, что бы замерить время только на открытие-закрытие подключения и сессии:

[simterm]

10:39:46 [setevoy@setevoy-arch-home ~]  $ time ssh rtfm-db "exit"

real    0m1.611s
user    0m0.028s
sys     0m0.006s
10:43:12 [setevoy@setevoy-arch-home ~]  $ time ssh rtfm-db "exit"

real    0m1.487s
user    0m0.031s
sys     0m0.004s
10:43:15 [setevoy@setevoy-arch-home ~]  $ time ssh rtfm-db "exit"

real    0m1.541s
user    0m0.028s
sys     0m0.009s

[/simterm]

Полторы секунды в среднем на каждое.

Возвращаем ControlMaster, повторяем:

[simterm]

10:24:12 [setevoy@setevoy-arch-home ~]  $ time ssh rtfm-db "exit"

real    0m1.988s
user    0m0.027s
sys     0m0.006s
10:24:55 [setevoy@setevoy-arch-home ~]  $ time ssh rtfm-db "exit"

real    0m0.817s
user    0m0.034s
sys     0m0.004s
10:25:00 [setevoy@setevoy-arch-home ~]  $ time ssh rtfm-db "exit"

real    0m0.809s
user    0m0.027s
sys     0m0.011s

[/simterm]

Первый раз почти 2 секунды – установление подключения, “рукопожатие”. Второй и третий раз – меньше секунды, т.к. используется уже имеющееся подключение (которое будет активно ещё ControlPersist 1m).

Ссылки по теме

Event Sequence of an SSH Connection

Using SSH Multiplexing

Running Ansible Through an SSH Bastion Host

OpenSSH/Cookbook/Multiplexing

Speeding up SSH Session Creation

ssh_config