LinuxでのSSH認証局(CA)構築:authorized_keysをやめて集中アクセス管理を実現する

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

アクセスモデルの比較:静的キー vs 集中型SSH CA

50台以上のLinuxサーバーにまたがって生のSSH鍵を管理するのは、運用上の悪夢です。想像してみてください。新しいエンジニアが入社した際、Ansibleを使って何十台もの仮想マシンに彼らの公開鍵を配布します。そして半年後、そのエンジニアが退職しました。すべてのステージング環境、バックアップ対象、レガシーサーバーから確実にその鍵が削除されたか誰かが確認したでしょうか? ほとんどの場合は放置されます。

一般的なアプローチの比較は以下の通りです:

  • authorized_keysの乱立: 各ノードが~/.ssh/authorized_keys内に各開発者の公開鍵の個別コピーを保持します。25人のエンジニアが80台のマシンにアクセスする場合、2,000件もの公開鍵エントリをやりくりすることになります。もし個人のノートPCが侵害された場合、即座にサーバー群全体に対してクリーンアップ用のPlaybookを実行しなければなりません。
  • LDAPやPAMディレクトリ統合: SSHハンドシェイク中に、ノードがFreeIPAやActive Directoryなどの外部IDプロバイダーへ問い合わせを行います。アクセス制御は一元化されるものの、厳格なネットワーク依存関係が生じます。LDAPノードがダウンしたり、ファイアウォールルールが壊れたりすると、管理者が緊急復旧用シェルから締め出されるリスクがあります。
  • OpenSSH認証局(SSH CA): 個々のクライアント鍵を追跡する代わりに、対象ホストは単一のオフラインCA公開鍵を信頼します。クライアントはCAに対してローカルの公開鍵への署名を要求します。引き換えに、明示的なユーザー名が埋め込まれた、特定の有効期間(例えば8時間)を持つ署名済み証明書を受け取ります。対象ノードは外部ネットワークへの問い合わせを行うことなく、この暗号署名をローカルで10ミリ秒未満で検証します。

SSH CAのメリットとデメリット

メリット

  • オフボーディング時にホストの変更が不要: チームからメンバーが離脱した際、対象サーバー側で作業を行う必要は一切ありません。単にそのメンバーの鍵への署名を停止するだけです。既存の証明書が有効期限を迎えると、アクセス権は自動的に失効します。
  • 短時間のアクセスウィンドウ: 通常の勤務シフトをカバーできるよう、証明書の有効期間を8時間などに制限して発行できます。エンジニアが暗号化されていない秘密鍵を紛失・盗難されたノートPCに残してしまった場合でも、攻撃者がそれを悪用する前に認証情報は失効します。
  • 厳密な権限境界: 対象アカウント(例: deploy、ubuntu、postgres)、送信元IP範囲、強制実行コマンドなどを署名の中に直接埋め込むことができます。
  • ネイティブなオフライン検証: OpenSSHは標準機能の暗号処理を用いてすべてを単独で処理します。対象サーバー側でサードパーティのデーモンプロセスやバックグラウンドエージェントを常駐させる必要はありません。

トレードオフ

  • CA署名鍵の重要度が極めて高い: 攻撃者にプライベートCA鍵を盗まれると、インフラ全体に対する有効なrootアクセス権限を偽造される危険があります。オフラインで保管するか、アクセスを厳重に制限するか、YubiKeyなどのハードウェアトークンで保護してください。
  • 大規模環境では発行インフラが必要: ssh-keygenを使った手動での証明書署名は、5〜10名程度の小規模管理者チームであればうまく機能します。それ以上の規模に拡大する場合は、HashiCorp Vault、Smallstep Step-CA、Teleportなどの自動発行ゲートウェイの導入が必要になります。

アーキテクチャの概要

本番環境におけるSSH CAの構成は、3つの明確な役割に基づいています:

  1. CAホスト: 隔離・要塞化されたワークステーションまたはオフラインの踏み台サーバー。このマシンが秘密署名鍵(ssh_user_ca)を保持し、公開鍵(ssh_user_ca.pub)を公開します。
  2. 対象サーバー: インフラ内のすべての本番ホスト。各サーバーのsshd_configでssh_user_ca.pubを参照するように設定します。
  3. クライアント: ローカルで標準的なed25519鍵を生成し、証明書署名を要求して、生成されたid_ed25519-cert.pubを用いて認証を行うエンジニア。

鉄則: SSHデーモンの設定を変更する際は、アクティブなtmuxセッション内でバックアップ用のrootターミナルを開いたままにしておいてください。設定ディレクティブの記述を誤った場合でも、そのアクティブなシェルがあれば本番環境からの締め出しを防ぐことができます。

ステップ・バイ・ステップの実装手順

ステップ 1: CAキーペアの生成

専用の署名用ホストで以下のコマンドを実行します。この秘密鍵を汎用サーバー上に配置してはいけません:

# CA用の安全なディレクトリを作成
sudo mkdir -p /etc/ssh/ca
sudo chmod 700 /etc/ssh/ca
cd /etc/ssh/ca

# 強固なパスフレーズを指定してルートCAキーペアを生成
sudo ssh-keygen -t ed25519 -C "prod-ssh-user-ca" -f ssh_user_ca

# 厳格なファイルパーミッションを設定
sudo chmod 600 /etc/ssh/ca/ssh_user_ca
sudo chmod 644 /etc/ssh/ca/ssh_user_ca.pub

ステップ 2: CAを信頼するよう対象サーバーを設定

ssh_user_ca.pubを各サーバーにコピーし、/etc/ssh/trusted-user-ca-keys.pubとして保存します:

# CA公開鍵を対象ノードにコピー
sudo tee /etc/ssh/trusted-user-ca-keys.pub <<'EOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPEXAMPLEKEY1234567890 prod-ssh-user-ca
EOF

sudo chmod 644 /etc/ssh/trusted-user-ca-keys.pub

次に、このCAによって署名された有効な証明書を受け入れるようsshdに指示します。/etc/ssh/sshd_config.d/ca.confに設定ファイルを作成します(または/etc/ssh/sshd_configを編集します):

TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pub
AuthorizedPrincipalsFile none

適用する前に構文チェックを実施してください。設定ディレクティブに不備があると、SSHポートが応答しなくなる恐れがあります:

# 設定の構文を検証
sudo sshd -t

# エラーがなければsshdを正常にリロード
sudo systemctl reload sshd

ステップ 3: ユーザーへの署名済み証明書の発行

エンジニアは自身のローカルPC上で標準的なed25519キーペアを生成します:

# クライアントPC上で実行
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519

エンジニアはid_ed25519.pubのみをCA管理者に送付します。CAホスト側で、適切なプリンシパルと短い有効期間を指定して公開鍵に署名します:

# CAマシン上で公開鍵に署名
ssh-keygen -s /etc/ssh/ca/ssh_user_ca \
  -I alex-laptop \
  -n ubuntu,deploy \
  -V +8h \
  -z 2026110501 \
  id_ed25519.pub

各フラグの役割は以下の通りです:

  • -s /etc/ssh/ca/ssh_user_ca: CA秘密鍵へのパス。
  • -I alex-laptop: 識別用のKey ID。ログイン時に対象サーバーの/var/log/auth.logへ直接記録されます。
  • -n ubuntu,deploy: この証明書でログイン可能な具体的なLinuxアカウント。ジュニア開発者がrootとしてログインするのを防ぎます。
  • -V +8h: 証明書の有効期間。この例では発行から8時間で失効します。絶対時刻(例: 20261105090000:20261105170000)での指定も可能です。
  • -z 2026110501: 追跡および監査用の一意なシリアル番号。

このコマンドにより、id_ed25519-cert.pubという名前の署名済み証明書が生成されます。

ステップ 4: 証明書を使用した接続

id_ed25519-cert.pubをエンジニアに返却します。エンジニアはそれを秘密鍵と同じ~/.ssh/ディレクトリに配置します。

証明書のペイロードを確認し、権限や残りの有効期間をチェックします:

ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub

証明書に埋め込まれたメタデータが表示されます:

Type: [email protected] user certificate
Public key: ED25519-CERT SHA256:7vQ... 
Signing CA: ED25519 SHA256:4kM... (prod-ssh-user-ca)
Key ID: "alex-laptop"
Serial: 2026110501
Valid: from 2026-11-05T08:30:00 to 2026-11-05T16:30:00
Principals: 
        ubuntu
        deploy
Critical Options: (none)
Extensions: 
        permit-pty
        permit-user-rc

証明書のファイル名が秘密鍵名と対応しているため(id_ed25519とid_ed25519-cert.pub)、OpenSSHクライアントはこれを自動的に読み込みます:

ssh -v [email protected]

詳細ログを確認すると、Server accepts key: ... [Certificate]と出力されているのが確認できます。リモートサーバーの~/.ssh/authorized_keysファイルが空であったりロックされていたりしても、ログインに成功します。

ステップ 5: 有効期限前の証明書失効

万が一エンジニアが昼休み中にノートPCを紛失した場合でも、8時間の有効期限が切れるのを待つ必要はありません。OpenSSHの鍵失効リスト(KRL: Key Revocation List)を使用して証明書を失効させます。

# CAホスト上でシリアル番号2026110501の証明書を失効
ssh-keygen -k -f /etc/ssh/revoked-keys -s /etc/ssh/ca/ssh_user_ca.pub -z 2026110501

生成された/etc/ssh/revoked-keysファイルをサーバー群に配布し、sshdにその場所を指定します:

# /etc/ssh/sshd_config.d/ca.conf に追加
RevocationFile /etc/ssh/revoked-keys

sudo systemctl reload sshdでサービスをリロードします。対象サーバーは、失効したシリアル番号が提示された接続を即座に切断・拒否します。

Share: