SSH証明書: より良いSSH体験
(jpmens.net)- SSH証明書は、従来の公開鍵ベースSSH認証の煩雑さを解消し、クライアントとサーバー間の自動信頼を提供する
- OpenSSH 5.4からサポートされており、CA(認証局) がユーザー鍵とホスト鍵に署名することで、
authorized_keysを修正せずに認証できる - 証明書には有効期限、許可ユーザー(principal)、アクセス元IP、強制コマンド(force-command) などを含められ、きめ細かなアクセス制御をサポートする
- TOFU(Trust on First Use) の手順が不要になり、ホスト鍵変更時も警告なしで安全に接続できる
- 自動署名サーバーやツールを活用すれば、大規模サーバー環境のSSH管理自動化とセキュリティ向上が可能
SSH証明書の概要と従来のSSH鍵ベース認証の限界
- SSH接続時には、初めて接続するサーバーのホスト鍵フィンガープリントを確認する必要があり、多くのユーザーはこれを検証せずに
yesを入力する TOFU(Trust on First Use) 方式を使っている- 管理者はサーバーのフィンガープリントを直接確認するか、
ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_keyコマンドで検証できる
- 管理者はサーバーのフィンガープリントを直接確認するか、
- 公開鍵ベース認証ではパスワードなしで接続できるが、各サーバーの
authorized_keysファイルに公開鍵を配布する必要がある - SSHエージェント(
ssh-agent)を使えば、秘密鍵をメモリに保存し、繰り返し入力せずに認証できる - 従来方式の限界
- ユーザーごとにサーバーへ公開鍵をコピーする必要がある
- ホスト鍵変更時にクライアント側で警告メッセージが発生する
- TOFUによる信頼管理の煩雑さ
SSH証明書と認証局(CA)
- SSH証明書(Certificate) はOpenSSH 5.4(2010年3月)からサポートされており、既存のSSH鍵フォーマットを拡張した構造
- SSH CAはSSH鍵ペアで構成され、公開鍵が信頼のルートとして機能する
- 主な利点
- サーバーの
authorized_keysファイルを修正する必要がない - ホスト鍵を置き換えても警告が出ない
- TOFU手順の排除により自動信頼を実現
- 証明書に許可ユーザー(principal)、許可IP、有効期限、強制コマンド(force-command) などを含められる
- 証明書の期限切れ時にアクセスを自動的に遮断できる
- サーバーの
SSH CAの構築と署名手順
- CAシステムでECDSAアルゴリズムを用いてCA鍵ペアを生成
ssh-keygen -t ecdsa -C "SSH CA" -f CA/ssh-ca
- ユーザーは自分の公開鍵(
*.pub)をCAに渡し、CAはそれに**署名(sign)**して証明書(*-cert.pub)を発行する- 例:
ssh-keygen -s CA/ssh-ca -I "Jane Jolie" -n jane -z 001 -V +1w jane.pub
- 例:
- サーバー構成
- CA公開鍵を
/etc/ssh/ssh-ca.pubに保存し、TrustedUserCAKeys設定を追加 - サーバーホスト鍵をCAで署名(
ssh-keygen -h -s CA/ssh-ca ...)し、HostCertificate項目に登録
- CA公開鍵を
- クライアント構成
known_hostsファイルに@cert-authorityを1行追加- 例:
@cert-authority *.example.com $(cat CA/ssh-ca.pub)
SSH証明書ベースの接続と検証
- ユーザーは署名済み証明書と秘密鍵を一緒に使って接続する(
ssh -i jane -l jane alice.example.com) - サーバーログには証明書のID、シリアル番号(serial)、CAフィンガープリントが記録される
- 複数のホスト名またはIPを証明書のprincipalとして追加できる
- 証明書で指定されたprincipal以外のユーザーとしてログインを試みると、
Certificate invalid: name is not a listed principalエラーが発生する - 証明書に強制コマンド(force-command) または 許可IP(source-address) を設定することで、きめ細かなアクセス制御が可能
点検とトラブルシューティングのチェックリスト
-
サーバー側の確認項目
TrustedUserCAKeys設定とCA公開鍵の存在- ホスト鍵への署名と
HostCertificateの指定 sshdの再起動が必要
-
クライアント側の確認項目
- ユーザー鍵がCAによって署名されている必要がある
known_hostsの@cert-authority項目とprincipalが一致している必要がある- 証明書の期限切れ時には
Certificate invalid: expiredメッセージが表示される - 証明書の制約条件が一致しない場合、パスワード入力が求められる
- SSHエージェントに証明書を追加すると、鍵と証明書の両方が登録される(
ssh-add jane) - 署名時のオプション(
-O)で機能を制御できる - 例:
-O clearですべての権限を削除した後、permit-agent-forwarding、permit-port-forwardingのみを許可
ホスト鍵証明書の自動化
- Pythonモジュール sshkey-tools とBottlePyを使って自動署名サーバー(hkbot) を実装
- CAサーバーで
hkbot.pyを実行した後、HTTPリクエストでホスト公開鍵をアップロードすると自動署名される - クライアントでは
curl -F hostkey=@/etc/ssh/ssh_host_ed25519_key.pub http://CA:8870 | shコマンドで自動インストール /etc/ssh/sshd_configを修正して検証後、systemctl restart sshdで適用
- CAサーバーで
- 以後のSSH接続では、証明書ベースで自動信頼とログインが可能になる
SSH証明書の利点まとめ
- TOFU不要、クライアントとサーバー間の自動信頼
- 短期有効証明書の発行により一時的なアクセス制御が可能
- 証明書の期限切れ時にアクセスを自動遮断でき、
authorized_keysの整理が不要 - 強制コマンド、PTY制限、アクセス元IP制御 などのきめ細かなポリシー設定が可能
- 自動化ツールにより大規模サーバー環境の管理簡素化が可能
- 関連プロジェクトとして Smallstep SSH を紹介
追加参考資料
更新
- SSH CAは自前のサーバーを保有し、root権限がある環境で特に有用
- マルチユーザーシステムでは、既存の
known_hostsおよびauthorized_keys方式が依然として必要 - SSH証明書フォーマット標準化ドラフト:
draft-miller-ssh-cert-06
1件のコメント
Hacker Newsの意見
いまだにSSHパスワードを使っている人がいるのは驚き
特に大企業の環境では複数のパスワードポリシーが絡み合っていて、単にサーバーへ接続するだけでも時間がかかる
そのため ssh-keygen で鍵を使うよう案内しても、ほとんどは「そのうちやろう」と言って結局やらない
しかし現実には 1 つの共通鍵を複数サーバーで使ったり、鍵を共有したりして、管理がすぐにぐちゃぐちゃになりがち
パスワードには少なくとも単純だという利点がある
パスワードはないが、ログイン時に物理的に Yubikey に触れる必要がある
数か月おきに誰かがまたSSH証明書を発見してブログ記事を書く
私も 15 年前に関連記事を書いたが、今見ると不十分だった
セキュリティエンジニアでさえ、SSH 証明書ではなく鍵認証を使っていることを忘れがちだ
複数サーバーの鍵を手作業で管理するのがあまりに面倒だ
今からでも移行する価値があるか悩んでいる
TOFU(Trust On First Use) 方式は単純だが、かなり通用する
自分のサーバーではホスト鍵を直接確認したら、それで十分だ
大企業環境では、内部サーバーの公開鍵一覧を SSL で署名された社内サイトに載せておけばよい
しかしサーバー数が多い、または頻繁に入れ替わる環境では証明書のほうがはるかに優れており、TOFU には多くの面で限界がある
ブラウザにもサーバーの TLS 鍵が変わったときに知らせる機能があればよいのにと思う
ほとんどはただ "yes" と入力して先へ進む
会社ではZscaler の SSL 検査のせいで時間と金を大量に無駄にしている
"self-signed certificate in certificate chain" エラーが出ると、いつも頭痛の種だ
独自のルート証明書を仕込み、ブラウザ設定をロックしてプロキシを使えなくする
Firefox や Chrome の設定ファイルを修正しても即座に上書きされる
しかも GUI から無効化するには IT のパスワードが必要だ
Cybereason のアンチウイルスより少しましな程度だ
HTTP ベースのプロトコルをすべて壊す
Git、RubyGems、go mod、Nix など数多くのツールが壊れる
ベンダーは「透過的」だと言うが、実際にはまったくそうではない
問題の診断に何時間もかかり、ほとんどの管理者はこうした破壊力を理解していない
記事では CA 証明書の利点しか触れられていなかったが、欠点も確かに存在する
私は TOFU に起因するセキュリティ問題を経験したことがない
SSH 証明書の欠点があるなら、具体的にどの点なのか知りたい
セキュリティを強化したいなら、USB など安全なチャネルで公開鍵を交換すればよい
証明書を使っても結局は同じ手順を踏む必要があり、ただ管理主体がユーザー側から管理者側へ移るだけだ
大規模組織では証明書が有用な場合もあるが、一般的な安全性は同じだ
インストールスクリプトや配布イメージに含めればよい
TOFU に意味があるのは、すでにセットアップ済みのマシンへアクセスするときだけだ
うちの dev/stg 環境では毎日マシンの半分を再インストールしている
SSH ホスト証明書のおかげで known_hosts を消したり鍵を維持したりする必要がなく、ずっと楽だ
個人プロジェクトとしてSshifuというツールを作っている
SSH 証明書ベースのログインとSSOを簡単にするツールだ
サーバーに sshifu-server をインストールして CA として使い、各 SSH サーバーはこの CA を信頼するよう設定する
ユーザーは
npx sshifuコマンドでログインすれば終わりだGitHub リポジトリを参照してほしい
実運用環境では証明書ベースのアクセスが複雑な運用管理の問題につながる
証明書の期限切れ、ユーザー削除、サーバー障害時のログインなど、さまざまな問題が発生する
Userify では 15 年にわたりこうした問題を扱ってきたが、安定した SSH 認証基盤を作るのは決して簡単ではない
pico.sh に SSH 証明書サポートを追加したが、RBAC スタイルのアクセス制御を実装できて非常に便利だった
ドキュメントリンクを参照
プロダクションでは SSH 証明書がむしろ複雑さを中央集権化して問題を大きくする
単一の CA が常時利用可能でなければならず、障害時には全体のアクセスが止まる
TTL の調整、信頼ルートの管理、デバッグの難しさなど、現実的な問題も多い
結局、人々はキャッシュやエージェントを再導入する
私たちは逆に、各ノードが HTTPS でユーザー情報をローカルの authorized_keysに同期するようにしている
こうすれば中央制御は維持しつつ、障害は局所化される
Userify ではこの方式を採用しており、認証だけでなく権限管理まで扱う
証明書だけではユーザー作成、sudo ロール、ホームディレクトリの整理といった問題は解決できない