SSHを高速化:接続多重化でセッションをより速く

接続多重化を使用して、ほぼ瞬時のSSH接続を実現します。この包括的なガイドでは、重要なSSHクライアントディレクティブである`ControlMaster`、`ControlPath`、および強力な`ControlPersist`の設定方法を詳しく説明します。後続のセッションの認証オーバーヘッドを大幅に削減する、単一の永続的な「マスター」接続を確立する方法を学びます。グローバルおよびホスト固有の設定の実用的な例、確認テクニック、およびより高速なワークフローのための必須トラブルシューティングのヒントが含まれています。

SSHを高速化:接続多重化でセッションをより速く

SSH接続多重化を使用すると、2番目のコマンドが既存の認証済み接続を再利用できるため、繰り返しのSSHコマンドがはるかに高速に感じられます。ssh host uptimeを実行し、次にssh host df -hを実行し、さらに同じホストにscpでファイルを転送する場合、最初の接続のみが完全なハンドシェイクと認証パスを必要とします。

これは、多数の短いセッションを開く管理者、開発者、および自動化ツールにとって特に便利です。これは魔法ではなく、リモートコマンドの実行を高速化するものではありません。繰り返しのセットアップコストを排除するものです。

SSH接続のオーバーヘッドを理解する

デフォルトでは、すべての標準SSHセッションは新しいTCP接続を確立し、完全なハンドシェイクを実行します。このプロセスには以下が含まれます。

  1. 鍵交換: 共有秘密と暗号化アルゴリズムを決定します。
  2. 認証: ユーザー資格情報(パスワード、鍵ファイル、または2要素トークン)を検証します。
  3. セッションセットアップ: 端末またはコマンドチャネルを初期化します。

このセットアップコストは、近くのLANでは小さく、待ち時間の長いリンク、VPN、踏み台ホスト、またはハードウェアバックアップ鍵や多要素プロンプトを必要とするアカウントでは非常に顕著です。接続多重化は、マスター接続を開いたままにし、新しいセッションをそのマスター経由でルーティングすることで、その作業の多くを繰り返すことを回避します。

多重化の仕組み

接続多重化は、ローカルのUnixドメインソケット(ローカルマシン上のファイル)を使用して、マスターSSHプロセスと新しいスレーブプロセス間の通信を行います。

  • マスター接続: 最初に実行するSSHコマンドが永続的な接続を作成し、通信用のソケットをセットアップします。
  • 制御パス: 後続のセッションがマスターを確認して接続するために使用する、指定されたローカルファイルパス(ソケット)です。
  • 再利用される接続: 同じ実効ホスト、ユーザー、ポートをターゲットとする後続のSSHコマンドは、ローカルソケットを介してマスターに接続し、新しい完全なSSHセットアップを回避します。

主要な設定ディレクティブ

接続多重化を有効にするには、通常はユーザー固有の設定ファイル(~/.ssh/config)内でSSHクライアント設定を構成します。3つの重要なディレクティブは、ControlMasterControlPath、およびControlPersistです。

1. ControlMaster

このディレクティブは、SSHがマスター接続を作成しようとするか、既存のものを再利用しようとするかを指定します。

説明
no (デフォルト)標準の単一接続モード。
yes セッションをマスターにし、スレーブを待機させます。(現在は単独で使用されることはほとんどありません)。
auto 推奨設定。マスター接続が存在する場合はそれを再利用し、存在しない場合は新しいマスター接続を開始します。

ほとんどの設定では、ControlMaster autoが実用的なデフォルトです。

2. ControlPath

通信に使用されるUnixドメインソケットファイルへのパス。このパスは、リモートホスト、ユーザー、ポートの組み合わせごとに一意である必要があり、セッションが制御チャネルを混同しないようにします。

パス内で変数を使用すると、一意性が確保されます。

変数 説明
%r リモートユーザー名
%h リモートホスト名
%p リモートポート

ControlPathの例:

ControlPath ~/.ssh/sockets/%r@%h:%p

ヒント: これらのソケット用の専用ディレクトリを作成し(mkdir -p ~/.ssh/sockets)、安全なパーミッションを設定してください(chmod 700 ~/.ssh/sockets)。

3. ControlPersist

このディレクティブは、最初のコマンドが終了した後、マスター接続を開いたままにする時間を指定します。

ControlPersist(OpenSSH 5.6で導入)以前は、マスター接続は端末セッションにアタッチされたままである必要がありました。ControlPersistを使用すると、マスタープロセスはデタッチされ、バックグラウンドでアクティブなままになります。

説明
no 端末が閉じられるとすぐにマスター接続が閉じられます。
yes マスター接続は無期限に持続します(手動で閉じるか、システムが再起動されるまで)。
時間値 期間を指定します(例:5mは5分、1hは1時間)。この非アクティブ期間の後に接続が閉じられます。

一般的な作業セッションでは、ControlPersist 10mまたは15mに設定するのが妥当な開始点です。共有ワークステーションや機密性の高い踏み台ホストでは、より短い値を使用してください。

~/.ssh/configでの実用的な実装

以下は、SSHクライアント設定ファイルで多重化を設定する方法を示す例です。

例1: グローバル設定

この設定は、接続するすべてのリモートホストに接続多重化を適用します(標準ポート22で動作していると仮定)。

# すべてのホスト(*)の設定
Host *
    # 接続の再利用または開始を有効にする
    ControlMaster auto

    # 最後のセッションが閉じられた後、接続を15分間維持する
    ControlPersist 15m

    # ソケットパスを定義し、ユーザー、ホスト、ポートに基づいて一意性を確保する
    ControlPath ~/.ssh/sockets/%r@%h:%p

    # オプション:一部の低帯域幅リンクで有用ですが、常に高速になるとは限りません
    Compression yes

例2: ホスト固有の設定

多くの場合、多重化を頻繁にアクセスするホストまたはグループに制限する方が良い方法です。

# 'prod-*'に一致するホスト固有の設定
Host prod-*
    HostName %h.example.com
    ControlMaster auto
    ControlPersist 5m
    ControlPath ~/.ssh/sockets/%r@%h:%p

# 踏み台ホスト固有の設定(より長い持続時間が必要な場合があります)
Host jumpbox
    ControlMaster auto
    ControlPersist 1h
    ControlPath ~/.ssh/sockets/%r@%h:%p

使用法、確認、および管理

1. 速度向上の確認

timeコマンドを使用して、パフォーマンスの向上を簡単に確認できます。

最初の接続:

$ time ssh myhost exit

real    0m1.234s
user    0m0.045s
sys     0m0.015s

マスターが生きている間の後続の接続:

$ time ssh myhost exit

real    0m0.045s
user    0m0.005s
sys     0m0.003s

2. マスター接続の状態を確認する

マスター接続が確立されると、指定されたControlPathにソケットファイルが存在します。-O(制御オプション)フラグを使用して、接続の状態を確認できます。

# myhostへの接続がアクティブかどうかを確認する
ssh -O check myhost

成功した場合、出力はソケット接続が開いていることを確認します。

3. マスター接続を終了する

永続的なマスター接続をすぐに閉じる必要がある場合(認証資格情報が変更された場合や、新しい設定をテストする必要がある場合など)は、exit制御オプションを使用します。

# myhostへのマスター接続を終了する
ssh -O exit myhost

このコマンドは、マスタープロセスに正常にシャットダウンするように指示します。後続のセッションは、新しいマスター接続を作成する必要があります。

より安全なデフォルト設定

新しいOpenSSHクライアントでは、%C%r%h%pを手動で組み合わせるよりも、ControlPathトークンとして優れていることがよくあります。これは接続詳細のハッシュに展開され、長いUnixソケットパスやホスト名の扱いにくい文字を回避します。

Host *
    ControlMaster auto
    ControlPersist 10m
    ControlPath ~/.ssh/sockets/%C

ソケットパスの長さは重要です。Unixドメインソケットにはプラットフォーム固有の制限があるためです。~/.ssh/sockets/[email protected]:2222のような長いパスは、一部のシステムで失敗する可能性があります。制御パスが長すぎるというエラーが表示された場合は、%Cに切り替えてください。

また、この設定に依存する前に、ソケットディレクトリが存在することを確認してください。

mkdir -p ~/.ssh/sockets
chmod 700 ~/.ssh/sockets

多重化を避けるべき場合

すべての状況で盲目的に多重化を有効にしないでください。注意が必要ないくつかのケースを以下に示します。

  • アカウント権限の変更: セッション中にグループメンバーシップ、強制コマンド、またはサーバー側のアカウントポリシーが変更された場合、マスターが閉じられるまで、再利用された接続は新しい状態を反映しない可能性があります。
  • 踏み台ホストとジャンプホストのトラブルシューティング: 接続障害をテストするときは、各コマンドが新しいパスを作成することを確認するために、多重化を無効にしてください。
  • 機密性の高いホスト: 永続的なマスター接続は、ControlPersistが期限切れになるまで、ローカルアカウントから認証済みチャネルを利用可能に保ちます。これは通常、正しいパーミッションを持つ個人のワークステーションでは問題ありませんが、すべてのセキュリティポリシーに適合するとは限りません。

1つのコマンドに対しては、次のように再利用を無効にします。

ssh -o ControlMaster=no -o ControlPath=none user@host

自動化ツールでの多重化

Ansible、rsync、Git over SSH、およびデプロイスクリプトは、多くの場合多数の短いセッションを開くため、多重化の恩恵を受けることができます。特にAnsibleの場合、SSH引数は通常ansible.cfgにあります。

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=10m -o ControlPath=~/.ssh/sockets/%C

自動化がCIから実行される場合は、ランナーのライフサイクルについて考えてください。存続期間の短いCIジョブは、ジョブ後にワークスペースが消えるため、あまり恩恵を受けない可能性があります。存続期間の長いデプロイホストは大きな恩恵を受ける可能性がありますが、クリーンアップと予測可能なパーミッションも必要です。セキュリティへの影響を完全に理解し、プライベートサブディレクトリを使用しない限り、制御ソケットを/tmpなどの共有の誰でも書き込み可能なディレクトリに配置しないでください。

rsyncの場合、ワークフローで同じホストに対して複数の個別のrsyncまたはsshコマンドを実行する場合、多重化が最も役立ちます。

rsync -az ./release/ app@web01:/opt/app/releases/current/
ssh app@web01 'systemctl --user restart app'
ssh app@web01 'systemctl --user status app --no-pager'

最初のコマンドがマスターを開きます。次の2つのコマンドは、ホスト、ユーザー、ポート、および有効なSSHオプションが一致する場合、それを再利用できます。

古いソケット問題のデバッグ

マスター接続が切断された後もソケットファイルが残ることがあります。その場合、後続のSSHコマンドが制御ソケットへの接続に関するエラーを出力し、通常の接続にフォールバックするか、使用中のオプションによっては失敗する可能性があります。

まずマスターを確認します。

ssh -O check web01

失敗し、~/.ssh/socketsの下に古いソケットが見つかった場合は、その古いファイルを削除します。これが頻繁に発生する場合は、ワークステーションのスリープ、VPNの切断、またはネットワークの変更がマスター接続を切断していないか確認してください。不安定なネットワークでは、長期間存続するマスターよりも、短いControlPersistの方が適している場合があります。

デバッグ中にSSHにさらに詳細な情報を出力させることもできます。

ssh -vvv web01 exit

ControlPathmux_client、または既存のマスターに言及している行を探します。多重化が関係していることがわかったら、マスターを閉じてから、DNS、鍵、またはリモートSSHデーモンを非難する前に再テストしてください。

踏み台ホストとオプションマッチング

多重化は、有効なSSH宛先とオプションに関連付けられています。同じサーバーに直接接続する場合と、踏み台ホストを経由して接続する場合では、それらは必ずしも同じ制御接続ではありません。これは、あるコマンドがホストエイリアスを使用し、別のコマンドが異なるUserPortProxyJump、またはIDファイル設定で生のホスト名を使用する場合も同様です。

予測可能な再利用のために、実際の接続詳細を~/.ssh/configに配置し、どこでもエイリアスを使用します。

Host app-prod-1
    HostName 10.20.30.41
    User deploy
    ProxyJump bastion-prod
    IdentityFile ~/.ssh/prod_deploy
    ControlMaster auto
    ControlPersist 10m
    ControlPath ~/.ssh/sockets/%C

次に、ssh app-prod-1scp file app-prod-1:/tmp/、およびapp-prod-1に対する自動化を実行します。エイリアス、IPアドレス、および1回限りの-Jフラグを混在させると、コマンドが既存のマスターを再利用する必要があるかどうかを理解するのが難しくなります。

これが、チームがランブックで推奨されるホストエイリアスを文書化する必要がある理由でもあります。共有された規則により、デプロイ中に混乱を招く中途半端な再利用接続を防ぐことができます。

トラブルシューティングとベストプラクティス

ディレクトリとパーミッション

セキュリティは最も重要です。SSHによって作成されるソケットファイルには、接続に関するメタデータ(潜在的な制御コマンドを含む)が含まれています。ソケットディレクトリに制限されたパーミッションがあることを確認してください。

# ディレクトリが存在しない場合は作成する
mkdir -p ~/.ssh/sockets

# 厳格なパーミッションを設定する(所有者のみアクセス可能)
chmod 700 ~/.ssh/sockets

複数ユーザーの制御

同じホストに接続するために異なるユーザー名を使用する場合、ControlPath%r(リモートユーザー)変数により、user1@hostuser2@hostに対して個別のソケットが作成されるため、多重化は自動的にこれを処理します。

他のクライアントとの競合

SSHに依存する自動化スクリプトやツールを実行する場合は、同じ多重化設定を使用するか、必要に応じて明示的に無効にするように構成されていることを確認してください。スクリプトが新しい接続を確保する必要がある場合は、コマンドラインで非多重化動作を強制できます。

ssh -o ControlMaster=no user@host

SSH接続多重化は、頻繁にSSHを使用するユーザーにとって、最もシンプルな生活の質の向上の1つです。ControlMaster autoを設定し、一意で短いControlPathを使用し、適切なControlPersistを設定し、ssh -O check hostで確認します。トラブルシューティング中に接続の動作がおかしい場合は、ssh -O exit hostでマスターを閉じ、新しいセッションで再テストしてください。