소켓 활성화가 포함된 systemd 사용자 단위를 통한 주문형 SSH Socks 에이전트가 예상대로 다시 시작되지 않습니다.

소켓 활성화가 포함된 systemd 사용자 단위를 통한 주문형 SSH Socks 에이전트가 예상대로 다시 시작되지 않습니다.

내가 사용하는 격리된 네트워크에 도달하려면 -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/[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

이것은 예상대로 작동합니다. 그런 다음 서비스를 수동으로 시작하거나 영구적으로 실행하는 것을 방지하고 싶습니다., 사용하여 주문형 (재생)생성에 사용됩니다. 작동하지 않는 것 같습니다. (내 버전) ssh이 소켓 파일 설명자를 받을 수 없는 것 같습니다.

문서를 찾았습니다 (1,2), 그리고한 가지 예사용하기위한systemd-socket-proxyd- 서비스를 "래핑"하는 두 가지 도구인 "서비스"와 "소켓"을 만듭니다.

$ 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가 systemd가 전달한 소켓을 허용할 수 없다는 것이 사실입니까? 아니면 최신 버전인가요? 내 것은최신 데비안 8.9 중 하나.
  2. 이 옵션은 루트 유닛에서만 사용할 수 있습니까 BindTodevice?
  3. 이전 터널이 만료된 후 첫 번째 새 연결에서 프록시 서비스가 올바르게 다시 생성되지 않는 이유는 무엇입니까?
  4. 이것이 "요청 시 SSH 프록시"를 설정하는 올바른 방법입니까? 그렇지 않다면 어떻게 합니까?

답변1

  • /usr/bin/ssh가 systemd가 전달한 소켓을 허용할 수 없다는 것이 사실입니까?

다음 사항을 고려하면 이는 별로 놀라운 일이 아닌 것 같습니다.

  • OpenSSH는 OpenBSD 프로젝트입니다
  • systemd는 Linux 커널만 지원합니다.
  • systemd 지원은 선택 사항/빌드 타임 종속성으로 OpenSSH에 명시적으로 추가해야 하므로 판매가 어려울 수 있습니다.

  • 이 옵션은 루트 유닛에서만 사용할 수 있습니까 BindTodevice?

사용자 systemd 인스턴스는 마스터 pid-0 인스턴스와 통신할 수 없는 등 매우 격리된 경우가 많습니다. 사용자 단위 파일의 시스템 단위에 의존하는 것과 같은 것은 불가능합니다.

언급된 문서 BindToDevice:

이 매개변수를 설정하면 장치에 추가 종속성이 추가될 수 있습니다(위 참조).

위의 제한으로 인해 이 옵션은 사용자 시스템 인스턴스에 영향을 미치지 않는다는 것을 암시할 수 있습니다.


  • 이전 터널이 만료된 후 첫 번째 새 연결에서 프록시 서비스가 올바르게 다시 생성되지 않는 이유는 무엇입니까?

내가 아는 한 일련의 사건은 다음과 같습니다.

  • SocksProxyHelper.socket시작되었습니다.
  • SOCKS 클라이언트는 localhost:8118에 연결됩니다.
  • 시스템이 시작됩니다 SocksProxyHelper.service.
  • 종속성으로 SocksProxyHelper.servicesystemd도 시작됩니다 SocksProxy.service.
  • systemd-socket-proxyd시스템 소켓을 수락하고 해당 데이터를 ssh.
  • ssh죽거나 죽임을 당합니다.
  • systemd는 이를 인지하고 비활성 상태로 설정 SocksProxy.service하지만 아무 작업도 수행하지 않습니다.
  • SocksProxyHelper.servicessh계속 실행되고 연결을 수락하지만 더 이상 실행되지 않기 때문에 연결할 수 없습니다 .

수정 사항은 해당 설명서를 인용하여 추가하는 것입니다 BindsTo=SocksProxy.service( SocksProxyHelper.service강조 추가).

구성에는 로 스타일 지정된 종속성이 필요합니다 . 그러나 이 종속성 유형은 선언된 효과 Requires=외에도 더 강력합니다 .Requires=바인딩된 유닛이 정지되면 본 유닛도 정지됩니다.. 즉, 갑자기 비활성화된 다른 장치에 바인딩된 장치도 중지됩니다. 여러 가지 이유로 장치가 갑자기 예기치 않게 비활성화될 수 있습니다.서비스 단위의 주요 프로세스가 자체적으로 종료될 수 있습니다., 장치 장치의 지원 장치가 분리되거나 장치가 설치된 장착 지점이 시스템 및 서비스 관리자의 개입 없이 분리될 수 있습니다.

동일한 장치에 결합하면 After=동작이 BindsTo=더욱 강력해집니다. 이 경우 해당 유닛은 다음과 같이 바인딩됩니다.장치도 활성화하려면 엄격하게 활성화되어야 합니다.. 이는 다른 유닛에 바인딩된 유닛이 갑자기 비활성화된다는 의미일 뿐만 아니라, 다른 유닛에 바인딩된 유닛이 조건 확인 실패로 인해 건너뛴다는 의미이기도 합니다(예: ConditionPathExists=,,, ConditionPathIsSymbolicLink=... - 아래 참조). 달리기. 따라서 많은 경우에 BindsTo=와 함께 사용하는 것이 가장 좋습니다 After=.


  • 이것이 "요청 시 SSH 프록시"를 설정하는 올바른 방법입니까? 그렇지 않다면 어떻게 합니까?

"올바른 방법"이 없을 수도 있습니다. 이 접근 방식에는 장점(모든 것이 "주문형"임)과 단점(systemd에 의존, ssh가 아직 수신을 시작하지 않았기 때문에 첫 번째 연결이 진행되지 않음)이 있습니다. 아마도 autossh에서 systemd 소켓 활성화 지원을 구현하는 것이 더 나은 솔루션이 될 것입니다.

답변2

나중에 참조할 수 있도록 systemd --user아래 데몬을 사용하여 주문형 SSH 터널에 대한 구성 파일을 systemd-socket-proxyd다양한 개선 사항 및 설명 설명과 함께 붙여넣었습니다.

~/.config/systemd/user/ssh-tunnel-proxy.socket

[Unit]
Description=Socket-activation for SSH-tunnel

[Socket]
ListenStream=1000

[Install]
WantedBy=sockets.target

~/.config/systemd/user/ssh-tunnel-proxy.service

[Unit]
Description=Socket-activation proxy for SSH tunnel

## Stop also when stopped listening for socket-activation.
BindsTo=ssh-tunnel-proxy.socket
After=ssh-tunnel-proxy.socket

## Stop also when ssh-tunnel stops/breaks
#  (otherwise, could not restart).
BindsTo=ssh-tunnel.service
After=ssh-tunnel.service

[Service]
ExecStart=/lib/systemd/systemd-socket-proxyd --exit-idle-time=500s localhost:1001

~/.config/systemd/user/ssh-tunnel.service

[Unit]
Description=Tunnel to SSH server

## Stop-when-idle is controlled by `--exit-idle-time=` in proxy.service
#  (from `man systemd-socket-proxyd`)
StopWhenUnneeded=true

[Service]
Type=simple
## Prefixed with `-` not to mark service as failed on net-fails;
#  will be restarted on-demand by socket-activation.
ExecStart=-/usr/bin/ssh -kaxNT -o ExitOnForwardFailure=yes  hostname_in_ssh_config  -L 1001:localhost:2000
## Delay enough time to allow for ssh-authentication to complete
#  so tunnel has been established before proxy process attaches to it,
#  or else the first SYN request will be lost.
ExecStartPost=/bin/sleep 2

맞춤 제작

위 스크립트에서 다음 문자열을 바꿔야 합니다.

  • 1000- ( ssh-tunnel-proxy.socket문서)
    (호스트:)포트로컬 MYSql 포트 에뮬레이션과 같은 로컬 청취 터널을 위한 소켓 활성화.
  • 1001- ( ssh-tunnel-proxy.servicessh-tunnel.service파일)
    로컬이란 무엇입니까?(호스트:)포트에이전트가 SSH 서비스 프로세스로 전달할 때 사용됩니다.
    사용되지 않는 포트를 선택하세요.
  • hostname_in_ssh_config- ( ssh-tunnel.service파일)
    연결할 호스트 그룹입니다.SSH 구성 (모든 SOCKS 구성이 여기에 속합니다).
  • localhost:2000- ( ssh-tunnel.service파일)
    SSH 터널 원격호스트:포트원격 MYSql이 바인딩되는 위치와 같은 끝점입니다.
  • x2 지연 시간( ssh-tunnel-proxy.servicessh-tunnel.service문서)
    주석에 설명되어 있습니다.
  • ssh-tunnel-...- (모든 유닛 파일의 접두사)
    터널링에 대한 필요성을 설명합니다 mysql-tunnel-.... 예: .
  • SSH- ( Description=모든 유닛 파일의 지시문에서)
    터널링에 대한 요구 사항을 설명합니다 MYSql. 예: .

터널을 제어하는 ​​명령

# After any edits.
systemctl --user daemon-reload
# If socket's unit-file has been edited.
systemctl --user restart ssh-tunnel-proxy.socket

# To start listening for on-demand activation of the tunnel
systemctl --user start ssh-tunnel.socket

# To enable on-demand tunnel on Boot
systemctl --user enable ssh-tunnel-proxy.socket

# To gracefully stop tunnel (any cmd will do)
systemctl --user stop ssh-tunnel.service
systemctl --user stop ssh-tunnel-proxy.service

# To gracefully stop & disable tunnel (till next reboot)
systemctl --user stop ssh-tunnel-proxy.socket

# To view the health of the tunnel
systemctl --user status ssh-tunnel-proxy.{socket,service} ssh-tunnel

# To reset tunnel after errors (both cmds may be needed)
systemctl --user reset-failed ssh-tunnel ssh-tunnel-proxy
systemctl --user restart ssh-tunnel-proxy.socket

답변3

평판 시스템 때문에 @ankostis 솔루션에 대해서는 언급할 수 없습니다...

systemd에 bash 수면 루프 사용을 피할 수 있는 옵션이 있는 것 같습니다.

예, systemd-notify가 있습니다.

또한 다음과 같이 로컬 포트 ​​낭비를 피하기 위해 systemd-socket-proxyd와 ssh 사이에 소켓을 사용하라는 @noam의 제안과 함께:

~/.config/systemd/user/ssh-tunnel-proxy.service

[Unit]
Description=Socket-activation proxy for SSH tunnel

## Stop also when stopped listening for socket-activation.
BindsTo=ssh-tunnel-proxy.socket
After=ssh-tunnel-proxy.socket

## Stop also when ssh-tunnel stops/breaks
#  (otherwise, could not restart).
BindsTo=ssh-tunnel.service
After=ssh-tunnel.service

[Service]
ExecStart=/lib/systemd/systemd-socket-proxyd --exit-idle-time=500s ${XDG_RUNTIME_DIR}/ssh-tunnel-proxy

~/.config/systemd/user/ssh-tunnel.service

[Unit]
Description=Tunnel to SSH server

## Stop-when-idle is controlled by `--exit-idle-time=` in proxy.service
#  (from `man systemd-socket-proxyd`)
StopWhenUnneeded=true

[Service]
Type=notify
NotifyAccess=all
## Prefixed with `-` not to mark service as failed on net-fails;
#  will be restarted on-demand by socket-activation.
ExecStart=-/usr/bin/ssh -kaxNT -o ExitOnForwardFailure=yes -o ControlMaster=no -o StreamLocalBindUnlink=yes -o PermitLocalCommand=yes -o LocalCommand="systemd-notify --ready" hostname_in_ssh_config -L ${XDG_RUNTIME_DIR}/ssh-tunnel-proxy:localhost:2000

ssh_config 매뉴얼 페이지에서는 LocalCommand "서버에 성공적으로 연결한 후 로컬 컴퓨터에서 실행할 명령 지정"에 대해 설명합니다.

ControlMaster=no멀티플렉싱을 사용할 때 SSH 세션이 마스터되지 않도록 하십시오. 동일한 호스트에 대한 다른 모든 멀티플렉싱된 SSH 세션이 자동으로 닫히고 종료되기 때문입니다.

마지막으로 소켓 포트를 localhost에 바인딩하는 것이 좋습니다.

~/.config/systemd/user/ssh-tunnel-proxy.socket

[Unit]
Description=Socket-activation for SSH-tunnel

[Socket]
ListenStream=127.0.0.1:1000
ListenStream=[::1]:1000

[Install]
WantedBy=sockets.target

답변4

아직 이것을 테스트하고 있지만(이 답변을 작성할 때 사용하고 있습니다) 누락된 성분이 바이너리 -o ExitOnForwardFailure=yes에 옵션으로 포함되어 있다고 생각합니다 ssh.

관련 정보