はじめに
つい先日、GitHubのRSA SSHホスト鍵が突如差し替えられるという一件がありました。
詳細に関しては識者による解説に委ねますが、ちょうどタイムリーな話題だったので、SSHをより安全に利用するという観点でおすすめ設定についていくつか紹介します。
なお、クリアコードではSSH以外にもおすすめzsh設定やおすすめEmacs設定という記事も公開しているので参考にしてみてください。
2023年5月11日更新:StrictHostKeyChecking
をyes
にする場合の安全なknown_hosts
の更新方法について追記しました。
おすすめ設定について
クリアコードでは、.ssh/config
のおすすめ設定を https://gitlab.com/clear-code/ssh.d にて公開しています。
これは、社内で.ssh/config
の設定を見直してみようという機運が高まったことによります。
公開しているおすすめ.ssh/config
設定はあくまで雛形なので、利用者ごとの事情にあわせたカスタマイズが前提です。
ディレクトリ構成
$ tree .ssh
.
├── LICENSE
├── README.md
├── conf.d ユーザーごとのカスタマイズを配置する
│ └── template.conf # 設定のサンプル
├── config
└── global.conf # 汎用的なカスタマイズ内容
基本的に、利用者ごとの事情にあわせた設定ファイル(.conf)をconf.d
ディレクトリ配下に配置することを想定しています。
.ssh/config
からconf.d配下の.confファイルを読み込むようになっています。
特定のサイトやネットワーク環境向けの設定といったように、必要に応じてファイルを分割すると管理しやすくなってよいでしょう。
なお、SSHの.ssh/config
のルールとして、最初に見つけた設定が優先される挙動になっています。
ファイルの末尾のほうに追記したもので上書きされたりはしないので、個別の設定を(汎用的な設定の)前に記述する必要があります。1
global.conf
よりも先にconf.d/*.conf
をInclude
しているのはそのためです。
おすすめ設定項目
汎用的なカスタマイズ内容である、global.conf
に含めた項目について紹介します。
リスクやメリット・デメリットを勘案して適宜必要なものを取捨選択してみてください。
HashKnownHostsをyesにする
HashKnownHosts
のSSHの既定値はyes
となっています。
ホストへの接続を受け入れると.ssh/known_hosts
に記録されますが、その際の通信先をハッシュ化して通信先を秘匿化するということを意味します。
ハッシュ化されていない状態のほうが.ssh/known_hosts
の内容がすぐに確認できて便利と思うかもしれません。
しかし、~/.ssh
ディレクトリ配下がまるごと漏れた場合に、パスフレーズを設定していないSSHの鍵があれば、known_hosts
との組み合わせで
意図せずアクセスされてしまう可能性があります。
また、コマンドの履歴(.bash_history
など)を探すよりも楽に攻撃対象を特定できるという意味でもリスクがあります。
もし、HashKnownHosts
をno
にしてしまっているのなら、変更されることをおすすめします。
2023/4/4追記: HashKnownHosts
については、開発者のDamien さんが『I'd prefer to remove hostname hashing. 』と言っている と@haruyamaさんに教えて いただきました。開発者としては筋の良くないオプションであると考えているようです。代替としてObscureKnownHostnames
を導入してHashKnownHosts
を非推奨にした後、最終的に削除するという案への言及があります。すぐに使えなくなるわけではありませんが、将来的に移行が必要になるかもしれないことは認識しておいたほうがよさそうです。
PasswordAuthenticationをnoにする
PasswordAuthentication
のSSHの既定値はyes
となっています。
no
にすると、サーバー側がパスワード認証を有効にしていた場合でも、クライアント側で明示的にパスワード認証での接続を禁止できます。
yes
だと、うっかり誤ったサーバーに接続した際にパスワードを漏洩する可能性があるため、no
にすることをおすすめします。2
StrictHostKeyCheckingをyesにする
StrictHostKeyChecking
のSSHの既定値はask
となっています。
ask
のままだと、(DNS改ざんなど)意図しないサーバーに接続しにいってしまった場合であっても(利用者が)fingerprintをきちんと確認せず惰性で受理してしまう危険性があります。
yes
にすると、ホストキーを必ずチェックするようになり、ホストキーがknown_hosts
に登録されていない場合は接続を拒否するため、安全性が高まります。
ただし、StrictHostKeyChecking
をyes
にする場合、事前になんらかの手段でホスト鍵のfingerprintを取得して、known_hosts
に登録しておく必要があります。
例えば、いくつかのサイトではknown_hosts
のエントリを明示しています。
- GitHub: 冒頭で紹介した記事でされているように https://api.github.com/meta から取得できる
- GitLab: https://docs.gitlab.com/ee/user/gitlab_com/#ssh-known_hosts-entries で公開されている
- Debian: https://db.debian.org/debian_known_hosts で公開されている
WebサイトやWeb APIでknown_hosts
のエントリが明示されていない場合でも、ssh-keyscan
を使用すると、以下の要領でホスト鍵のfingerprintを取得できます。
$ ssh-keyscan gitlab.com
# gitlab.com:22 SSH-2.0-GitLab-SSHD
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
# gitlab.com:22 SSH-2.0-GitLab-SSHD
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
# gitlab.com:22 SSH-2.0-GitLab-SSHD
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
# gitlab.com:22 SSH-2.0-GitLab-SSHD
# gitlab.com:22 SSH-2.0-GitLab-SSHD
ただし、httpsのURLでアクセスするWebサイトやWeb APIでは得られた情報の真正性がTLSの仕組みによって担保される3のに対して、ssh-keyscan
ではそのような検証は行われないため、StrictHostKeyChecking
がask
の時と同様の危険性があります。
自分達で管理しているホストの場合には、セットアップ作業の過程などでホスト上でssh-keyscan localhost
を実行して得られた情報を控えておき、関係者間で安全な方法でknown_hosts
の情報を共有するようにするとよいでしょう。
そうでない場合は、異なるネットワークにいる人同士複数人でssh-keyscan
を実行して結果を突き合わせるなどして、結果の真正性を確かめる必要があります。
なお、StrictHostKeyChecking
をyes
にすると、頻繁にVMを作成・破棄することが多いケースではホストキーの再登録の手間が頻繁に生じます。
そのような場合には、利用者ごとの.confを使って次のようにパターンを明示して、VMに使用するホストをStrictHostKeyChecking
の対象から除外するとよいでしょう。
# 信頼できる192.168.1.*の範囲(宅内LANを想定)でホストキーの変更があればユーザーに問い合わせる設定例
Host 192.168.1.*
StrictHostKeyChecking ask
もしくは、ssh -o StrictHostKeyChecking=ask
で一時的にデフォルトのask
にして接続することもできます。
おわりに
今回は、おすすめ.ssh/config
設定について解説をまじえて紹介しました。
おすすめ設定とはいっても、単なる雛形でしかありません。 実際の利用においては個々のユースケースにあわせてカスタマイズが必要です。
また、一度設定すればそれで終わりではありません。 定期的により安全とされる内容に見直しすることも重要です。
もし秘伝のタレ化した.ssh/config
が手元にあるなら、これを機会に見直してみるのもいいかもしれません。
こんなおすすめ設定があるよ、というのがあればぜひMerge Requestを https://gitlab.com/clear-code/ssh.d に送ってください。
-
設定の優先順については、
man ssh_config
の冒頭に明記されています。 ↩ -
あえてパスワードで接続したい場合には、特定のホストでのみ許可するように.confの設定を追加するか、十分に信頼できる接続先のホストであれば
ssh -o PasswordAuthentication=yes
で一時的に有効化して接続するなどする必要があります。 ↩ -
WebブラウザーやWeb APIのクライアントは、httpsでの接続先のホストが本当にそのドメインの持ち主の物かどうかを証明書チェーンを使って検証した上で、ホストとの間で安全な経路で通信します。そのため、レスポンスとして得られた
known_hosts
のエントリは第三者によって改竄されていない正しい物であることが保証されます。 ↩