O proxy SSH sob demanda de meias por meio de unidades de usuário systemd com ativação de soquete não é reiniciado conforme desejado

14

Para acessar uma rede isolada, eu uso um -D .

Para evitar a necessidade de digitar os detalhes toda vez que os adicionei a ~/.ssh/config:

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

Em seguida, criei um arquivo de definição da unidade de serviço :

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

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

[Install]
WantedBy=default.target

Deixei o daemon recarregar as novas definições de serviço, habilitei o novo serviço, iniciei-o, verifiquei seu status e verifiquei que ele estava ouvindo:

$ 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

Isso funciona como pretendido. Então, eu queria evitar ter que iniciar manualmente o serviço ou executá-lo permanentemente com , usando para a (re) geração sob demanda. Isso não funcionou, acho que (minha versão do) não pode receber descritores de arquivos de soquete.ssh

Encontrei a documentação ( 1 , 2 ) e um exemplo para usar a systemd-socket-proxydferramenta-para criar 2 serviços "wrapper", um "serviço" e um "soquete":

$ 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

Isso parece funcionar, até sshmorrer ou ser morto. Em seguida, ele não voltará a aparecer na próxima tentativa de conexão, quando deveria.

Questões:

  1. O / usr / bin / ssh pode realmente não aceitar soquetes passados ​​pelo systemd? Ou apenas versões mais recentes? A minha é a do up2date Debian 8.9 .
  2. Apenas unidades de raiz podem usar a BindTodeviceopção?
  3. Por que meu serviço de proxy não está reaparecendo corretamente na primeira conexão nova após a morte do túnel antigo?
  4. Essa é a maneira correta de configurar um "proxy sob demanda ssh socks"? Se não, como você faz isso?
Alex Stragies
fonte
autosshdeve se reconectar caso a conexão falhe (embora não seja o caminho do sistema).
Jakuje 3/17/17
@Jakuje: Agradecemos pelo comentário, mas não quero que a conexão seja permanente. Quero que ele seja gerado quando o usar e depois (idealmente após um tempo limite sem envio de dados em x minutos), seja encerrado automaticamente. Além disso, minha solução anterior foi usada autossh.
Alex Stragies

Respostas:

4
  • O / usr / bin / ssh pode realmente não aceitar soquetes passados ​​pelo systemd?

Eu acho que isso não é muito surpreendente, considerando:

  • OpenSSH é um projeto do OpenBSD
  • O systemd suporta apenas o kernel do Linux
  • O suporte ao systemd precisaria ser explicitamente adicionado ao OpenSSH, como uma dependência opcional / em tempo de construção, portanto, provavelmente seria uma venda difícil.

  • Apenas unidades de raiz podem usar a BindTodeviceopção?

As instâncias systemd do usuário geralmente são bastante isoladas e, por exemplo, não podem se comunicar com a instância principal do pid-0. Coisas como depender das unidades do sistema dos arquivos das unidades do usuário não são possíveis.

A documentação para BindToDevicemenções:

Observe que a definição desse parâmetro pode resultar em dependências adicionais a serem adicionadas à unidade (veja acima).

Devido à restrição mencionada acima, podemos sugerir que a opção não funciona nas instâncias do usuário systemd.


  • Por que meu serviço de proxy não está reaparecendo corretamente na primeira conexão nova após a morte do túnel antigo?

Pelo que entendi, a cadeia de eventos é a seguinte:

  • SocksProxyHelper.socket começou.
  • Um cliente SOCKS se conecta ao host local: 8118.
  • systemd inicia SocksProxyHelper.service.
  • Como uma dependência de SocksProxyHelper.service, systemd também inicia SocksProxy.service.
  • systemd-socket-proxydaceita o soquete systemd e encaminha seus dados para ssh.
  • ssh morre ou é morto.
  • O systemd percebe e coloca SocksProxy.serviceem um estado inativo, mas não faz nada.
  • SocksProxyHelper.servicecontinua executando e aceitando conexões, mas não consegue se conectar ssh, pois não está mais em execução.

A correção é adicionar BindsTo=SocksProxy.servicea SocksProxyHelper.service. Citando sua documentação (ênfase adicionada):

Configura dependências de requisitos, com estilo muito semelhante ao Requires=. No entanto, esse tipo de dependência é mais forte: além do efeito Requires=, declara que, se a unidade ligada a estiver parada, esta unidade também será parada . Isso significa que uma unidade ligada a outra unidade que entra repentinamente no estado inativo também será parada. As unidades podem entrar repentinamente, inesperadamente, no estado inativo por diferentes razões: o processo principal de uma unidade de serviço pode terminar por sua própria escolha , o dispositivo de suporte de uma unidade de dispositivo pode ser desconectado ou o ponto de montagem de uma unidade de montagem pode ser desmontado sem o envolvimento de o gerente de sistema e serviço.

Quando usado em conjunto com After=a mesma unidade, o comportamento de BindsTo=é ainda mais forte. Nesse caso, a unidade ligada estritamente deve estar no estado ativo para que esta unidade também esteja no estado ativo . Isto não significa apenas uma unidade ligada a outra unidade que, de repente entra no estado inativo, mas também aquele que é obrigado a outra unidade que fica ignorada devido a uma verificação de condição falhou (como ConditionPathExists=, ConditionPathIsSymbolicLink=... - veja abaixo) será interrompido, caso estar correndo. Por isso, em muitos casos, é melhor combinar BindsTo=com After=.


  • Essa é a maneira correta de configurar um "proxy sob demanda ssh socks"? Se não, como você faz isso?

Provavelmente não há "caminho certo". Este método tem suas vantagens (tudo "sob demanda") e desvantagens (dependência do systemd, a primeira conexão não é concluída porque o ssh ainda não começou a escutar). Talvez implementar o suporte à ativação do soquete systemd no autossh seja uma solução melhor.

Vladimir Panteleev
fonte
Eu adicionei BindsTo=SocksProxy.serviceà seção Unidade do arquivo ~/.config/systemd/user/SocksProxyHelper.service, após a After=SocksProxy.servicelinha. Agora, a reinicialização manual do serviço SocksProxy não é mais necessária, quando o SSH morre / fica_qualificado. Existe uma maneira de o systemd "reter" a conexão inicial, para que ela não seja redefinida como TCP?
Alex Stragies
@ Vladimir Panteleev, um ponto que gostaria de esclarecer: o suporte à ativação do soquete systemd pode ser implementado com relativa facilidade, analisando $LISTEN_FDSsem adicionar uma dependência sd_listen_fds(), por isso ainda pode ser uma venda difícil, mas não muito difícil.
Amir #