それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

ssh の HashKnownHosts に追加する方法を知り、StrictHostKeyCheckingをちゃんと使えるようになる。

ssh の HashKnownHosts に追加する方法

HashKnownHosts を有効にしていると、 .ssh/known_hotss がハッシュ化される。

これにより、どのサーバーと通信していたか、関係性の秘匿が可能になる。

hash を使う known hosts のために嫌がらせなんじゃないかと最初は思うかもしれませんが、とても大事な機能です。

サーバーのホスト鍵の確認

takuya@:logs$ ssh-keygen -H -F github.com
# Host github.com found: line 15
|1|Xs0rgP4k....=|0a/5z/h...DE= ecdsa-sha2-nistp256 AAAAE2....U2w0WZ2YB/++Tpockg=

HashKnownHostsとはなにか。

いままでのknown_hosts は、ホスト名|鍵が確認されていた。しかし、これには接続履歴を見られるリスクが存在するので、HashKnownHostsを用いて、接続済みホスト名をハッシュ化し秘匿するようになった。

一部では嫌われるが、すでにデフォルトで有効になっている。付き合うしか無い。

なぜHashKnownHostsを使うのか

ディスクを盗難された場合を考えましょう。ディスク盗難により、ssh秘密鍵が危殆化します。known_hostsも漏洩します。するとどうでしょう、known_hostsが今すぐ使えるサーバーのリストに早変わりです。漏洩した秘密鍵をがknown_hostsに掲載されているので簡単に接続できてしまいますね。.bash_historyを探さなくても接続可能なサーバの一覧が入手できます。

known_hostsや.bash_historyからプライバシー情報がダダ漏れです。この対策のためにHashKnownHostsを使ってファイルから情報漏洩を予防するんだと思います。

HashKnownHostsはこのために、ホスト名・IP・ポートをハッシュ化してknown_hostsに書き込んで使います。

HashKnownHostsへのホスト鍵の追加

HashKnownHostsなので、指定のハッシュ化を通さないとknown_hostsを追加できません。それは次の方法で行います。

HashKnownHostsを追加する方法

 ssh-keyscan  -H github.com >> ~/.ssh/known_hosts

もしrsa 鍵だけでいいのなら ssh-keyscan -H -t rsa github.com

HashKnownHostsに存在を調べる。

known_hosts に存在するかかどうかを確認する。一致するホスト名があるかどうかハッシュ値を調べる。

ssh-keygenを使う。 ここまでで紹介した。ssh-keyscan とにているので間違わないように注意する。

ssh-keygen -H -F github.com

HashKnownHostsから削除する

HashKnownHostsにすると~/.ssh/known_hostsを開いて手作業で編集ができない。そのため専用コマンドを使う。

ssh-keygen -R github.com

ファイルを分割しているときは

ssh-keygen -R github.com -f /path/to/known_hosts

重複を防いだ登録

ホスト公開鍵を新規で登録して重複を防ぐ。

if ! ssh-keygen -H -F github.com > /dev/null ; then
     ssh-keyscan -H -t rsa github.com >> ~/.ssh/known_hosts
fi

もっと単純に

! ssh-keygen -H -F github.com > /dev/null || ssh-keyscan -H -t rsa github.com >> ~/.ssh/known_hosts

さらに関数に

function known_hosts_add(){
    ! ssh-keygen -H -F $1 > /dev/null || ssh-keyscan -H -t rsa $1 >> ~/.ssh/known_hosts
}

というわけで、known_hosts を管理する必要があります。

UserKnownHostsFile で、ホスト鍵ファイルを指定

known_hostsに書きすぎると自動化で困ります。そこでUserKnownHostsFileを使います。

冒頭に紹介した scan を使ってファイルを生成し、UserKnownHostsFileを使って接続します。

例えば次のようにします。

$ ssh-keyscan  -H github.com >> ~/known_hosts.github
$ ssh -o UserKnownHostsFile=~/known_hosts.github github.com

これは、.ssh/configに記載することもできます。

.ssh/config 例

Host github
   hostaname github.com
   UserKnownHostsFile ~/known_hosts.github, ~/.ssh/known_hosts

上記のようにknown_hostsを複数に分けてconfigに書いておくこともできます。

CI/CDなど自動化時にknown_hostsで困らないように

ssh接続で外部サーバーに操作するスクリプトを使って自動的デプロイ、cpuなどの稼働状況取得、CI/CDで自動化しているなどで困ります。ssh接続でKnownHostsに困らされると思います。ネットでみると StrictHostCheck をオフにしている人たちがかなりいます。

ちゃんと「鍵」を管理したほうが良いです。鍵は、セキュリティの基本なのです。もしssh -o StrictHostKeyChecking=noで済ませていると書いてあれば、その持ち主はMITMを許してくれる優しいエンジニアだと思います。意識高い系のQiitaの凄優しいエンジニア君たちです

もし、CI/CD でデプロイをするのなら、-o UserKnownHostsFile=/path/to/fileでちゃんとホスト公開鍵の鍵束を信頼できる一覧としてプロジェクトに含めるべきだと思います。

たとえば、trabvis-ci では、信頼できるホスト名をci.yamlに掲載する方法が紹介されています。gitlab-ci では SSH_KNOWN_HOSTS 変数を使って登録する方法が紹介されています。

known_hostsをちゃんと管理しないとだめですね

known_hostsを甘く見ちゃいけません。平文秘密鍵ファイルと一緒に配置したらあきまへん。平文鍵ファイルを使うならHashKnownHostsをオフにするのは危険です。StrictHostKeyCheckingをオフにするのはMITMを許すので盗聴にたいしてあまりに危険です。

CheckHostIP をつけると便利

DNSラウンドロビンをしてるとき、CheckHostIP=noをしておくと便利

~/.ssh/config

CheckHostIP=no

通常のknown_hostsの登録

ssh github.com 

これだと、github.comのIPが変わったときに再登録が必要になる。

なぜなら、ホスト名+IPアドレス+ポート をハッシュ化するからである。 f:id:takuya_1st:20220218150348p:plain

このようなことが起きないように、CheckHostIP=noにするか手作業でknown_hostsを作るのがいいと思う。

UpdateHostKeys

ホスト鍵が変わったときにyes/noで自動でYESを答える機能。ホスト鍵が変わる=MITMとも言えるので、この設定は控えたほうがいいかもしれない。

ただし、自分の管理化でローカルサーバーとかならいいかもしれない。つまり、ホスト毎の設定であれば書いて構わないだろうが、グルーバルには書くなってことです。

参考資料

SSHのホスト鍵設定 - 簡潔なQ

2022-02-18 追記

UpdateHostKeys/CheckHostIPについて追記。

# 2022/03/17

追記