El proxy SSH Socks bajo demanda a través de unidades de usuario systemd con activación de socket no se reinicia como se desea

14

Para llegar a una red aislada, uso un -D .

Para evitar tener que escribir los detalles cada vez que los agregué a ~/.ssh/config:

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

Luego creé un archivo de definición de unidad de servicio :

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

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

[Install]
WantedBy=default.target

Dejé que el demonio volviera a cargar las nuevas definiciones de servicio, habilité el nuevo servicio, lo inicié, verifiqué su estado y verifiqué que está escuchando:

$ 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/[email protected]/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

Esto funciona según lo previsto. Luego, quería evitar tener que iniciar manualmente el servicio, o ejecutarlo permanentemente con , mediante para el (rea) desove bajo demanda. Eso no funcionó, creo que (mi versión de) no puede recibir descriptores de archivos de socket.ssh

Encontré la documentación ( 1 , 2 ) y un ejemplo para usar la systemd-socket-proxydherramienta -tool para crear 2 servicios "wrapper", un "servicio" y un "socket":

$ 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

Esto parece funcionar, hasta que sshmuere o muere. Entonces no volverá a aparecer en el siguiente intento de conexión cuando debería.

Preguntas:

  1. ¿Puede / usr / bin / ssh realmente no aceptar sockets pasados ​​por systemd? ¿O solo versiones más nuevas? El mío es el de up2date Debian 8.9 .
  2. ¿Solo las unidades de raíz pueden usar la BindTodeviceopción?
  3. ¿Por qué mi servicio proxy no se reaparece correctamente en la primera conexión nueva después de que el túnel viejo muere?
  4. ¿Es esta la forma correcta de configurar un "proxy de calcetines ssh a pedido"? Si no, ¿cómo lo haces?
Alex Stragies
fuente
autosshdebe ocuparse de reconectarse en caso de que falle la conexión (aunque no es el sistema).
Jakuje
@Jakuje: Gracias por el comentario, pero no quiero que la conexión sea permanente. Quiero que se genere cuando lo uso, y luego (idealmente después de un tiempo de espera sin datos enviados en x minutos) auto-terminar. Además, mi solución anterior utilizada autossh.
Alex Stragies

Respuestas:

4
  • ¿Puede / usr / bin / ssh realmente no aceptar sockets pasados ​​por systemd?

Creo que eso no es demasiado sorprendente, teniendo en cuenta:

  • OpenSSH es un proyecto OpenBSD
  • systemd solo es compatible con el kernel de Linux
  • el soporte de systemd debería agregarse explícitamente a OpenSSH, como una dependencia opcional / tiempo de compilación, por lo que probablemente sería una venta difícil.

  • ¿Solo las unidades de raíz pueden usar la BindTodeviceopción?

Las instancias de systemd de usuario generalmente están bastante aisladas y, por ejemplo, no pueden comunicarse con la instancia principal de pid-0. Cosas como depender de las unidades del sistema de los archivos de la unidad del usuario no son posibles.

La documentación para las BindToDevicemenciones:

Tenga en cuenta que establecer este parámetro puede dar como resultado que se agreguen dependencias adicionales a la unidad (consulte más arriba).

Debido a la restricción mencionada anteriormente, podemos implicar que la opción no funciona desde instancias systemd de usuario.


  • ¿Por qué mi servicio proxy no se reaparece correctamente en la primera conexión nueva después de que el túnel viejo muere?

Según tengo entendido, la cadena de eventos es la siguiente:

  • SocksProxyHelper.socket Está empezado.
  • Un cliente SOCKS se conecta a localhost: 8118.
  • Se inicia systemd SocksProxyHelper.service.
  • Como dependencia de SocksProxyHelper.service, systemd también se inicia SocksProxy.service.
  • systemd-socket-proxydacepta el socket systemd y reenvía sus datos a ssh.
  • ssh muere o es asesinado.
  • systemd se da cuenta y se coloca SocksProxy.serviceen un estado inactivo, pero no hace nada.
  • SocksProxyHelper.servicesigue ejecutándose y aceptando conexiones, pero no puede conectarse ssh, ya que ya no se está ejecutando.

La solución es agregar BindsTo=SocksProxy.servicea SocksProxyHelper.service. Citando su documentación (énfasis agregado):

Configura las dependencias de requisitos, muy similares en estilo a Requires=. Sin embargo, este tipo de dependencia es más fuerte: además del efecto Requires=, declara que si la unidad unida a se detiene, esta unidad también se detendrá . Esto significa que una unidad unida a otra unidad que de repente entre en estado inactivo también se detendrá. Las unidades pueden entrar repentina e inesperadamente en estado inactivo por diferentes razones: el proceso principal de una unidad de servicio puede terminar por su propia elección , el dispositivo de respaldo de una unidad de dispositivo puede desconectarse o el punto de montaje de una unidad de montaje puede desmontarse sin la participación de El administrador de sistemas y servicios.

Cuando se usa junto con After=la misma unidad, el comportamiento de BindsTo=es aún más fuerte. En este caso, la unidad destinada estrictamente tiene que estar en estado activo para que esta unidad también esté en estado activo . Esto no sólo significa una unidad con destino a otra unidad que de repente entra en estado inactivo, pero también uno que se une a otra unidad que obtiene son obviados debido a una comprobación de condición de fallo (como ConditionPathExists=, ConditionPathIsSymbolicLink=, ... - ver más abajo) será suspendida, debería hacerlo estar corriendo Por lo tanto, en muchos casos es mejor combinar BindsTo=con After=.


  • ¿Es esta la forma correcta de configurar un "proxy de calcetines ssh a pedido"? Si no, ¿cómo lo haces?

Probablemente no haya una "forma correcta". Este método tiene sus ventajas (todo es "a pedido") y desventajas (dependencia de systemd, la primera conexión no funciona porque ssh aún no ha comenzado a escuchar). Quizás la implementación de soporte de activación de socket systemd en autossh sería una mejor solución.

Vladimir Panteleev
fuente
He agregado BindsTo=SocksProxy.servicea la sección Unidad del archivo ~/.config/systemd/user/SocksProxyHelper.service, después de la After=SocksProxy.servicelínea. Ahora ya no es necesario reiniciar manualmente el servicio SocksProxy, cuando SSH muere / se mata. ¿Hay alguna forma para que systemd "retenga" la conexión inicial, para que no se restablezca TCP?
Alex Stragies
@Vladimir Panteleev, un punto que me gustaría aclarar: el soporte para la activación del socket systemd se puede implementar de manera relativamente fácil analizando $LISTEN_FDSsin agregar una dependencia sd_listen_fds(), por lo que aún puede ser difícil de vender, pero no demasiado difícil.
Amir el