9月7日、Oxide Computerが「301 - Has anybody seen my keys?: A key-hierarchy strategy for rack-level security」と題した記事を公開した。ラック単位のセキュリティを実現するための鍵階層設計と、ラック秘密鍵のローテーション戦略を詳細に解説したものだ。
暗号鍵のローテーションは「古い鍵を新しい鍵に置き換えるだけ」に聞こえるが、分散システムでは話がまったく違う。切り替えのタイミングがノードによってズレれば、一部のデータは旧鍵でしか復号できなくなる。かといって切り替えを「準備」した後にコミットが取り消されれば、鍵が宙ぶらりんになる。この「準備したが使われなかった鍵」をどう扱うか——そこがOxide Computerの設計の核心だ。
Oxide ComputerとRFDという設計文書
Oxide Computerは、クラウドインフラをオンプレミスで運用したい企業向けに、ハードウェアからソフトウェアまで一貫して設計・製造するスタートアップだ。2024年から実機の出荷を開始しており、ハードウェアとソフトウェアの垂直統合モデルによって、既存のクラウドベンダーとは異なるアプローチでセキュリティを実装できる点が注目されている。
同社は設計上の意思決定を「RFD(Request for Discussion)」と呼ばれる公開文書として公開しており、今回の記事もその一つ(RFD 301)である。ハードウェアとソフトウェアを自社で握るからこそ踏み込める、ラックという物理単位でのセキュリティ設計が読み取れる内容となっている。
ラック秘密鍵を起点とした鍵階層
Oxide Computerのラックでは、ラック秘密鍵(Rack Secret)を頂点とした鍵階層が構築されている。この秘密鍵は、Shamir秘密分散などで分割された複数の鍵シェアを集めることで再計算され、システム内で利用されるすべての子鍵の起点となる。
子鍵を生成する手段は2つある。
- 鍵導出(Key Derivation): ラック秘密鍵から直接派生させる方法。派生した鍵をディスクに保存する必要がない点が利点だが、親鍵がローテーションされると派生した全ての子鍵も変わる。
- 鍵ラッピング(Key Wrapping): 鍵を別の鍵で暗号化して保存する方法。ラッパー鍵がローテーションされても下位の鍵(実際のデータ暗号化鍵)は変わらなくてよいため、大量のストレージデータを再暗号化せずに済む。ZFS上のU.2ドライブ暗号化に適しているが、暗号化された鍵をどこかに保存・複製する必要がある。
設計上の要件と3つの厄介な制約
このシステムが達成しようとしているセキュリティ目標は以下のとおりだ。
- ラック秘密鍵からできる限り鍵を導出し、保存される鍵の数を減らす
- 秘密鍵の漏洩に備え、ラック秘密鍵のローテーションを可能にする
- U.2ドライブごとに固有の暗号化鍵を使い、1つが漏洩しても他に影響しないようにする
- 再構成(Reconfiguration)後、新たに追加されたsled(ラックに挿入されるサーバーモジュール)が、共有されていない旧データにアクセスできないようにする
これらを実現するうえで立ちはだかる制約が3つある。第一に、U.2ドライブのZFSラッパー鍵を切り替えるには、旧鍵と新鍵を同時に把握している状態が必要になる。第二に、分散システムの性質上、全sledが新しい再構成のコミットを同時に知ることができない。第三に、新しい再構成が「準備(prepare)」フェーズで止まり、コミットされないケースがある。ZFSラッパー鍵を即座に切り替えてしまうと、コミットされなかった場合に鍵が復元不能になる。
エポック単位の再構成と旧秘密鍵の保護
この問題を解決するため、各構成には単調増加するエポック番号が振られる。
エポック2への再構成が発生した場合、鍵の配布を担うディーラー(dealer)が以下の手順を踏む。
- エポック1の鍵シェアを十分数集め、エポック1のラック秘密鍵を再計算する。
- エポック2用の新しいラック秘密鍵を生成し、シェアに分割する。
- エポック2のラック秘密鍵から
old-rack-secret暗号化鍵を導出し、エポック1のラック秘密鍵をこの鍵で暗号化する。 - 暗号化されたエポック1の秘密鍵を、新しいグループのsledに「prepare」メッセージとともに送付する。
ここで重要なのは、エポック2がコミットされるまでは、暗号化されたエポック1の秘密鍵を復号できないという点だ。エポック2のシェアが揃わなければ old-rack-secret 鍵を導出できないからである。エポック2が永遠にコミットされなければ、旧秘密鍵も復号されないまま保護され続ける。
エポック2のコミットが確認されたsledは、新しいシェアを集めてエポック2のラック秘密鍵を復元し、old-rack-secret 鍵でエポック1の秘密鍵を復号する。これにより旧・新それぞれのU.2暗号化鍵を導出してZFS暗号化の設定を切り替え、切り替え完了後に旧エポックの暗号化済み秘密鍵を安全に削除する。
「準備したが使われなかった鍵」問題をどう封じるか
この設計が解決している本質的な問題は、分散システムにおける「準備したが使われなかった鍵」の管理だ。2フェーズコミットプロトコル(prepare → commit の2段階で合意を確定する分散トランザクション手法)と鍵のエポック管理を組み合わせることで、コミット前には旧秘密鍵を復号する手段が存在せず、コミット後には旧秘密鍵への依存を安全に断ち切れる構造になっている。詳細な2フェーズコミットの設計はRFD 238で解説されている。
悪意あるsledがある時点でラック秘密鍵を入手して保存していたとしても、再構成によって新しいラック秘密鍵が生成されれば、それ以降に書き込まれるデータは保護される。漏洩したsledを取り除くことで被害の拡大を食い止められる設計だ。ハードウェアを自社設計するOxide Computerだからこそ実装できる、ラックという物理単位でのセキュリティ境界の考え方が色濃く表れている。
詳細は301 - Has anybody seen my keys?: A key-hierarchy strategy for rack-level securityを参照していただきたい。