MJUN Tech Note

mac, Ubuntuでautosshとsystemd, launchdで常にPortforwardする

こんにちは.今回はssh接続を極力維持してくれるAutosshと Linux, Unixのサービス管理を行うsystemd, launchdを組み合わせて,常にssh Portforwardを行う環境を作成します.

この設定は特定のネットワーク下で閲覧・アクセスできるサイト等を閲覧する際に, 毎回sshやVPN接続をする必要がなくなります.

autosshとは

autosshはssh接続を極力維持してくれるCLIコマンドです.
インストールは以下の方法で行います.

# Ubuntu
sudo apt install autossh
# macOS
brew install autossh

コマンドの使い方はsshとほとんど変わりません.

autossh -M 0 -f -L 12022:remote:22

-Mオプションはモニターポートです.特に何もなければ0で無効にしても良いと思います.詳しくはman autosshに記述されています.

-fオプションはautosshをバックグラウンドで実行します. 注意として,パスワードの要求などの入力を行うことができないので, このオプションを使用する際はリモート先にパスワードなしでログインできる必要があります.

autosshとsystemd, launchdの組み合わせ

systemdはUbuntu,launchdはmacOSのサービス管理ツールです.
systemd, launchdにautosshと登録することで,

  • sshが落ちた場合はautosshが再接続
  • autosshが落ちた場合はsystemd, launchdが再接続
  • システム起動時はsystemd, launchdが接続

というように,より強固にssh接続を維持することができます. 今回は,ssh configに書いた設定を元にautosshする方法でポートフォワードしていきます.

事前準備

まずは事前準備として,リモート先にパスワードなしでssh接続できるようにしておきます.
sshの認証を公開鍵認証に設定しておくと良いでしょう.

ここで注意でするのは,Ubuntuで秘密鍵にパスフレーズを設定した場合です.
macOSでは~/.ssh/configUseKeychainを設定することで, ssh使用時にパスフレーズがKeychainに保存され, 自動的にssh-agentへ読み込まれるのですが, UbuntuではKeychainがないため自分で行う必要があります.

先ほど述べたように,autosshではssh時の入力を扱うことができないため, Ubuntuでautosshする際はパスフレーズなしの秘密鍵を用意しておく必要があります. macではKeychainが良しなしにやってくれるので必要ありません. 秘密鍵のパスワードは以下のコマンドで設定・解除できます.

ssh-keygen -f ~/.ssh/id_rsa -p

上記を解決したら,初回の通常のssh接続を行います. 初回ssh時にはfingerprintの確認が行われ,応答が必要なため,autosshする際に発生しないようにするためです. 今回はssh configに書いた設定でsshしていきます.

Host remote
  HostName hoge
  User hoge
  LocalForward 6006 localhost:6006
ssh remote
The authenticity of host 'hoge (::1)' can't be established.
ED25519 key fingerprint is SHA256:hogehogehogehoge.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes

yes以外のパスワード等の入力なしで初回ログインが済んだら成功です.次に進みましょう.

autosshをサービス化する

次に,autosshをサービス化するためにコンフィグを書いていきます.

mac: Launchdの場合

まずはautosshのフルパスの場所を確認しておきましょう.

$ which autossh
/opt/homebrew/bin/autossh

今回は/opt/homebrew/binにあるようです.Intel macだと/usr/local/binにあったりします. Launchdの設定ファイルの場所はいくつかありますが,今回はユーザーがログインした際に実行するようにします. こうすることで,先ほど記入した~/.ssh/configの内容が使用できるようになります. ~/Library/LaunchAgents/remote.autossh.plistに以下の内容のファイルを置きます.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>KeepAlive</key>
  <true/>
  <key>RunAtLoad</key>
  <true/>
  <key>EnvironmentVariables</key>
  <dict>
    <key>AUTOSSH_GATETIME</key>
    <integer>0</integer>
  </dict>
  <key>UserName</key>
  <string>[username]</string>
  <key>Label</key>
  <string>remote.autossh</string>
  <key>ProgramArguments</key>
  <array>
    <string>/opt/homebrew/bin</string>
    <string>-M</string>
    <string>0</string>
    <string>-N</string>
    <string>remtote</string>
  </array>
</dict>
</plist>

ファイルが書き込めたらlaunchdに登録していきます.この際,plistのパスは絶対パスで書いてください.

launchctl load /Users/[username]/Library/LaunchAgents/remote.autossh.plist

今回はplistにRunAtLoadを追加しているので,loadした時点で実行も行われているはずです.確認してみます.

$ launchctl list | grep remote.autossh
57892	0	remote.autossh

左からPIDとexit code,Labelが表示されます.今回はPIDがあり,exitcode=0なので成功です. サービスから削除を行う場合はunloadを行います.

launchctl unload /Users/[username]/Library/LaunchAgents/remote.autossh.plist

ssh configを変更した場合はstop, startで再起動を行います.

launchctl stop iplab.autossh
launchctl start iplab.autossh

Ubuntu: Systemdの場合

Ubuntuではsystemdに設定を行なっていきます. RedHat系のCentOSやAmazonLinux等でもsystemdは同じなので, 少し変えれば同じように設定できると思います.(未確認)

/etc/systemd/system/remote.autossh.serviceに設定を書いていきます.

[Unit]
Description=keep ssh
After=network-online.target ssh.service

[Service]
User=[username]
Type=simple
RestartSec=3
Restart=always
TimeoutStopSec=10
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/bin/autossh -M 0 -N remote

[Install]
WantedBy=multi-user.target

最後にサービスを起動して,正常に動いているかstatusを確認し,常時起動に設定しておきます.

sudo systemctl start remote.autossh.service
sudo systemctl status remote.autossh.service

sudo systemctl enable remote.autossh.service

以上で完了です.お疲れ様でした.