SSHのホスト鍵設定
ホスト鍵とは
SSHの鍵はデジタル署名用の秘密鍵であり、本人確認に使われる。いわゆるid_rsa
は、ユーザー側の本人確認のために使われる。
一方、SSHサーバー側も専用の秘密鍵を所有している。これは /etc/ssh/ssh_host_{dsa,ecdsa,ed25519,rsa}_key
のような場所に保管されている。SSH接続の際には、これを使った公開鍵認証も行われる。クライアント側の .ssh/known_hosts
と照らし合わせてチェックする。
ホスト鍵がないと何が問題か
もし悪意ある第三者が通信を盗聴・改竄できる場合、偽のサーバーと通信させることができてしまう。すると、適切な暗号を用いて全くの別人と会話しているという本末転倒な状態になる。偽のサーバー上と気付かずにsudoパスワードを入れたら困ったことになるかもしれない。
HashKnownHostsをオフにする
筆者は、ホスト鍵を安全に運用するために、HashKnownHosts
をオフにするべきだと考えている。
そもそも HashKnownHosts
とは、 .ssh/known_hosts
においてホスト名をハッシュ化して保存するオプションである。ハッシュ化をしない場合、 known_hosts
の各行は以下のようになっている。
example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHayNTYAAAAIbmlzdHAyNTYAAABBBAHOh5LY0tU5hZGZn4iFvUQ9EJSGW7n9KbTXj5WK5AEIQNB5ShhNPwJcXqtc5hxwEmBX2VSdjUFkIT6U2Otur7w=
HashKnownHosts
を使うと、「ホスト名またはIPアドレス」「署名方式」「公開鍵」のうち、「ホスト名またはIPアドレス」の部分がハッシュ化され、
|1|tbdGjw+HE9Clw2hC7ezBLOMGFGI=|xOtpgqDyfDlT/PB7cYm442R1+zY= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHayNTYAAAAIbmlzdHAyNTYAAABBBAHOh5LY0tU5hZGZn4iFvUQ9EJSGW7n9KbTXj5WK5AEIQNB5ShhNPwJcXqtc5hxwEmBX2VSdjUFkIT6U2Otur7w=
のようになる(|1|ソルト|ハッシュ|
)。ハッシュ化することで、
- 特定のホスト名が、この行に該当するかどうかは判定できる。
- しかし、この行だけ見て、ホスト名を復元することは困難である。
となる。つまり、
HashKnownHosts
のメリット:known_hosts
が漏洩しても、接続先ホストの情報が復元できない。HashKnownHosts
のデメリット:known_hosts
の管理が困難になる。どのホストを信任しているかわからないため、偽のホストを信頼してしまう危険性が増える。
と考えられる。接続先ホストの情報は仮に漏れても大きな影響はなさそうだし、むしろ known_hosts
が漏洩するような状況では秘密鍵など他の重要な情報も漏れている状況だから、メリットがデメリットに釣り合わないと思う。
known_hosts
を管理する
ここでは、ホスト名のハッシュ化を止めた上で、 known_hosts
をきちんと管理することを考えたい。前述のとおり、 known_hosts
の基本フォーマットは
ホスト名またはIPアドレス 署名方式 公開鍵 (コメント)
である。また、 #
で始まる行もコメントである。
「ホスト名またはIPアドレス」の部分の詳細なフォーマットは以下の通り。
- 基本的には、
gitlab.com
とか52.167.219.168
のようにホスト名またはIPアドレスがそのまま使える。 - 22番以外のポートのときは、
[example.com]:60022
とか[192.0.2.23]:60022
のように[]
づけで表記する。 ,
で複数のホスト名またはIPアドレスを並べることができる。ホスト名とIPアドレスを並べてもよい。 (ハッシュ化していないときのみ)*
は0文字以上のワイルドカードとして使える。 (ハッシュ化していないときのみ)?
は1文字のワイルドカードとして使える。 (ハッシュ化していないときのみ)
例えば、GitHubとGitLabのための known_hosts
は以下のように書ける。
# GitHub -- marked CheckHostIP no github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== # GitLab gitlab.com,52.167.219.168 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com,52.167.219.168 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 gitlab.com,52.167.219.168 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
CheckHostIP
をオフにする
ホスト鍵は基本的に、接続しようとしたDNS名と照合される。しかし、 CheckHostIP
が有効の場合、IPアドレスに対しても照合が行われる。
普通、DNSの対応付けが変わっていても、接続先のサーバーが想定通りのホスト鍵を返せば信頼してもよいはずなので、 CheckHostIP
は予防的な意味合いが強いと思われる。特に、GitHubのようにDNSラウンドロビンを使っている場合は面倒なので、上記のワイルドカードを使うか、そもそも CheckHostIP
を外してしまうのがよいと思う。 (GitHubのIPアドレス一覧)
StrictHostKeyChecking
の有効化
想定していないホスト鍵が送られてきたとき、SSHは以下のように振る舞う。
- 別のホスト鍵を既に知っている場合、問答無用で接続拒否になる。オレオレ詐欺で言うところの「母ちゃん俺だよ、携帯番号変えたからさ」というやつである。どうしても接続するなら
known_hosts
を手動かコマンドでいじる必要がある。 - 未知のホストの場合
StrictHostKeyChecking yes
の場合: 接続拒否する。StrictHostKeyChecking no
の場合:known_hosts
に追加して続行する。StrictHostKeyChecking ask
の場合(デフォルト): ユーザーの答えに応じて上のどちらかの処理をする。
.ssh/config
に入っているホストにしか接続しないような生活であれば、どれもそれほど変わらないと思う。筆者は StrictHostKeyChecking yes
にしておき、新規ホストを追加したとき、そのホストに対して一時的に StrictHostKeyChecking ask
を付与している。
EC2への対処
EC2のように、同じIPアドレスのマシンを消したりまた立ち上げたりしていると、既知のホスト鍵との衝突でどうしても接続拒否になってしまう。せっかく known_hosts
をちゃんと管理しているので、テキストエディタで消してしまうとよいと思うが、ホスト鍵のチェックを強制的に省略する方法もあるにはある。
UpdateHostKeys
の有効化
UpdateHostKeys ask
とすると、ホスト鍵が更新されたときに、新しいホスト鍵を known_hosts
に追加することができる。(以前のホスト鍵で認証したあとで送られてくるので、問題はない。) サーバー側をうまく設定すれば、キーローテーションをすることもできる。
まとめと宣伝
known_hosts
はちゃんと管理することもできる。ちなみに known_hosts
と authorized_keys
を正しくハイライトするVimプラグインを作ったのでぜひ。