Вопрос или проблема
Мне нужно получить доступ к некоторым серверам внутри NAT. Поскольку у меня есть публичный сервер, вот что я делаю:
У обоих A и B есть служба, которая выполняет команду: ssh -fnN -R 17000:localhost:22 [email protected] -i privateA
Единственное отличие – это порт. Для B он составляет 17001.
Это создает спящую связь от серверов внутри NAT к моему публичному серверу 24/7.
Теперь я могу подключиться в любое время к S и использовать команду: ssh -i privateS -p 17000 user@localhost
, чтобы подключиться к A.
Отлично. Это решает мою непосредственную проблему. Но проверяя способы сделать это, у меня был другой вариант, и я не смог найти способ фактически его использовать.
Главный недостаток этого метода заключается в том, чтобы быть уверенным, что вы знаете каждый удаленный порт сервера заранее и настраиваете каждый сервер на его использование, поскольку выбор порта происходил из команд в A и B, а не в S.
Если мы используем -R 0:localhost:22
в первых командах (в A и B), все работает так же, но удаленный порт будет случайным. И команда SSH даже сообщает номер порта, созданного в S. Но эта информация доступна только в A и B.
Из S я просто вижу два открытых порта в режиме прослушивания, но не знаю, какой использовать для доступа к A или B.
Представьте, что вместо 2 у меня 50 удаленных серверов.
Как я могу идентифицировать каждое SSH-соединение?
Моя первая попытка заключалась в использовании команд внутри моего файла authorized_keys и идентификации по используемому приватному файлу. Здесь я мог бы извлечь процесс SSH, а затем список портов под этим процессом.
Но, так как я использую -N
, команды вообще не выполняются. Какой метод я мог бы попробовать?
Каково использование команды, которая создает случайный порт на удаленной машине и не делится этой информацией с ней? Каково предполагаемое использование -R 0:host:22
?
Вновь, моя проблема решена, просто пытаюсь здесь научиться…
С точки зрения сервера нет разницы между тем, когда вы используете -R 17000:…
или -R 0:…
на клиенте. Некоторый порт выделяется. Машина сервера не заботится о том, был ли он выбран человеком-пользователем клиентской машины или каким-то алгоритмом.
Допустим, он был выбран человеком-пользователем клиентской машины, и этим пользователем являетесь вы. Тогда ваша ответственность заключается в том, чтобы передать номер, который вы выбрали (например, 17000
), будущим пользователям туннеля.
Если вы решите использовать -R 0:…
, то информирование будущих пользователей туннеля все равно остается вашей ответственностью, ничего не меняется в этом отношении. И вы узнаете номер во время выполнения (“команда SSH даже сообщает номер порта, созданного в S”).
Обратите внимание в общем, что будущие пользователи туннеля могут или не могут быть пользователями S. С помощью -R
вы можете указать удаленный (т.е. локальный для S) адрес привязки, это может быть внешний адрес; и если сервер настроен на разрешение этого (см. этот мой ответ), то будет возможно использовать туннель, подключаясь из вне S, без входа в S.
Таким образом в общем, хранение (или изучение) на S того, какой порт туннелируется куда, не решит проблему. Вы видите это как хорошую идею, потому что можете войти в S.
Либо вы (кто запускает ssh
на клиентах) используете статические номера, и тогда можете заранее информировать будущих пользователей туннелей (включая себя); либо вы используете -R 0:…
и берете на себя ответственность за информирование будущих пользователей туннелей (включая себя) не заранее.
Я понимаю, что каждый ssh -R 0:…
автоматизирован в вашем случае. Поэтому вам следует также автоматизировать процедуру информирования будущих пользователей туннеля. Вот как вы можете это сделать для информирования user
(возможно, себя) на S:
#!/bin/sh
# клиентская сторона, скажем, A
ssh -fNMS /path/to/socket [email protected]
port="$(ssh -S /path/to/socket -O forward -R 0:localhost:22 placeholder)"
echo "$port" | ssh -S /path/to/socket placeholder 'cat >A.port' # или B.port и т.д.
Это быстрый и грязный скрипт, он основан на этом другом моем ответе, где вы найдете некоторые объяснения деталей.
Ответ или решение
SSH (Secure Shell) представляет собой мощный инструмент для безопасного удаленного управления и передачи данных. Использование его функционала для доступа к серверам, находящимся за NAT (Network Address Translation), часто требует аккуратной конфигурации и понимания безопасности. В вашем случае, вы описали сценарий, в котором SSH перенаправляет порты, и используете опцию -R
для создания обратного SSH-туннеля. Давайте более подробно рассмотрим проблему идентификации порта, созданного с использованием случайного номерного порта.
Проблема идентификации портов
При использовании команды ssh -R 0:localhost:22
, SSH неявно выделяет случайный порт на сервере. Эта функция удобна, так как избавляет от необходимости заранее задавать порты для каждого сервера. Однако она порождает несколько вопросов, особенно когда вы имеете дело с множеством серверов: как идентифицировать, какой порт назначен как целевой для каждого из этих серверов?
Как работает -R 0:host:port
При использовании -R 0:host:port
, SSH серверу поручает выбрать свободный порт на своей стороне, который будет использоваться для туннелирования. Этот порт возвращается клиентскому приложению, но не передается автоматически для дальнейшего использования. Вам необходимо реализовать стратегию для передачи этой информации, чтобы другие клиенты (или вы сами) могли их использовать.
Варианты подхода к идентификации портов
-
Использование сокетов:
Вы можете создать UNIX-сокет для обмена сообщениями между клиентами. После установки соединения, клиент может записать выделенный порт в файл или отправить его обратно на сервер, где вы сможете его прочитать. Вот пример такого сценария, который вы можете адаптировать:# На клиенте ssh -fNMS /path/to/socket [email protected] port="$(ssh -S /path/to/socket -O forward -R 0:localhost:22 placeholder)" echo "$port" | ssh -S /path/to/socket placeholder 'cat > A.port'
Этот скрипт создает сокет для управления сессиями и записывает выделенный порт, чтобы его можно было позже использовать.
-
Мониторинг процессов:
Как вы уже пытались, можно использовать файлauthorized_keys
для выполнения команд на начальном этапе SSH-сессии. Однако, как вы отметили,-N
не выполняет команды. Альтернативный подход — использовать скрипты, которые запускаются параллельно сssh
, чтобы обеспечить необходимую логику для извлечения информации о портах. -
Регистрация состояния:
Если у вас есть возможность, вы можете рассмотреть возможность ведения журнала создаваемых туннелей с помощью централизованного логирования или системы, которая может отслеживать такие события. Это поможет автоматически обрабатывать информацию о портах без необходимости вручную отслеживать каждое подключение.
Почему важно знать случайный порт?
Идентификация случайных портов имеет значение в следующих контекстах:
- Безопасность: Ключ к системам должен быть защищен, а случайный порт не может быть предсказан. Это важно для защиты от несанкционированного доступа.
- Управление ресурсами: В случае большого количества серверов случайные порты могут создать путаницу. Поэтому следует четко документировать созданные подключения.
Заключение
Ваша задача по идентификации случайных портов может быть решена с помощью систем автоматизации и организации обмена информацией о выделенных портах. Основная идея состоит в том, чтобы автоматизировать процесс уведомления о созданных туннелях. Применяя один из предложенных подходов, вы сможете улучшить управление SSH-соединениями и избавиться от зависимости от постоянного ручного ввода информации о портах.