☰ Оглавление

Если вы не всё понимаете на этой странице, то рекомендую сперва прочитать, как настроить простейшие вещи в ssh.

Задача

У меня есть около десяти машин (серверов и рабочих станций), на которые мне нужен оперативный доступ. При этом, только к двум возможен доступ по ssh. Остальные находятся за NAT, или закрыты firewall-ами, или не имеют постоянных IP-адресов… Одним словом, — тяжко. Задача: обеспечить к ним доступ.

Обеспечение доступа

Общая идея

Мы подними с «недоступных» машин ssh-соединения на «доступные». Поверх этих соединений мы пробросим реверс-туннели, по которым можно будет попасть на «недоступные» машины.

Создаём пользователя

Авторизация у нас, конечно, будет по ключу (подробнее про авторизацию по ключу). Больше того, так как туннель должен подниматься автоматически, мы не можем закрыть ключ паролем. То есть, ключ будет не очень-то защищённым.

Поэтому, по этому ключу мы будем пускать только определённого пользователя, не обладающего большими правами.

Создадим такого пользователя:

useradd -c 'For ssh-tunneling only' -g nobody -m -N -s /home/t/bin/fake-shell t

В файл /home/t/bin/fake-shell вы можете написать что угодно, от грубых предупреждений для тех, кто пытается вас ломать, до чего-нибудь полезного.

Конечно, речь идёт о пользователе на «доступной» машине.

Настраиваем sshd для нашего пользователя

Создаём индивидуальную секцию в локальном /etc/ssh/sshd_config:

Match User t
        X11Forwarding no
#       AllowTcpForwarding no
        PermitTTY no
        ForceCommand /home/t/bin/fake-shell

Чтобы не залипали туннели, важно добавить в /etc/ssh/sshd_config инструкции

ClientAliveCountMax 2
ClientAliveInterval 10

Без них будет наблюдаться такая проблема: если клиент успешно подключился и поднял туннель, а потом молча отвалился (скажем, у него изменился IP), то при повторном подключении он не сможет снова поднять туннель, так как сервер уже поднял туннель для мёртвого клиента и сервер не может определить, что тот клиент умер (так как не пытается это определить).

Этими опциями мы как раз заставляем сервер проверять, жив ли клиент.

Не забываем о полезных опциях:

PasswordAuthentication no
PermitRootLogin no
# по настроениею
AllowUsers t

Добавляйте их с осторожностью и только, если вы понимаете, что делаете.

На удалённой, «недоступной», машине настраиваем подключение

В ~/.ssh/config прописываем что-то вроде:

Host tunn
  User t
  HostName michurin.net
  IdentityFile ~/.ssh/id_rsa_open
  ServerAliveInterval 10
  ServerAliveCountMax 2
  ExitOnForwardFailure yes
  VerifyHostKeyDNS no
  StrictHostKeyChecking no
  RequestTTY no
  RemoteForward 2080 localhost:22

Здесь michurin.net — это на «доступный сервер». Туннель будет подниматься с порта 2080 на «доступном» сервере и ходить на localhost:22 на «недоступном».

Вам необходимо настроить доступ по ключу ~/.ssh/id_rsa_open, не закрытому паролем. Если доступ работает, то ставим в cron автоподнималку:

*/5 * * * * ssh -N tunn >>~/cron-ssh.log 2>&1

Если не использовать crontab, то можно как-то так:

nohub sh -c 'while : ; do date; ssh -N rnt; sleep 60; done'

Но это уже как кому нравится.

Кстати, на эту машину вы будете ходить через туннель на локальный интерфейс. Если другого доступа не предусматриваеться, то в настройках sshd можно указать

ListenAddress 127.0.0.1

Это добавит безопасности системе. А если ваша машина действительно расположена за NAT-ами и firewall-ами, то, очень может быть, что слушать на других интерфейсах вам и не нужно.

Настраиваем доступ с «доступной» машины на «недоступную»

Для вашего любимого пользователя на «доступной» машине (где вы завели пользователя t), добавляем в ~/.ssh/config:

Host home
    User me
    HostName localhost
    Port 2080

Теперь вы можете на «доступной» машине сказать:

ssh home

и попасть на «недоступную». Мы добились, чего хотели.

Дальше можно настроить удобный прямые туннели с «недоступной» на «недоступную», как вам надо. Главное, возможность обеспечена.

Настройка systemd

Вы можете настроить запуск туннеля через systemd

Создаёте файл, например /etc/systemd/system/tunnel.service, примерно такого содержания:

[Unit]
Description=Reverse tunnel
After=network.target

[Service]
Type=simple
User=t
Group=users
ExecStart=/usr/bin/ssh -N tunn
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

Перечитываете настройки systemd, проверяете, что запускается, запускаете навсегда:

systemctl daemon-reload
systemctl -l status tunnel
systemctl start tunnel
systemctl -l status tunnel
systemctl enable tunnel