SSH-прокси-серверы по требованию через системные юзеры Systemd с активацией через сокет не перезагружаются

14

Чтобы добраться до изолированной сети, я использую -D .

Чтобы избежать необходимости вводить детали каждый раз, я добавляю их в ~/.ssh/config:

$ awk '/Host socks-proxy/' RS= ~/.ssh/config
Host socks-proxy
  Hostname pcit
  BatchMode yes
  RequestTTY no
  Compression yes
  DynamicForward localhost:9118

Затем я создал файл определения модуля обслуживания :

$ cat ~/.config/systemd/user/SocksProxy.service 
[Unit]
Description=SocksProxy Over Bridge Host

[Service]
ExecStart=/usr/bin/ssh -Nk socks-proxy

[Install]
WantedBy=default.target

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

$ systemctl --user daemon-reload
$ systemctl --user list-unit-files | grep SocksP
SocksProxy.service   disabled

$ systemctl --user enable SocksProxy.service
Created symlink from ~/.config/systemd/user/default.target.wants/SocksProxy.service to ~/.config/systemd/user/SocksProxy.service.

$ systemctl --user start SocksProxy.service 
$ systemctl --user status SocksProxy.service 
● SocksProxy.service - SocksProxy Over Bridge Host
   Loaded: loaded (/home/alex/.config/systemd/user/SocksProxy.service; enabled)
   Active: active (running) since Thu 2017-08-03 10:45:29 CEST; 2s ago
 Main PID: 26490 (ssh)
   CGroup: /user.slice/user-1000.slice/user@1000.service/SocksProxy.service
           └─26490 /usr/bin/ssh -Nk socks-proxy

$ netstat -tnlp | grep 118
tcp     0    0 127.0.0.1:9118        0.0.0.0:*             LISTEN     
tcp6    0    0 ::1:9118              :::*                  LISTEN

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

Я нашел документацию ( 1 , 2 ) и пример использования systemd-socket-proxyd-tool для создания 2 сервисов «обертки», «сервиса» и «сокета»:

$ cat ~/.config/systemd/user/SocksProxyHelper.socket 
[Unit]
Description=On Demand Socks proxy into Work

[Socket]
ListenStream=8118
#BindToDevice=lo
#Accept=yes

[Install]
WantedBy=sockets.target

$ cat ~/.config/systemd/user/SocksProxyHelper.service 
[Unit]
Description=On demand Work Socks tunnel
After=network.target SocksProxyHelper.socket
Requires=SocksProxyHelper.socket SocksProxy.service
After=SocksProxy.service

[Service]
#Type=simple
#Accept=false
ExecStart=/lib/systemd/systemd-socket-proxyd 127.0.0.1:9118
TimeoutStopSec=5

[Install]
WantedBy=multi-user.target

$ systemctl --user daemon-reload

Это не похоже , чтобы работать, пока sshумирает или погибает. Тогда он не будет вновь появляться при следующей попытке подключения, когда это необходимо.

Вопросов:

  1. Может ли / usr / bin / ssh действительно не принимать системные сокеты? Или только более новые версии? Мой из up2date Debian 8.9 .
  2. Только единицы root могут использовать эту BindTodeviceопцию?
  3. Почему мой прокси-сервер не восстанавливается правильно при первом новом подключении после того, как старый туннель умирает?
  4. Это правильный способ настроить «прокси ssh socks по требованию»? Если нет, то как ты это делаешь?
Алекс Страгиес
источник
autosshследует позаботиться о повторном подключении в случае сбоя подключения (хотя это не системный путь).
Jakuje
@Jakuje: Спасибо за комментарий, но я не хочу, чтобы соединение было постоянным. Я хочу, чтобы он порождался при его использовании, а затем (в идеале, после истечения времени ожидания отсутствия данных, отправленных в x минут) самозавершаться. Кроме того, мое предыдущее решение используется autossh.
Алекс Стрэги

Ответы:

4
  • Может ли / usr / bin / ssh действительно не принимать системные сокеты?

Я думаю, что это не так уж удивительно, учитывая:

  • OpenSSH - это проект OpenBSD
  • systemd поддерживает только ядро ​​Linux
  • Поддержка systemd должна быть явно добавлена ​​в OpenSSH, как необязательная зависимость / время сборки, так что это, вероятно, будет трудно продать.

  • Только единицы root могут использовать эту BindTodeviceопцию?

Пользовательские экземпляры systemd обычно довольно изолированы и, например, не могут взаимодействовать с основным экземпляром pid-0. Такие вещи, как зависимость от системных модулей из файлов пользовательских модулей, невозможны.

Документация для BindToDeviceупоминаний:

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

Из-за вышеупомянутого ограничения мы можем подразумевать, что опция не работает с пользовательскими экземплярами systemd.


  • Почему мой прокси-сервер не восстанавливается правильно при первом новом подключении после того, как старый туннель умирает?

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

  • SocksProxyHelper.socket запущен
  • Клиент SOCKS подключается к localhost: 8118.
  • systemd запускается SocksProxyHelper.service.
  • Как зависимость SocksProxyHelper.service, systemd также запускается SocksProxy.service.
  • systemd-socket-proxydпринимает сокет systemd и пересылает свои данные в ssh.
  • ssh умирает или убит.
  • systemd замечает и переводит SocksProxy.serviceв неактивное состояние, но ничего не делает.
  • SocksProxyHelper.serviceпродолжает работать и принимать подключения, но не может подключиться ssh, так как он больше не работает.

Исправление должно добавить BindsTo=SocksProxy.serviceк SocksProxyHelper.service. Цитирую свою документацию (выделение добавлено):

Настраивает зависимости требований, очень похожие по стилю Requires=. Однако этот тип зависимости сильнее: в дополнение к эффекту Requires=он объявляет, что если остановленный блок остановлен, этот блок также будет остановлен . Это означает, что юнит, связанный с другим юнитом, который внезапно переходит в неактивное состояние, также будет остановлен. Блоки могут неожиданно неожиданно переходить в неактивное состояние по разным причинам: основной процесс сервисного блока может завершиться по его собственному выбору , устройство поддержки устройства может быть отключено или точка монтирования блока монтирования может быть отключена без участия менеджер системы и сервиса.

При использовании в сочетании с After=одним и тем же устройством поведение BindsTo=становится еще сильнее. В этом случае блок , к которому привязан строго, должен находиться в активном состоянии, чтобы этот блок также находился в активном состоянии . Это означает не только блок , связанный с другим блоком , который внезапно входит в неактивное состояние, но и один , который связан с другим блоком , который получает пропущено из - за проверки не удалось условий (таких как ConditionPathExists=, ConditionPathIsSymbolicLink=... - смотри ниже) будет остановлен, если он быть запущенным Следовательно, во многих случаях лучше всего сочетать BindsTo=с After=.


  • Это правильный способ настроить «прокси ssh socks по требованию»? Если нет, то как ты это делаешь?

Там, вероятно, нет "правильного пути". У этого метода есть свои преимущества (все по требованию) и недостатки (зависимость от systemd, первое соединение не проходит, потому что ssh еще не начал слушать). Возможно, реализация поддержки активации сокетов systemd в autossh была бы лучшим решением.

Владимир Пантелеев
источник
Я добавил BindsTo=SocksProxy.serviceв раздел Unit файла ~/.config/systemd/user/SocksProxyHelper.service, после After=SocksProxy.serviceстроки. Перезапуск службы SocksProxy вручную больше не требуется, когда SSH умирает / gets_killed. Есть ли способ для systemd «удерживать» исходное соединение, чтобы он не получал сброс TCP?
Алекс Стрэги
@Vladimir Panteleev Я хотел бы уточнить одно замечание: поддержка активации systemd сокетов может быть реализована относительно легко путем анализа $LISTEN_FDSбез добавления зависимости sd_listen_fds(), так что это может быть трудно продать, но не слишком сложно.
Амир