VPN の秘密鍵をどこに置くかは二つの問いで決まる。鍵素材をホストの外へコピーできるか、そして誰もキーボードにいない状態でプロセスが使えるかだ。ストアのマーケティング上の呼び名はどちらにも答えない。再起動後に戻ってくる必要のあるトンネルデーモンには無人利用が要り、人間が入力する PIN に縛られたものは除外される。

コピーと使用のどちらを選ぶか

コピーと使用は別の形で失敗する。だから一つの要件ではなく二つの要件として扱う。鍵のバイトを読める攻撃者は ID を別のホストへ持ち出し、元のマシンは気づかない。バイトは読めないが署名処理に到達できる攻撃者は、そのアクセスが続く限り認証を通してしまう。

ファイルの鍵はきわめて簡単にコピーできる。だからこそバックアップと復元も最も簡単だ。ソフトウェア鍵ストアは API を変えるが境界は変えない。プロバイダは自前のエクスポート呼び出しを拒むが、鍵を入れたのと同じ管理者コンテキストには通常ほかの経路がある。ソフトウェアプロバイダでの「エクスポート不可」は対応操作についての表明であり、ハードウェアの壁の証明ではない。気軽なコピーへの減速帯と見なし、すでにセッションを握っている相手への防御とは考えないこと。

TPM やスマートカードは署名操作をハードウェア内部で実行し、結果だけを返す。これでコピーの経路は閉じ、使用の経路は署名を要求できるものに開いたままになる。

ストアをトンネルデーモンに合わせる

デーモンはセキュリティポリシーよりも強くこれを制約する。WireGuard は base64 の秘密鍵をファイルか wg set の入力から取り、証明書ストアへの経路を持たない。だから TPM 裏付けのインターフェース鍵は選択肢にならない。OpenVPN を OpenSSL 3 に対してビルドしたものはプロバイダ URI 経由で鍵を読み込め、strongSwan は PKCS#11 対応と並んで TPM プラグインを同梱するが、どちらもパッケージのビルド方法に依存する。

選んだストアに届かないデーモンはハードウェア境界を飾りにする。誰かが鍵を一度エクスポートし、ファイルに残し、設計の残りはそのコピーの上で静かに動く。

更新は突き合わせのもう半分であり、ここでほとんどの設計が崩れる。初回登録では機能するが、再発行のたびにコンソールログインを要求するストアは、証明書が都合の悪い時刻に切れる最初の機会に迂回される。現在の鍵にまだ数か月あるうちに再発行の経路を試すこと。

移す前に鍵を棚卸しする

鍵が何であり、どこに住むかを変える前に記録する。subject alternative names を落とす移行は、ルーティング障害のように読める形でトンネルを壊す。証明書をダンプし、デーモンが待つ場所で秘密鍵が読めることを確認し、組が本当に一致するかを確かめる。

openssl x509 -in vpn.crt -noout -subject -ext subjectAltName
openssl pkey -in vpn.key -check -noout
openssl x509 -in vpn.crt -noout -pubkey | openssl sha256
openssl pkey -in vpn.key -pubout | openssl sha256

最後の二つのダイジェストは同一でなければならない。そうでなければデーモンは設定を終えたあと、真の原因の近くを指さない証明書または署名のエラーで毎回失敗する。WireGuard の同等はもっと短い。公開鍵は秘密鍵から直接導かれるからだ。wg pubkey < /etc/wireguard/wg0.key はサーバがすでに保持するピア鍵を出力しなければならない。

権限も同じ棚卸しに入る。stat -c '%a %U:%G' /etc/wireguard/wg0.key は 600 root:root を返すべきで、グループや全員が読めるなら、意図しなかったプロセスに鍵がすでに渡っていたことになる。

ストアと使用経路を確認する

検証は三つに分かれ、三つ目が飛ばされる。選んだストアに鍵があること、デーモンが残り物のコピーではなくその鍵を読んだこと、そしてエクスポート成果物が消えたあとも起動することを確認する。

certutil -store -user My
certutil -csp "Microsoft Platform Crypto Provider" -key -user
certutil -verifykeys -user My
ipsec listcerts

Windows では最初のコマンドが個人ストアを一覧し、各項目の横に鍵プロバイダを出す。ここにハードウェア裏付けに見えてソフトウェアプロバイダに座っている証明書が現れる。二つ目はプラットフォーム暗号プロバイダが持つ鍵を一覧するので、証明書はあるのに VPN の ID がそこに無いなら、秘密の半分は別の場所に住んでいる。Linux ゲートウェイでは ipsec listcerts が strongSwan の読み込み内容を、TPM プラグイン由来の鍵も含めて報告する。項目数に頼らず、指紋や公開鍵ハッシュを棚卸しと比べること。

負のテストが設計を証明する。エクスポートした鍵をデーモンの設定ディレクトリの外へ移し、サービスを再起動し、どの ID を提示するかをログで読む。それでも上がるトンネルはストアを使っており、起動に失敗するなら設計は本当にコピーで動いていた。

更新とロールバックを書き留める

ロールバックは二つの系統で大きく異なり、その差はインシデント対応の電話ではなく設計メモに属する。ファイル鍵は暗号化してバックアップし復元できるので、失敗した移行は巻き戻せる。エクスポートできない鍵はそもそもバックアップできず、装置が壊れたときの回復は再発行と再登録だけになる。

停止になる前に失効を確認する。openssl x509 -in vpn.crt -noout -checkend 2592000 は証明書が三十日以内に切れると非ゼロで終わるので、監視チェックにそのまま入る。この行を毎週走らせれば、誰も予定していなかった更新を捕まえられる。

削除はサーバ側で行う。ピアを消すかシリアル番号を取り消し、トンネルが落ちることを確認する。キャッシュされたセッションを持つクライアントは中途半端な失効をしばらく隠せるからだ。失効は CA データベースだけでなく、コンセントレータの CRL や OCSP の経路にも届かなければならない。証明書は公開文書であり、RFC 5280 のプロファイルがその検証方法を定めるが、その検証はローテーション前にコピーされた秘密鍵を守らない。

決定は一か所に書く。どのストアが鍵を保持し、どのプロセスが使ってよく、誰が再発行でき、ロールバックは何か。その段落こそ監査人が尋ねるものであり、担当者が変わっても残るものだ。

関連記事