web-dev-qa-db-ja.com

ソケットをアクティブ化したsystemdユーザーユニットを介したオンデマンドSSH Socksプロキシが、希望どおりに再起動しない

隔離されたネットワークに到達するには、 ssh-Dsocksproxy を使用します。

詳細を~/.ssh/configに追加するたびに詳細を入力する手間を省くために:

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

次に systemd-user サービスユニット定義ファイルを作成しました。

$ 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

これは意図したとおりに機能します。次に、サービスを手動で開始したり、 systemdsocket-activation をオンデマンドで使用して autossh で恒久的に実行したりすることを避けたかった(再)産卵。 (私のバージョンの)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で渡されたソケットを受け入れませんか?それとも新しいバージョンのみですか?私のものは p2date Debian 8.9からのもの です。
  2. ルートのユニットのみがBindTodeviceオプションを使用できますか?
  3. 古いトンネルが停止した後、最初の新しい接続でプロキシサービスが正しく再生成されないのはなぜですか?
  4. これは「オンデマンドのSSHソックスプロキシ」を設定する正しい方法ですか?そうでない場合、どうやってそれを行うのですか?
14
Alex Stragies
  • / usr/bin/sshは本当にsystemdで渡されたソケットを受け入れませんか?

次の点を考慮すると、それほど驚くことではないと思います。

  • OpenSSHはOpenBSDプロジェクトです
  • systemdはLinuxカーネルのみをサポートします
  • systemdのサポートは、オプション/ビルド時の依存関係として、明示的にOpenSSHに追加する必要があるので、おそらく困難です。

  • ルートのユニットのみが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.serviceSocksProxyHelper.serviceに追加することです。そのドキュメントの引用(強調を追加):

要件の依存関係を構成します。スタイルはRequires=とよく似ています。ただし、この依存タイプはより強力です。Requires=の効果に加えて、それはバインドされたユニットが停止すると、このユニットも停止すると宣言します。つまり、突然非アクティブ状態になった別のユニットにバインドされているユニットも停止します。ユニットは、さまざまな理由で突然、突然、非アクティブ状態になることがあります。サービスユニットのメインプロセスが独自に終了する可能性があります、デバイスユニットのバッキングデバイスが取り外されているか、マウントのマウントポイントですユニットは、システムおよびサービスマネージャの関与なしにマウント解除される場合があります。

同じユニットでAfter=と組み合わせて使用​​すると、BindsTo=の動作がさらに強力になります。この場合、バインドされているユニットはこのユニットもアクティブ状態になるには、厳密にアクティブ状態でなければなりませんです。これは、突然非アクティブ状態になる別のユニットにバインドされているユニットだけでなく、条件チェックの失敗によりスキップされた別のユニットにバインドされているユニット(ConditionPathExists=ConditionPathIsSymbolicLink=、…など)も意味します—下記を参照)実行されている場合は停止します。したがって、多くの場合、BindsTo=After=を組み合わせるのが最適です。


  • これは「オンデマンドのSSHソックスプロキシ」を設定する正しい方法ですか?そうでない場合、どうやってそれを行うのですか?

おそらく「正しい方法」はありません。この方法には、長所(すべてが「オンデマンド」)と短所(systemdに依存しているため、sshがまだリッスンしていないため、最初の接続が通過しない)があります。おそらく、autosshにsystemdソケットアクティベーションサポートを実装する方が良いソリューションでしょう。

4