ssh_configのIncludeでハマった話

こんにちは、エンジニアの @hanhan1978です。

OpenSSHのバージョン7.3以降だと、ssh_configにおいてIncludeオプションが利用できるのはご存知でしょうか?これを利用すると、ssh_configを複数に分割して利用することが可能になります。分割して何が嬉しいのかというと、例えば仕事で接続するサーバの接続情報を共通のconfigとして読み込むことが出来ます。

具体的な構成例でいうと、下記のように configcommon_config の2つを用意して、config から common_config を読み込むことが出来ます。

~/.ssh
├─ config
└─ common_config

configの中に、下記のようなIncludeオプションを記述するだけです。

Include ~/.ssh/common_config

ここからが本題なのですが、ssh_configの Includeオプションの仕様を正確に把握しておかないと、このIncludeが意図したように動作しないことがあります。

説明のための事前準備

config1config2の2つのファイルがあったとします。ファイルの中身はそれぞれ server1, server2の接続情報が書かれています。

  • config1の中身
Host server1
    HostName xx.xxxx.xx
    User somebody
    IdentityFile ~/.ssh/id_rsa_server1
  • config2の中身
Host server2
    HostName xx.xxxx.xx
    User somebody
    IdentityFile ~/.ssh/id_rsa_server2

上手くいかない設定例

例えば、config1からconfig2を読み込もうとして、下記のように記述すると意図した通りに動作しません。

Host server1
    HostName xx.xxxx.xx
    User somebody
    IdentityFile ~/.ssh/id_rsa_server1

Include ~/.ssh/config2

この状態で、server2にログインしようとすると、下記のようにエラーが出てしまいます。※ちなみにserver1へのログインは成功します。

$ ssh server2
ssh: Could not resolve hostname server2: nodename nor servname provided, or not known

上手くいかない理由

ssh_configのマニュアルには下記のような記述があります。

ssh_config(5) - Linux manual page

Include Include the specified configuration file(s). Multiple pathnames may be specified and each pathname may contain glob(3) wildcards and, for user configurations, shell-like ‘~’ references to user home directories. Files without absolute paths are assumed to be in ~/.ssh if included in a user configuration file or /etc/ssh if included from the system configuration file. Include directive may appear inside a Match or Host block to perform conditional inclusion.

簡単に解説するとIncludeは MatchやHostのblock内に書かれると、そのblock内にIncludeしたファイルの設定内容を取り込むと書かれています。

実際に読み込まれた設定内容は下記のようになっていたものと思います。※説明のためにインデントを使って表現しています。

Host server1
    HostName xx.xxxx.xx
    User somebody
    IdentityFile ~/.ssh/id_rsa_server1
    Host server2
    HostName xx.xxxx.xx
    User somebody
    IdentityFile ~/.ssh/id_rsa_server2

Includeしたconfig2の内容がHost server1 の設定として読み込まれてしまいます。かつ、Host, Hostname, IdentityFile, Userの設定は2回目の定義なので無視されてしまいます。

こうして、server1には接続出来るけど、server2にはログインできない設定になってしまいました。

上手くいく設定例

意図通りに動かすためには ~/.ssh/config の先頭に Includeオプションを持ってきます。これでconfig2の設定が意図したとおりに読み込まれます。

Include ~/.ssh/config2

Host server1
    HostName xx.xxxx.xx
    User somebody
    IdentityFile ~/.ssh/id_rsa_server1

まとめ

ssh_configのIncludeでハマったというタイトルですが、Includeの仕様を無視して使って失敗していただけですね。 Includeの仕様を上手に利用すれば、例えば一部の設定だけ共通化してHost内の共通設定として利用することも出来ますね。

それでは、皆様も楽しいconfig共通化ライフをお過ごし下さい!

おまけ

Includeは便利なのですが、実はbash_completionIncludeした設定内容を補完してくれません。

なので利用する際はbashをversion4以降にアップグレードした上でbash_completion2を利用すると、Includeした設定内容も補完対象にしてくれるので幸せになれます。