2026年 OpenSSH(.ssh/config) の書き方を見直す

Summary

2026年も始まりました。
年末は仕事に追われ、年越し後からようやくおやすみになりました。。

はじめに

OpenSSH, Win32-OpenSSH があるが Version で進化してきた。簡単ではあるがまとめる。

OpenSSH 機能対応バージョン

機能対応バージョンリリース日
ed255196.52014-01
ProxyJump (-J)7.32016-08-01
ControlPath %C6.72014-10
Include (ssh_config)7.32016-08-01
Include (sshd_config)8.22020-02-14
IdentityFile .pub指定不明 (古くから対応)-

機能対応マトリクス

OSOpenSSH versioned25519ProxyJump%CInclude
Ubuntu 14.046.6XXX
Ubuntu 16.047.2XX
Ubuntu 18.047.6
Ubuntu 20.048.2
Ubuntu 22.048.9
Ubuntu 24.049.6
CentOS/RHEL 54.3XXXX
CentOS/RHEL 65.3XXXX
CentOS/RHEL 77.4
RHEL 88.0
RHEL 98.7
Windows 11 22H28.6
Windows 11 23H29.4
Windows 11 24H29.5
Windows 11 25H29.8

OS とデフォルトバージョンのリストを見ると、現在主要な OS は ed25519 鍵に対応しているし、 OpenSSH 7.3 (Ubuntu 18.04, CentOS 7, Windows 11 22H2)以上であれば、今回紹介する方法は実現できる。のでどれか一つでも試してみましょう。

ファイル構造

複数の端末を使う場合、 dotfiles にして Git で管理することになる。
この場合管理対象が増えてくると構造化して案件やプロジェクトが終了したら ~/.ssh/conf.d/nodes/ の設定ファイルで Include をやめるか conf.old のように名前を変えれば接続先には出ず、不用意にアクセスすることを防止するが設定は保管しておくことができる。(結構、廃止したプロジェクトでも過去のアクセス情報を探すのに ssh/config を確認するケースは多い)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ tree ~/.ssh
~/.ssh
├── conf.d                                conf はすべてここに入れる
│   ├── cm                                ControlPath が入るフォルダー
│   ├── envs                              実際の Host conf を入れるフォルダー
│   │   └── org                           組織としてフォルダーにする
│   │       ├── dev-0.conf.old                廃止済みファイル
│   │       └── dev-1.conf                    実際の環境名で設定ファイル
│   │
│   └── nodes                             端末ごとに設定をまとめる
│   │   ├── _commons.conf                     デフォルト設定を入れるファイル
│   │   └── linux.localhost.conf              各 node で使う設定をまとめたファイル
│   │                                         これを ~/.ssh/config で Include すれば設定が終わる
│   │
│   └── template.conf                     テンプレートファイル、よく使う設定をまとめておく
│── keys                                  鍵を保管する場所
│   └── private
│   │   └── naa0yama@tmp.pem
│   └── public
│       └── naa0yama@github.pem
└── config                                Include で nodes のファイルを参照させる

envs

~/.ssh/conf.d/envs/ は各環境ごとの実際の Host 設定を格納する。
これを分けておくことで、ファイル内では Host * するなど共通の設定を末尾にまとめて書くことが出来、見通しがよくなり、大量の書く場合も User user1 のように普段と違うユーザーにしている箇所などがわかりやすくなる。

~/.ssh/conf.d/envs/org/dev-1.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# - ----------------------------------------------------------------------------
# - Hosts
# - ----------------------------------------------------------------------------
# - options                             parameters
Host org.dev.bastion
    HostName                            bastion.example.com

Host org.dev.bastion-in-node1
    HostName                            192.0.2.1
    ProxyJump                           org.dev.bastion


# - ----------------------------------------------------------------------------
# - Defaults
# - ----------------------------------------------------------------------------
# - options                             parameters
Host org.dev.*
    User                                naaoyama
    IdentitiesOnly                      yes
    IdentityFile                        ~/.ssh/keys/public/org_dev.pem
    Port                                22

この例では、

  • Host は <org>.<envs>.<hostname> の命名を採用する。
    • こうすることでファイル末尾に Host org.dev.* 汎用設定をまとめることが可能記述自体がスッキリする。
  • ProxyJump を利用することで、 ProxyCommand を覚えてなくても bastion 経由のアクセスを定義できるし TOKEN を覚える必要がないので認知負荷も少ない。

nodes

~/.ssh/conf.d/nodes/_commons.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# - ----------------------------------------------------------------------------
# - Commons
# - ----------------------------------------------------------------------------
# - options                             parameters
Host *
# Authentication
    # SSH 接続時に使用した秘密鍵を自動的に ssh-agent に追加
    # ssh-agent に登録することでパスフレーズの入力を省略できる
    # 時間指定も可能(30分後に自動削除)
    # AddKeysToAgent                    30m

    # サーバーがホスト鍵を更新した場合、known_hosts を自動更新
    # 鍵ローテーション時に手動で known_hosts を編集する必要がなくなる
    # ask = 確認プロンプトを表示
    UpdateHostKeys                      yes

    # 認証方法の試行順序を指定
    # 不要な方法をスキップして接続が速くなる
    # 公開鍵 → キーボードインタラクティブ → パスワード
    PreferredAuthentications            publickey,keyboard-interactive,password

    # IdentityFile で指定した鍵のみを試行
    # ssh-agent に大量の鍵がある場合、全部試すと "Too many authentication failures" になる
    # IdentitiesOnly                    yes

    # Kerberos 認証で認証を試行するか
    GSSAPIAuthentication                no

# Control
    ControlMaster                       auto
    ControlPath                         ~/.ssh/conf.d/cm/mux-%C.sock
    ControlPersist                      30m

# Keepalive
    ConnectTimeout                      5
    ConnectionAttempts                  3
    ServerAliveInterval                 50
    ServerAliveCountMax                 5

_commons.conf はどの接続にも設定した汎用的なデフォルト設定をすべて記載するファイル。
これをしておくことで envs 配下に複数に同じ設定を書かずに済む。

~/.ssh/conf.d/nodes/linux.localhost.conf
1
2
3
4
5
6
7
8
# - ----------------------------------------------------------------------------
# - Node
# - ----------------------------------------------------------------------------
# - options                     parameters
Include                         conf.d/nodes/_commons.conf


Include                         conf.d/envs/org/*.conf

linux.localhost.conf は Include のみの記載に済ませることをおすすめする。
ssh/config の仕様として ~/.ssh からの相対パスのため conf.d/ から始まるのは覚えておこう

linux.localhost.conf は私の terminal では複数環境で環境固有の設定を読み込む場合に下記のコマンド結果を shell 変数として保持しており、つなげた名前のファイルを動的に読み込むことで行っているのでその名残である。自身がわかる名前であれば良いと思う。

1
2
3
4
$ uname | tr '[:upper:]' '[:lower:]'
linux
$ hostname | cut -d . -f 1 | tr '[:upper:]' '[:lower:]'
localhost

keys

言わずのがなだろうが、簡単に。
SSH 秘密鍵はできれば Yubikey や Windows Hello などの ed25519-sk を使うのが一番良いと個人的には思うが実態としてまだまだ ssh-agent の利用は普及してないため、、鍵の保管場所を定めて使いやすくするのが目的である。

1
2
3
4
5
6
7
$ tree ~/.ssh
~/.ssh
└── keys                                  鍵を保管する場所
    └── private
    │   └── naa0yama@tmp.pem
    └── public
        └── naa0yama@github.pem

トピックとして ssh-agent を利用している場合でも agent に登録されている鍵が5個以上になると世の中の sshd では認証失敗になるケースがある。そもそも ssh 時には鍵を順番に送付してしまうためセキュリティ的にも良くない。

Topic
そこで設定すべきなのが IdentitiesOnly yesIdentityFile である。
IdentitiesOnly を設定することで IdentityFile に合致する鍵のみで認証するようになる。
IdentityFile は普段は秘密鍵を設定するが、前述の通り公開鍵を指定することでも動作する、これを使うと ssh-agent に 10個とか鍵があっても適切な鍵のみを Target に送信するためセキュアで認証失敗になることもない。

~/.ssh/config

今までの設定が済んでいれば、 nodes 配下にある該当の conf を Include に1行書けば設定が終わる

~/.ssh/config
1
Include conf.d/nodes/linux.localhost.conf

ドキュメント

AddKeysToAgent

AddKeysToAgentIdentityFile で指定した鍵を指定時間だけ ssh-agent に登録できる。パスフレーズを設定している鍵は登録されることで入力が省略され利便が上がる。が、秘密鍵を適切に管理していればすでに ssh-agent やパスワード管理ツールで保管して ssh-agent で利用しているだろうから効能は薄い。 30m のよう指定すると30分後に ssh-agent から削除される

1
2
3
4
Host example
    AddKeysToAgent 30m
    IdentitiesOnly yes
    IdentityFile ~/.ssh/id_rsa_nopass

Control*

ControlMaster, ControlPersist, ControlPath シリーズ。

  • ControlMaster

    • SSH 接続を多重化して認証を簡略化したり高速化する
    • no (defualt): 通常の独立した接続として動作
    • auto: マスター接続を使おうとするが、存在しない場合は新規作成
  • ControlPath

    • 接続共有に使用するコントロールソケットのパスを指定
  • ControlPersist

    • 最初のクライアント接続終了後もマスター接続を維持する期間を指定
    • no (default): 最初のクライアント接続が閉じると即座にマスター接続も閉じる
    • 秒数 または時間形式: 指定した時間アイドル状態が続いた後に自動終了

利便よく使いたい場合は下記がおすすめ、 ControlPath の設定がミソで OpenSSH6.7 から %C を使うことで %l%h%p%r%j のハッシュを取るこれを取ることで従来の mux-%r@%h:%p.sock のような呪文を書かずに済む。また踏み台ホストが増えて path が長くなって使えなくなる事象も発生しないので無難に利用するべき。

  • %l: ドメイン名を含むローカルホスト名
  • %h: リモートホスト名
  • %p: リモートポート番号
  • %r: リモートユーザー名
  • %j: ProxyJumpオプションの内容(未設定なら空文字列)
1
2
3
4
Host *
    ControlMaster   auto
    ControlPath     ~/.ssh/conf.d/cm/mux-%C.sock
    ControlPersist  30m
Hugo で構築されています。
テーマ StackJimmy によって設計されています。