ソケットの有効化を含む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このソケットファイル記述子を受け取ることができないようです。

文書が見つかりました(12)、そして一例使用するためsystemd-socket-proxyd- サービスを「ラップ」する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がsystemdによって渡されたソケットを受け入れることができないというのは本当ですか?それとも最新バージョンですか?私のもの最新のDebian 8.9の1つ
  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.serviceSocksProxyHelper.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.serviceおよびssh-tunnel.serviceファイル)
    ローカルとは何ですか?(ホスト:)ポートエージェントが SSH サービスプロセスに渡すときに使用されます。
    未使用のポートを選択してください。
  • hostname_in_ssh_config- (ssh-tunnel.serviceファイル)
    接続するホストグループです。SSH構成 (すべてのSOCKS構成はここに属します)。
  • localhost:2000- (ssh-tunnel.serviceファイル)
    SSHトンネルリモートホスト:ポートリモート MYSql がバインドされる場所と同じエンドポイントです。
  • x2 遅延時間ssh-tunnel-proxy.serviceおよびssh-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

関連情報