Создание SSH-туннеля. Часть 3 из 4

19.01.2020

Теги: CLILinuxSSHUbuntuВиртуализацияКомандаКонфигурацияНастройкаСервер

Мы создавали ssh-туннели между виртуальными машинами, где сетевые соединения стабильны. Но в реальной жизни каналы связи оставляют желать много лучшего. Было бы разумно как-то отслеживать наличие соединения и автоматически его восстанавливать.

В OpenSSH присутствует стандартная схема для мониторинга состояния подключения, причем как на стороне сервера, так и на стороне клиента. Суть ее заключается в том, что OpenSSH будет проверять наличие рабочего подключения и в случае отсутствия такового будет просто завершать ssh-сеанс, избавляя нас от зависших сессий.

Проверка активности соединения

Для этого отредактируем файл конфигурации /etc/ssh/sshd_config на виртуальной машине ssh-server:

$ sudo nano /etc/ssh/sshd_config
# отключаем дефолтный механизм проверки активности соединения
TCPKeepAlive no
# проверять активность подключения клиента каждые 30 секунд
ClientAliveInterval 30
# сервер закроет соединение после трех неудачных попыток
ClientAliveCountMax 3

$ sudo systemctl restart ssh.service

Если что-то произойдет с клиентом, например, компьютер просто отключится от сети, то через 90 секунд ssh-server закроет туннельное соединение.

В файле /etc/ssh/sshd_config есть параметр TCPKeepAlive, который по умолчанию имеет значение yes. Он позволяет поддерживать TCP-соединение в активном состоянии, даже когда нет передачи пакетов. Эта решается на уровне протокола TCP/IP с помощью отправки специальных проверочных пакетов.

Кроме того, OpenSSH имеет альтернативные средства контроля активности сеансов — ClientAliveInterval и ClientAliveCountMax. При использовании этих параметров, в отличие от TCPKeepAlive, запросы отправляются через защищённый ssh-канал и не могут быть подменены.

При создании туннельного подключения со стороны клиента есть возможность указать аналогичные параметры ServerAliveInterval и ServerAliveCountMax. Команда создания туннеля на виртуальной машине web-server:

$ ssh -p 2222 -o "TCPKeepAlive no" -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
> -R 3306:127.0.0.1:3306 evgeniy@192.168.110.8
Иногда возможна ситуация, когда порт не был проброшен, хотя туннель был поднят. То есть, со стороны ssh-сервера и ssh-клиента все будет выглядеть нормально, туннель будет существовать и работать, но вот порт не будет проброшен. Для этого случая предусмотрен дополнительный параметр ExitOnForwardFailure yes.

Параметры на стороне клиента можно задавать как в командной строке, так и записать их в файл конфигурации:

$ nano ~/.ssh/config
# Проброс соединения 192.168.110.8 ==R==> 192.168.110.12
Host remote-forward-ssh-server
  HostName 192.168.110.8
  Port 2222
  User evgeniy
  IdentityFile ~/.ssh/tcp-forward-ssh-server
  TCPKeepAlive no
  ServerAliveInterval 30
  ServerAliveCountMax 3
  ExitOnForwardFailure yes
  RemoteForward 3306 127.0.0.1:3306

# Проброс соединения 192.168.110.8 <==L== 192.168.110.12
Host local-forward-ssh-server
  HostName 192.168.110.8
  Port 2222
  User evgeniy
  IdentityFile ~/.ssh/tcp-forward-ssh-server
  TCPKeepAlive no
  ServerAliveInterval 30
  ServerAliveCountMax 3
  ExitOnForwardFailure yes
  LocalForward 3307 127.0.0.1:3306

В этом случае команда создания туннеля будет проще:

$ ssh remote-forward-ssh-server

Поскольку при создании туннеля не планируется выполнять команды на виртуальной машине ssh-server, можно добавить опцию

$ ssh -N remote-forward-ssh-server

Но в этом случае терминал у нас зависнет, т.к. будет ожидать окончания выполнения этой команды. И для дальнейшей работы нам потребуется еще один терминал. Но мы можем запустить эту команду в фоновом режиме:

$ ssh -N remote-forward-ssh-server &
[1] 3949

Чтобы завершить фоновый процесс, надо переместить его на передний план, а потом завершить с помощью Ctrl+C:

$ fg 1
ssh -N remote-forward-ssh-server
^C

Автоматическое восстанавление туннеля

Утилита autossh предназначена для мониторинга соединений ssh и их автоматического восстановления в случае разрыва. Она уже входит в репозитории Ubuntu, поэтому устанавливаем ее на виртуальную машину web-server:

$ sudo apt install autossh
$ autossh
usage: autossh [-V] [-M monitor_port[:echo_port]] [-f] [SSH_OPTIONS]

    -M specifies monitor port. Overrides the environment
       variable AUTOSSH_PORT. 0 turns monitoring loop off.
       Alternatively, a port for an echo service on the remote
       machine may be specified. (Normally port 7.)
    -f run in background (autossh handles this, and does not
       pass it to ssh.)
    -V print autossh version and exit.

Environment variables are:
    AUTOSSH_GATETIME    - how long must an ssh session be established
                          before we decide it really was established
                          (in seconds). Default is 30 seconds; use of -f
                          flag sets this to 0.
    AUTOSSH_LOGFILE     - file to log to (default is to use the syslog
                          facility)
    AUTOSSH_LOGLEVEL    - level of log verbosity
    AUTOSSH_MAXLIFETIME - set the maximum time to live (seconds)
    AUTOSSH_MAXSTART    - max times to restart (default is no limit)
    AUTOSSH_MESSAGE     - message to append to echo string (max 64 bytes)
    AUTOSSH_PATH        - path to ssh if not default
    AUTOSSH_PIDFILE     - write pid to this file
    AUTOSSH_POLL        - how often to check the connection (seconds)
    AUTOSSH_FIRST_POLL  - time before first connection check (seconds)
    AUTOSSH_PORT        - port to use for monitor connection
    AUTOSSH_DEBUG       - turn logging to maximum verbosity and log to
                          stderr

Команда создания туннеля на виртуальной машине web-server:

$ autossh -M 0 -N -p 2222 -o "TCPKeepAlive no" -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
> -o "ExitOnForwardFailure yes" -R 3306:127.0.0.1:3306 evgeniy@192.168.110.8
$ autossh -M 0 -N remote-forward-ssh-server
Для autossh обязательна опция -M, которая задает порт для мониторинга соединения. Но ssh-клиент может и сам это делать (это опции ServerAliveInterval и ServerAliveCountMax). Так что опцию -M будем всегда отключать.

Чтобы запустить autossh в фоновом режиме, добавляем опцию -f:

$ autossh -M 0 -f -N -p 2222 -o "TCPKeepAlive no" -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
> -o "ExitOnForwardFailure yes" -R 3306:127.0.0.1:3306 evgeniy@192.168.110.8
$ autossh -M 0 -f -N remote-forward-ssh-server
Здесь опции -M и -f относятся к autossh, а все остальные передаются ssh.

Проверим, что туннель работает, воспользовавшись командой ps:

$ ps -f -C autossh
UID        PID  PPID  C  STIME  TTY          TIME  CMD
evgeniy   4000  3210  0  12:26  ?        00:00:00  /usr/lib/autossh/autossh -M 0 -N remote-forward-ssh-server

Чтобы завершить процесс, используем команду pkill:

$ pkill autossh

Проверяем, как работает autossh

Во второй части мы решали две задачи:

  1. Пробросить ssh-туннель от TKMCOMP до web-server через промежуточный ssh-server, чтобы иметь возможность подключаться с физической машины TKMCOMP к серверу БД на виртуальной машине web-server
  2. Пробросить ssh-туннель от web-server до TKMCOMP через промежуточный ssh-server, чтобы иметь возможность подключаться с виртуальной машины web-server к серверу БД на физической машине TKMCOMP

Мы сейчас посмотрим, как работает autossh, пробрасывая туннель от web-server до ssh-server (правая половина первого рисунка). Для проверки того, что туннель работает, установим на виртуальную машину ssh-server клиент БД MySQL:

$ sudo apt install mysql-client

Теперь с виртуальной машины web-server выполним команду создания туннеля:

$ autossh -M 0 -N remote-forward-ssh-server

А с виртуальной машины ssh-server соединяемся с сервером БД MySQL:

$ mysql -uroot -pqwerty --protocol=TCP

Соединение прошло успешно. Теперь выключим сетевой интерфейс на виртуальной машине ssh-server:

$ sudo ip link set dev enp0s3 down

Удостоверимся, что подключиться к серверу БД MySQL теперь нельзя:

$ mysql -uroot -pqwerty --protocol=TCP
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (111)

И посмотрим, как отреагирует утилита autossh на машине web-server:

$ autossh -M 0 -N remote-forward-ssh-server
Timeout, server 192.168.110.8 not responding. # прошло 90 секунд, сервер не отвечает
ssh: connect to host 192.168.110.8 port 2222: No route to host # попытка соединения с сервером
ssh: connect to host 192.168.110.8 port 2222: No route to host # попытка соединения с сервером
ssh: connect to host 192.168.110.8 port 2222: No route to host # попытка соединения с сервером

При включении сетевого интерфейса на виртуальной машине ssh-server:

$ sudo ip link set dev enp0s3 up

Туннель будет восстановлен. Это можно проверить, если выполнить команду на ssh-server:

$ mysql -uroot -pqwerty --protocol=TCP
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.28-0ubuntu0.18.04.4 (Ubuntu)
..........

Если возникли какие-то проблемы с autossh, можно запустить утилиту в режиме отладки:

$ AUTOSSH_DEBUG=1 autossh -M 0 -N remote-forward-ssh-server
autossh[2744]: port set to 0, monitoring disabled # мы отключили мониторинг
autossh[2744]: checking for grace period, tries = 0
autossh[2744]: starting ssh (count 1) # запуск ssh (попытка 1)
autossh[2744]: ssh child pid is 2747
autossh[2744]: check on child 2747
autossh[2744]: set alarm for 600 secs
autossh[2747]: execing /usr/bin/ssh
Timeout, server 192.168.110.8 not responding.
autossh[2744]: check on child 2747
autossh[2744]: ssh exited with error status 255; restarting ssh
autossh[2744]: expired child, returning 1
autossh[2744]: checking for grace period, tries = 1
autossh[2744]: starting ssh (count 2) # запуск ssh (попытка 2)
autossh[2744]: ssh child pid is 2754
autossh[2744]: check on child 2754
autossh[2744]: set alarm for 559 secs
autossh[2754]: execing /usr/bin/ssh
ssh: connect to host 192.168.110.8 port 2222: No route to host
autossh[2744]: check on child 2754
autossh[2744]: ssh exited with error status 255; restarting ssh
autossh[2744]: expired child, returning 1
autossh[2744]: checking for grace period, tries = 2
autossh[2744]: starting ssh (count 3) # запуск ssh (попытка 3)
autossh[2744]: ssh child pid is 2755
autossh[2744]: check on child 2755
autossh[2744]: set alarm for 524 secs
autossh[2755]: execing /usr/bin/ssh
ssh: connect to host 192.168.110.8 port 2222: No route to host
autossh[2744]: check on child 2755
autossh[2744]: ssh exited with error status 255; restarting ssh
autossh[2744]: expired child, returning 1
autossh[2744]: checking for grace period, tries = 3
autossh[2744]: starting ssh (count 4) # запуск ssh (попытка 4)
autossh[2744]: ssh child pid is 2756
autossh[2744]: check on child 2756
autossh[2744]: set alarm for 521 secs
autossh[2756]: execing /usr/bin/ssh

Поиск: CLI • Linux • Ubuntu • SSH • Виртуальная машина • Команда • Конфигурация • Настройка • Сервер • Туннель

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.