Expertus metuit
Эффективная работа с SSH
Опубликовано 2024-04-06 в 22:59

Ранее я выборочно писал о разных полезностях в SSH, а в этот раз решил написать вообще обо всём, чем я в SSH пользуюсь. Будет в меру объяснений и много примеров. По сути здесь весь мой опыт использования SSH и всё написанное здесь я лично использовал. Соответственно, если чем-то не пользовался (например, tun-устройствами), то об этом не пишу.

──────────────────

──────────────────

Протокол SSH (Secure Shell Protocol) сам по себе очень мощный и расширяемый, среди его возможностей:

  • безопасный защищённый доступ (login) к удалённой машине в режиме терминала и bash/zsh/etc-сессии;
  • защищённая передача файлов между компьютерами (SFTP/SCP);
  • защищённая передача сетевого трафика между машинами — ssh-туннели.

SSH построен по слоёной (layered) архитектуре, подробности можно прочитать в википедии, например, нас же интересует только слой соединений, именно в нём реализуются прикладные возможности SSH. Этот слой описан в RFC 4254.

Внутри одного установленного SSH-соединения для каждого из прикладных сервисов предусмотрены так называемые каналы (channels). Все каналы работают параллельно, что позволяет одновременно скачивать и закачивать файлы, перенаправлять сетевой трафик и работать в нескольких интерактивных терминалах.

В стандарте RFC 4254 определено много разных типов каналов, которые можно условно сгруппировать в такие категории:

  • Запуск команд
  • Интерактивная сессия в псевдо-терминале
  • Перенаправление/проброс/туннелирование сетевого трафика
  • Перенаправление X11

Чаще всего SSH используется для интерактивных сессий bash/zsh/etc, для которых выделяется псевдо-терминал в котором и происходит вся работа в текстовом командно-терминальном режиме.

❈ ❈ ❈

Безопасность SSH-соединений обеспечивается криптографическими алгоритмами в транспортном протоколе и включает в себя аутентификацию и шифрование трафика. Полностью всё это описано в RFC 4253 и в этой статье я в детали углубляться не буду.

❈ ❈ ❈

Главной и по сути эталонной реализацией ssh является проект OpenSSH, в рамках которого созданы серверные (sshd, sftp-server, ssh-agent) и клиентские приложения (ssh, scp, sftp), а также набор сопровождающих инструментов (ssh-keygen и другие). Существуют и другие (в том числе коммерческие) реализации, но в этой статье только про openssh как на стороне сервера, так и на стороне клиента.

Главный наш инструмент — программа ssh из клиентской части openssh. В разных операционных системах она либо уже установлена (например, в macOS), либо устанавливается из системного репозитория (как почти во всех вариантах Linux), либо ставится как-то ещё (как в Windows, где с какой-то из версий Windows 10 ssh устанавливается автоматически).

Важно отметить, что некоторые из описанных ниже возможностей могут отсутствовать в вашей версии openssh. Это может быть старая версия, или же модифицированная вендором операционной системы. Я предполагаю, что вы используете версию openssh выпуска 2020 года или позднее.

Пара слов о криптографии

В работе SSH активно используются криптографические алгоритмы. Самым понятным примером являются симметричные криптосистемы, в них для шифрования и дешифрования используется одинаковый — секретный (secret) — ключ. То есть обе стороны коммуникации должны у себя иметь одинаковые ключи, чтобы обмениваться зашифрованными сообщениями.

Если упоминаются открытые (public) и закрытые (private) ключи, то речь идёт об асимметричной криптосистеме. В этой системе для криптографических операций используются разные ключи. Открытые ключи являются публичными и общедоступными, закрытые должны храниться в секрете.

Самым известным примером использования асимметричных алгоритмов является электронная (цифровая) подпись: при помощи закрытого ключа генерируется электронная подпись — специальное сообщение, которое может быть проверено при помощи открытого ключа. Электронная подпись позволяет удостоверить, что её создатель действительно обладает доступом до закрытого ключа.

Во время работы криптографических защищённых соединенией используются оба типа криптосистем. Обычно асимметричные алгоритмы используются на этапе установки соединения, чтобы стороны могли аутентифицировать друг друга и безопасно сгенерировать одинаковые сессионные секретные ключи для последующей работы соединения.

Асимметричные алгоритмы для непосредственно шифрования и дешифрования обычно не используются, так как их основное предназначение — это электронная подпись.

Подключение и аутентификация

Любое использование SSH как клиента включает в себя:

  • установку соединения с криптографической проверкой доверия серверу;
  • аутентификацию клиента;
  • создание одного или нескольких каналов для собственно задач соединения: терминал, запуск команд, проброс сетевого трафика и так далее.

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

% ssh github.com
The authenticity of host 'github.com (140.82.121.3)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Вам выводится не весь открытый ключ, а его отпечаток (fingerprint), то есть хеш, в данном случае — sha256. Если вы точно уверены, что это корректный отпечаток, то набираете yes и локальный клиент запоминает открытый ключ для данного сервера в текстовом файле ~/.ssh/known_hosts. При последующих соединениях этот файл проверяется и если для этого хоста ключ совпадает, предупреждение не выводится и соединение считается доверенным. В этот момент оно уже криптографически защищено, как раз в том числе этим серверным ключом, открытую часть которого вы проверяли и подтверждали.

Далее следует аутентификация, при которой уже сервер должен со своей стороны проверить, кто к нему подключается. Два самых распространённых способа: по логину+паролю и по ключу. Подключение по ключу считается более надёжным, так как обеспечивает дополнительный слой защиты, так как, в отличие от пароля, закрытая часть ключа не передаётся по сети вообще. Об использовании ключей ниже будет отдельный раздел.

Тут важно отметить, что при аутентификации так называемый логин (то есть имя пользователя, login name) передаётся всегда, причём сразу после установки соединения и серверу это значение необходимо, чтобы начать аутентификацию (например, найти запись об этом пользователе во внутренней системе аутентификации). Даже если в команде не указываете никакой логин, клиент всё равно отправляет какое-то значение по умолчанию, обычно это ваш логин на локальной машине.

После аутентификации защищённое соединение полностью установлено и можно начинать работу.

Конфигурация на стороне клиента

Конфигурация ssh-клиента формируется следующим образом (в порядке приоритетности, какое значение найдётся первым, такое и будет использовано):

  • опции командной строки программы;
  • опции, указанные в пользовательском конфиге ssh;
  • опции, указанные в системном конфиге ssh.

Опции пользовательского конфига ищутся по умолчанию в файле ~/.ssh/config, но этот путь можно изменить через аргумент -F /path/to/custom/file.

Местоположение системного файла конфигурации зависит от операционной системы и параметров компиляции openssh. Например, в линуксе это обычно путь /etc/ssh/ssh_config, для системного клиента ssh в макоси путь такой же, а для клиента из brew — /opt/homebrew/etc/ssh/ssh_config.

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

Файлы конфигурации — это чрезвычайно мощный инструмент, позволяющий значительно упростить и улучшить работу с консольным клиентом ssh. Самый распространённый сценарий — это разные параметры для разных серверов, например, где-то нужно пробросить X11, где-то не нужно, для разных серверов можно указать разные логины, пути к ssh-ключам и так далее.

Каждая строчка файла определяет либо опцию, либо критерий их группировки. Критериев два, они задаются директивами Host и Match. Каждый из них начинает блок опций, которые используются совместно, когда выполняется указанное условие. Блок продолжается до следующего вхождения ключевого слова Host или Match, либо до конца файла, если больше таких вхождений нет.

Например, такой конфиг определяет опции для двух разных адресов ssh-серверов github.com и regolit.com:

Host github.com
    User git
    ForwardX11 no

Host regolit.com
    User sergei

Соответственно при запуске команды ssh regolit.com будет использоваться логин sergei.

Отступ перед ключевыми словами для конкретных опций конфигурации нужен только для читаемости, никакой функциональной роли он не играет. Также не играет роли регистр символов для конкретных опций, например, ForwardX11 и forwardx11 задают одну и ту же опцию.

Директива Match позволяет формировать более сложные условия применимости группы опций конфигурации.

Все доступные опции конфигурации клиентского приложения описаны в документации man ssh_config.

Любую опцию конфигурации можно указать непосредственно при вызове команды ssh в аргументе -o, в этом случае она переопределит любое значение этой опции из всех файлов конфигурации. Таких аргументов может быть несколько. Пример использования:

% ssh -o Compression=no -o PasswordAuthentication=no regolit.com

──────────────────

Если при подключении через команду ssh указать аргумент -G, то вместо подключения будет выведен список значений всех опций конфигурации, полученных через аргументы команды или опции всех файлов конфигурации.

Конфигурация на стороне сервера

Расположение файлов конфигурации сервера openssh (он обычно называется sshd) зависит от конкретной операционной системы. В ubuntu и debian это, например, /etc/ssh/sshd_config плюс файлы в каталоге /etc/ssh/sshd_config.d/. Опций конфигурации много и полный их список можно посмотреть в документации man sshd_config, в статье я буду их указывать при необходимости, но в целом больше будут писать о клиентской стороне вопроса.

В серверных файлах конфигурации тоже можно использовать директивы Host и Match.

Некоторые опции конфигурации можно также указывать в файле ~/.ssh/authorized_keys, они используются при подключении с использованием конкретного ключа для конкретного пользователя. Об этом подробнее я расскажу ниже в разделе о безопасном создании ssh-туннеля.

Использование SSH-ключей для аутентификации

Криптоключи используются для аутентификации следующим образом:

  • пользователь генерирует пару из открытого и закрытого ключей на клиентской стороне;
  • на стороне сервера открытая часть ключа указывается в нужном месте (либо через файл, либо через настройки какого-нибудь сервиса);
  • при подключении в SSH-клиенте указывается, какой именно ключ нужно использовать.

С технической точки зрения в протоколе SSH используется механизм challenge-response, который в упрощённом виде выглядит так:

  • сервер генерирует случайную строку и шифрует её клиентским открытым ключом;
  • получившийся challenge отправляется клиенту;
  • клиент имеющимся у него закрытым ключом расшифровывает challenge и отправляет ответ серверу;
  • сервер проверяет ответ (response) и если он совпадает с оригинальной строкой, аутентифицирует пользователя.

Для ключей аутентификации также используется термин identity.

Ключевые пары генерируются командой ssh-keygen, у неё много аргументов и их описывать не буду, а приведу только типичные примеры использования. Результатом выполнения обычно являются два файла: закрытый ключ и его открытая часть с именем, оканчивающимся на .pub.

При создании ключа можно указать пароль, которым этот ключ будет зашифрован. При использовании нужно будет вводить этот пароль. Если пароль не указать, ключ не будет зашифрован.

Сгенерируем ключевую пару для доступа к github:

% ssh-keygen -f ~/.ssh/id_GITHUB
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sergei/.ssh/id_GITHUB
Your public key has been saved in /home/sergei/.ssh/id_GITHUB.pub
The key fingerprint is:
SHA256:PsCz257hmrrpuDAoMwnpGyjmsHyXoa5icYypsoH3VN4 [email protected]
The key's randomart image is:
+--[ED25519 256]--+
|                 |
|                 |
|                 |
| .   .           |
|o +   = S        |
|*= o + *         |
|/++ o = E        |
|@Xo* + = +       |
|***+Bo+o=        |
+----[SHA256]-----+

В результате было создано два файла: собственно закрытый ключ в /home/sergei/.ssh/id_GITHUB и его открытая часть /home/sergei/.ssh/id_GITHUB.pub. При генерации использовался алгоритм по умолчанию — ed25519.

Чтобы использовать этот ключ для работы с github, нужно в web-интерфейсе github загрузить открытую часть из файла id_GITHUB.pub, а при подключении указывать ключ id_GITHUB в файле конфигурации следующим образом:

Host github.com
    User sigsergv
    IdentityFile /home/sergei/.ssh/id_GITHUB

Теперь все обращения к github.com через ssh будут использовать логин sigsergv и закрытый ключ из файла /home/sergei/.ssh/id_GITHUB.

В современных версиях openssh при генерации ключа по умолчанию используется алгоритм ed25519. Ранее использовался RSA, однако ed25519 считается безопаснее. Вы можете по-прежнему использовать rsa, для этого при вызове ssh-keygen нужно указать аргумент -t rsa.

──────────────────

Чтобы сконфигурировать сервер для использования SSH-ключа, его открытую часть нужно сохранить в файл ~/.ssh/authorized_keys на стороне сервера в каталоге соответствующего пользователя. В этом файле находятся открытые ключи, по одному в каждой строчке. При подключении SSH-сервер проверяет этот файл для указанного пользователя и разрешает доступ, если клиент может подтвердить, что у него есть закрытая часть указанного там ключа.

Переиспользование одного соединения

SSH позволяет использовать одно подключение для нескольких одновременно работающих сессий. Работает это так:

  • устанавливается мастер-соединение, в котором создаётся специальный локальный файл-сокет;
  • последующие соединения до этого хоста делаются через файл-сокет и перенаправляются в мастер-соединение.

Внешне это выглядит как подключение к серверу без аутентификации: можно открыть терминал, можно передавать данные через scp, rsync и так далее. И всё это без повторной аутентификации.

Чтобы всё работало корректно, необходимо в пользовательском конфиге указать шаблон построения имени файла-сокета:

Host *
    ControlPath ~/.ssh/ctl_socket_%h_%n_%p_%r

Мы используем такой формат, чтобы создать максимально уникальное, но при этом воспроизводимое имя для сокета, чтобы оно не пересекалось с другими похожими соединениями. Сам файл создаём в локальном пользовательском каталоге ~/.ssh, чтобы не пересекаться ещё и с другими пользователями.

Теперь для старта мастер-подключения нужно к команде ssh добавить аргумент -M:

% ssh -M server.com

После успешной аутентификации будет создан файл-сокет с именем типа ~/.ssh/ctl_socket_192.168.8.3_server.com_22_sergei. А чтобы переиспользовать соединение, нужно просто выполнить команду ssh server.com, в результате чего вы сразу подключитесь без ввода пароля или SSH-ключа.

Обратите внимание, что мастер-подключение будет создано только если указать аргумент -M. Это сделано специально, так как эта функциональность потенциально опасная и её не нужно разрешать автоматически для всех новых соединение или узлов.

Но при желании вы можете в файле конфигурации указать параметр ControlMaster (или глобально, или для конкретного хоста). Например, ControlMaster autoask при подключении попытается подключиться к существующему соединению, а если это не получится, то спросит у пользователя разрешение на создание нового.

Для ещё бо́льшей безопасности можно опцию ControlPath указывать не для всех хостов, а только для некоторых.

SSH Bastion

SSH Bastion, SSH-бастион или узел-бастион — это специальный компьютер в сетевой инфраструктуре, который стоит на границе защищённой сети и доступен снаружи по SSH. Единственный способ подключиться к защищённой сети снаружи — это сначала подсоединиться к бастиону через SSH и уже оттуда (тоже по SSH, например) зайти на нужную машину в защищённой сети.

Существует несколько сценариев использования бастиона (подробнее они будут описаны ниже):

  • proxy jump — соединение до SSH-сервера, находящегося за бастионом;
  • туннелирование соединения — на локальной рабочей станции открывается сетевой порт, который через SSH-соединение пробрасывается на узел за бастионом;
  • проксирование — на локальной рабочей станции открывается SOCKS-порт, через который можно пробрасывать любой трафик, используя его как SOCKS-прокси;
  • подключение через интерактивную сессию — непосредственный логин на сервер бастиона с последующим подключением оттуда до нужного сервера.

Proxy Jump

Допустим, у вас есть сервер server2.com, но доступ к нему с внешнего интернета закрыт. Однако есть доступ до сервера server1.com, с которого уже виден server2.com. Тогда вы можете одной командой подключиться сразу к серверу server2.com через server1.com, используя аргумент -J:

% ssh -J server1.com [email protected]

В результате такой команды вы попадёте сразу на узел server2.com. И server1.com тут выступает в роли промежуточного джамп-сервера.

Если вы регулярно подключаетесь на определённые узлы через джамп-сервер, то можете сконфигурировать автоматическое его использование. Например, если группа серверов с адресами вида 10.1.2.* находится в закрытом периметре, доступном только через сервер bastion.example.com, то вы можете добавить такую секцию в файл конфигурации ~/.ssh/config:

Host 10.1.2.*
    ProxyJump bastion.example.com

Теперь достаточно набрать команду вида ssh [email protected], чтобы подключиться к серверу 10.1.2.39 через указанный в конфиге бастион.

Туннелирование сетевых соединений

Основной сценарий использования SSH-туннелей — это установка соединения до сетевых локаций, доступных только через SSH. Например:

  • доступ до сервера базы данных в закрытом контуре;
  • доступ до подсети в закрытом контуре;
  • доступ из закрытого контура до сервиса на локальной машине.

Перенаправление соединения с локальной машины на порт машины в закрытом контуре

Ситуация: вам необходимо подключиться к порту 3306 сервера базы данных с адресом 10.3.8.4, недоступного напрямую с локальной машины (с адресом 192.168.19.3), но доступного с ssh-сервера (с адресом 172.30.49.2), к которому вы можете подключиться.

ssh tunnels

В такой ситуации вы можете запустить такое подключение:

% ssh -L 9999:10.3.8.4:3306 [email protected]

После подключения вы сможете подключиться к порту 9999 на локальной машине и это соединение будет проброшено через SSH-сервер 172.30.49.2 до порта 3306 сервера с адресом 10.3.8.4.

По умолчанию такое соединение создаёт псевдо-терминал, позволяющий запускать команды. Если вам нужен только туннель, то лучше остальные SSH-каналы не использовать, это делается аргументами -TN (-T — не создавать терминал, -N — не выполнять команды при подключении):

% ssh -TN -L 9999:10.3.8.4:3306 [email protected]

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

Ситуация: приложению из закрытого контура необходимо подключиться к сервису, который недоступен изнутри, но доступен с вашей рабочей станции.

Пример: есть внешний сервер example.com, с которого нужно скачать файл. Процесс скачивания требует аутентификации, которую может провести только персона из закрытого контура.

ssh tunnels

С машины 192.168.19.3 (которая имеет прямой доступ наружу) устанавливаем такое соединение до граничного узла 172.30.49.2, который также смотрит в закрытый контур через адаптер с адресом 10.3.1.99.

% ssh -R 10.3.1.99:3333:example.com:443 [email protected]

В результате пользователь машины в закрытом контуре 10.3.8.4 может в браузере набрать адрес http://10.3.1.99:3333, который через туннель будет перенаправлен на внешний сервер https://example.com

И то же самое без создания терминала:

% ssh -TN -R 10.3.1.99:3333:example.com:443 [email protected]

Перенаправление сетевого трафика через SOCKS-прокси

В этом режиме работы после установки соединения с внешним сервером на локальной машине открывается сетевой порт, который можно использовать как SOCKS-прокси в других приложениях.

% ssh -D localhost:8999 server.example.com

После установки соединения такой командой SSH-клиент начинает выполнять роль SOCKS-прокси вы можете указывать адрес localhost:8999 как SOCKS-прокси в других локальных приложениях.

SSH agent

SSH agent — это специальная программа, менеджер SSH-ключей. Он загружает ключи из файлов (например, ~/.ssh/id_GITHUB) и хранит их в памяти, работая в фоновом режиме. Когда SSH-клиенту требуется закрытый ключ, он обращается к агенту, а не берёт ключ из файла. После загрузки ключа в агент оригинальный ключ можно удалить, но тогда в случае недоступности агента доступа к ключу больше не будет.

Штатных способов извлечь закрытый ключ из агента не существует. Это можно сделать через дамп памяти, но штатно в самом агенте такой функциональности нет. Когда SSH-клиент обращается к агенту, он на самом деле просит его выполнить определённую криптографическую операция, например, подписать блок данных или проверить подпись. При этом закрытый ключ границы агента не покидает.

В составе openssh уже есть реализация SSH-агента, однако я рекомендую его заменить на агента из gnupg, этот процесс описан в статье Меняем ssh-agent на gpg-agent. Кроме того, менеджер паролей KeePassXC умеет интегрироваться с SSH-агентом и предоставлять ему ключи из своего хранилища.

SSH-агент позволяет сэкономить время и не набирать каждый раз пароль к закрытому ключу при установке соединения.

Ещё SSH-агент умеет «пробрасывать» себя через SSH-соединение на другой сервер и позволяет пользоваться ключами локального агента на другом сервере.

Как работает ssh-агент

Всё общение с ssh-агентом происходит по специальному протоколу через контрольный сокет. Путь к сокету содержится в переменной окружения SSH_AUTH_SOCK, обычно там что-то типа /run/user/1000/gnupg/S.gpg-agent.ssh. Этот сокет поднимается при старте агента во время старта системы, соответственно значение переменной окружения выставляется в скриптах инициализации переменных окружения. Например, в Debian инициализация переменной SSH_AUTH_SOCK для gpg-agent происходит в стартовом скрипте /etc/X11/Xsession.d/90gpg-agent.

Когда SSH-клиент (например, программа ssh) пытается аутентифицироваться при подключении, он сначала запрашивает у агента доступные открытые ключи и только затем пытается прочитать ключи из файлов в каталоге ~/.ssh. Затем он последовательно предлагает их серверу для аутентификации.

SSH агент никогда не возвращает закрытый ключ, вместо этого он сам выполняет операцию подписывания блока данных, когда клиент запрашивает. Именно через подписывание данных происходит проверка, что клиент обладает закрытым компонентом ключа, открытая часть которого находится на стороне SSH-сервера.

Управление ключами в агенте

В составе пакетов openssh есть утилита ssh-add для работы с агентом по этому протоколу. Она используется для базовых операций: добавление ключа, удаление и так далее. Эта команда работает по протоколу SSH agent, поэтому её можно использовать независимо от того, какой именно тип SSH-агента запущен (оригинальный из openssh или сторонний от gnupg, например).

Добавление нового ключа делается такой командой (в качестве аргумента передаётся путь до закрытого ключа):

% ssh-add /home/sergei/.ssh/id_GITHUB

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

Доступные в агенте ключи можно посмотреть командой, она выдаёт отпечатки (fingerprints):

% ssh-add -l

Для просмотра открытых ключей используется команда (она выдаёт открытые ключи в формате файла authorized_keys):

% ssh-add -L

Перенаправление агента в SSH-сессии

Одна из полезных фич SSH-агента — это перенаправление контрольного сокета на другой SSH-сервер. Это позволяет использовать ключи локального агента на внешнем сервере. Например, вы можете подключиться с рабочей станции сначала на сервер server1.com, а уже из его shell-сессии через команду ssh подключиться к серверу server2.com, используя ключ с локальной рабочей станции.

Чтобы подключиться с перенаправлением агента, нужно использовать аргумент -A, например, так:

% ssh -A server1.com

Теперь в сессии на server1.com можно набрать команду ssh server2.com и на локальный ssh-агент придёт запрос ключа, всё будет выглядеть так, как будто на стороне server1.com хранится ключ аутентификации.

Включить перенаправление агента можно и через файлы конфигурации, как глобально, так и для отдельных узлов. Например, так:

Host server1.com
    ForwardAgent yes

Обратите внимание, что перенаправление агента — достаточно опасная операция, так как на сервере создаётся контрольный файловый сокет, доступ до которого можно получить не только из этой SSH-сессии. Чтобы частично себя обезопасить, можно включить в SSH-агенте подтверждение каждого использования ключа, такое позволяет делать, например, gpg-agent.

Нельзя включать перенаправление агента для всех узлов. Да и для конкретных это тоже желательно не делать, а при необходимости указывать аргумент -A при подключении.

Вместо перенаправления агента лучше использовать Proxy Jump, описанный выше — это более безопасно.

Перенаправление X11

Если у вас на локальной рабочей станции linux (или запущен локальный X11-сервер в windows или macos), то вы можете через SSH перенаправлять протокол X11 и локально показывать окна запущенных на внешнем сервере десктопных приложений.

В целом такой подход потребляет довольно много трафика и нормально работает только на широких каналах.

Чтобы включить перенаправление X11, нужно добавить аргумент -X. После этого в запущенной сессии вы сможете запустить десктопное приложение и оно откроется у вас на локальном десктопе.

У такого режима работы есть ряд проблем с безопасностью, поэтому я не рекомендую им пользоваться и отключать его на стороне SSH-сервера.

Использование scp

Команда scp из состава openssh используется для безопасной передачи файлов через протокол SFTP (для современных серверов) или SCP (для старых серверов), работающий внутри стандартного SSH-соединения. scp расшифровывается как “secure cp” и работает примерно так же, как стандартная команда копирования файлов.

scp [ARGS] SOURCE TARGET

В качестве SOURCE и TARGET могут выступать локальные пути к файлам (каталогам) и пути к внешним серверам в формате HOST:PATH, USER@HOST:PATH, здесь PATH — это путь к файлу (каталогу) на внешнем сервере. В SOURCE и TARGET можно указывать пути к внешним сервера одновременно, в этом случае файл (каталог) будет скопирован с одного сервера на другой (через вашу рабочую станцию, где вы вызываете команду).

scp как и ssh использует опции из файлов конфигурации и опции, передаваемые через аргумент -o. Например, если у вас в файле конфигурации заданы все параметры подключения для узла server1, вам не нужно их указывать в команде scp:

Host server1
    Hostname 192.168.78.3
    User sergei
    IdentityFile ~/.ssh/id_rsa-CORP

И вызов команды scp для передачи файла может выглядеть так:

% scp server1:/etc/passwd ./local/path/

В современных версиях scp для передачи файлов по умолчанию используется протокол SFTP, однако если внешний сервер его не поддерживает, вы получите ошибку вида Write failed: Broken pipe. Чтобы передать файл по устаревшему протоколу SCP, нужно указать аргумент -O (это не нуль, а заглавная буква o).

% scp -O server2:/etc/passwd ./local/path/

Использование SSH другими сервисами

SSH как транспортный протокол используют некоторые популярные сервисы и приложения. Например, rsync или git.

Для всех таких соединений применяются настройки из файлов конфигурации. Например, если вы настроите доступ к корпоративному серверу git.corp.example.net через корпоративный ssh-бастион bastion.example.net в файле ~/.ssh/config:

Host git.corp.example.net
    ProxyJump bastion.example.net

То вы сможете работать с git-сервером git.corp.example.net так, как будто у вас есть прямой доступ до него — весь ssh-трафик будет туннелироваться через соединение до bastion.example.net прозрачным образом.

Обеспечение безопасности SSH сервера

Если сервер выступает в роли бастиона, то возможности его пользователей должны быть серьёзно ограничены.

Например, если бастион используется только для туннелирования трафика, можно запретить интерактивные сессии. Например, вот такой блок можно добавить в файл конфигурации сервера (/etc/ssh/sshd_config), чтобы ограничить права пользователю tunnel.

Match User tunnel
    PermitTTY no
    X11Forwarding no
    PermitTunnel no
    GatewayPorts no

    ForceCommand /usr/sbin/nologin

Подобного результата можно добиться также правкой файла ~/.ssh/authorized_keys, его формат позволяет указывать дополнительные опции для каждого открытого ключа. Например, вы можете в этом файле записать два разных ключа: один использовать для интерактивной сессии, а второй — только для туннелирования. Это позволяет использовать один аккаунт на сервере для разных операций.

Опции записываются в виде пар option_name=option_value, разделённых запятыми, эта строка записывается в начало строки перед нужным открытым ключом. Список опций отличается от стандартных опций конфигурации сервера и описан в man authorized_keys.

Вот как может выглядеть файл для двух ключей: первый без ограничений, а второй только для установки туннелированных сетевых соединений:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGRn+K08Qkqw7Jbbhh5rUifZxzPG6ZJpdt2FL+gNtZUM sigsergv@workstation

no-X11-forwarding,no-agent-forwarding,no-pty,command="/bin/true"  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCr/pNR1...AjUE= bastiontunnel

Очевидно, что если у пользователя есть доступ к интерактивной сессии, он сможет поправить файл ~/.ssh/authorized_keys и убрать из него все ограничения.

──────────────────

Ещё одна полезная опция в ~/.ssh/authorized_keys — expiry-time, она позволяет блокировать ключ по достижению указанной даты. Например, ключ можно сконфигурировать так, чтобы им нельзя было пользоваться после 00:00 1 января 2025 года по UTC:

expiry-time=202501010000Z,no-X11-forwarding,no-agent-forwarding,no-pty,command="/bin/true"  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCr/pNR1...AjUE= bastiontunnel

Что осталось за кадром

Некоторыми возможностями openssh я практически не пользуюсь, поэтому писать о них не стал:

  • tun-устройства для проброса низкоуровневого сетевого трафика;
  • использование директив Match в файлах конфигурации;
  • аппаратные токены для хранения ключей.

Также я не стал детально описывать конкретные сценарии, приёмы или особенности конфигурации, которыми я сам пользуюсь. Возможно, это будет в отдельной статье, где я расскажу подробно о сетевой инфраструктуре на базе SSH и как она позволяет оптимизировать работу программиста или другого ИТ-специалиста.

Комментарии

Текст комментария (допустимая разметка: *курсив*, **полужирная**, [ссылка](http://example.com) или <http://example.com>) Посетители-анонимы, обратите внимение, что более чем одна гиперссылка в тексте (включая оную из поля «веб-сайт») приведёт к блокировке комментария для модерации. Зайдите на сайта с использованием аккаунта на twitter, например, чтобы посылать комментарии без этого ограничения.
Имя (обязательно, 50 символов или меньше)
Опциональный email, на который получать ответы (не будет опубликован)
Веб-сайт
© 2006—2024 Sergey Stolyarov | Работает на pyrengine