著者:Aghiles Ait Messaoud(PhD)— iExecで働く研究ソフトウェアエンジニア。
はじめに
このシリーズのパート1では、Noxの信頼チェーンの基盤を確立しました。すなわち、起動時の検証によって、機密仮想マシン(CVM)が、既知のOSイメージと、アテステーション済みのIntel TDXハードウェア上で既知のアプリケーションスタックを起動していない限り、いかなる秘密情報も取得できないようにする仕組みです。ただし、その保証は起動時にプラットフォーム内部で強制されるため、それ自体では、後の時点で稼働中のNoxサービスが、アテステーションされたのとまったく同一のワークロードであることを、エンドユーザーや外部監査人が直接確認する手段は提供されません。
この文書はシリーズの第 2 部であり、そのギャップを埋めます。つまり、ランタイム・アテステーション、そして CVM のライフタイムのどの時点でも、ある Nox コンポーネントが、真正の Intel TDX Trust Domain(TD)内で期待されるコードを本当に動かしていることを、任意の当事者が検証できることです。 (i)稼働中の CVM からフレッシュな TDX クォートを要求すると何が得られ、その中身は何か;(ii)TDX フリート上で稼働中の CVM を発見し、そのクォートを公開するためにデプロイされるコンポーネント;(iii)このエビデンスを表面化させるエンドツーエンドのシーケンスとユーザ向けインタフェース;(iv)署名から、実際に実行された docker-compose に至るまでの、クォート検証のステップバイステップ手順、を説明します。
これはパート 1 で説明した TEE の基盤の上に直接構築されており、その範囲を、Runtime Attestation UI 経由で提供されるランタイム・アテステーションに意図的に限定します。信頼チェーンの残りのリンク(ソースコードのバインディングや、許可された測定のオンチェーン上のガバナンス)については、後続のパートで扱います。
本ドキュメントの残りは次のように整理されています。背景(Background)では、ランタイム・アテステーションとは何か、TDX クォートがどう構造化されているか、そして Nox が依存する 3 つのクォートフィールドを思い出します。アーキテクチャのデプロイメント(Architectural deployment)では、TDX サーバ周りにデプロイされるコンポーネントと、それらがやり取りするデータを説明します。参照環境(Reference environment)では、この記事が依拠するコンポーネントのバージョンを固定します。シーケンス図(Sequence Diagram)では、UI が稼働中の CVM を発見してアテステーションするまでのエンドツーエンドの流れを追跡します。ユーザインタフェースの紹介(User Interface Presentation)では、インタフェースと 3 つのアテステーションレベルを示します。Nox コンポーネントのアテステーション手順(Attestation steps of a Nox component)では、単一の CVM に適用される検証プロトコルを詳述します。最後に、今後の予定(Future Work)では、予定している改善点として、イメージの来歴、ユーザが供給するチャレンジ、追加のクォート検証者を概説します。
背景
このセクションでは、本ドキュメントが依拠して構築している概念を見直します。ランタイム・アテステーションとは何か、TDX クォートがどのように構造化されているか、そして Nox が依存する 3 つのクォートフィールド、すなわち report_data、RTMRs、それらに関連するイベントログです。
Runtime Attestation
ランタイム・アテステーションは、CVM のライフタイムのどの時点でも、要求に応じて任意のリモート当事者が、期待されるコードと設定を持つ Nox コンポーネントが、真正の Intel TDX Trust Domain(TD)内で本当に動作していることを検証できるようにする仕組みです。ブート時のアテステーション(パート 1 を参照)が、ハードウェアから dstack-OS までの信頼チェーンを確立するのに対し、ランタイム・アテステーションは、シンプルなチャレンジ—レスポンス・プロトコルを通じて、その信頼を外部ベリファイアへ公開します。
TDX クォート
TDX クォートは、プラットフォームの Quoting Enclave によって暗号学的に署名されて生成される構造体です。これは検証者が TD を信頼するために必要なエビデンスを持ち、Intel から用意されたアテステーション鍵で署名されているため、証明書チェーンを Intel の信頼の根までたどることで、誰でもその真正性を検証できます。Nox がランタイム・アテステーションのために依存する 3 つのフィールド(report_data、RTMRs、およびそれらに関連するイベントログ)を、以下に詳述します。
report_data
report_data は 64 バイトのフィールドで、その内容はワークロードによって完全に選択されます。TDX はそれを署名済みクォートへそのまま(逐語的に)コピーします。これにより、アプリケーションは任意のデータをハードウェアのアテステーションへバインドできます。一般的な用途は次の通りです:
鮮度/チャレンジ応答:Runtime Attestation UI が行うのと同様に、検証側が提供する nonce を埋め込み、クォートが要求に応じて生成されたことを証明します。
アイデンティティ・バインディング:公開鍵または TLS 証明書のハッシュ(RA-TLS の基礎。パート 1 を参照)を埋め込むことで、TD 内で確実にセキュアチャネルが終了していることを証明します。
ブロックチェーンのウォレットアドレスやアプリケーション状態のハッシュなど、他の証明。
Nox では UI がランダムなチャレンジを生成し、その値がクォートの report_data に正確に見つかることを期待します。
RTMRs
RTMR(Runtime Measurement Registers)は、TPM PCR の TDX における同等物です。直接書き込めない追記専用レジスタで、ハッシュチェーンを通じてのみ拡張されます。TD には 4 つがあり、dstack はそれぞれに明確な役割を割り当てます:
RTMR0: 仮想ハードウェア/ファームウェア環境。
RTMR1: Linux カーネル。
RTMR2: カーネルのコマンドラインと initrd。
RTMR3: アプリケーション固有の測定: app-id、os_image_hash、compose-hash、instance-id、key-provider。
TD の初期メモリ内容と構成は MRTD に別途記録されます。検証時には、RTMR0〜RTMR2(MRTD とともに)がブートチェーンの完全性をアテステーションし、RTMR3 が、期待されるアプリケーションコードと構成が実行中であることをアテステーションします。Nox では RTMR3 に注目します。これは、クォートを特定の Nox コンポーネントおよびその docker-compose に紐づけるためです。
イベントログ
RTMR 値は不透明なハッシュです。期待される測定が折り込まれているかをアテステーションしますが、それが何であったかは示しません。イベントログは、RTMR(実際には RTMR3)へ拡張された個々の測定イベントの、人間が読める記録です。各イベントは app-id、compose-hash、instance-id、key-provider のようなキー・バリュー測定であり、すべてのイベントは次の拡張式によってレジスタに折り込まれます:
RTMR3_new = SHA384(RTMR3_old || SHA384(event_log))
ベリファイアはこの式によりイベントログをリプレイし、再計算したレジスタを、署名されたクォート内の rt_mr3 値と比較します。一致すれば、個々のイベント値、特に os_image_hash と compose_hash は、CVM が実際に実行した OS イメージおよび docker-compose の忠実な表現として信頼できます。
アーキテクチャのデプロイメント
このセクションでは、Runtime Attestation UI を動作させるために TDX サーバ周りにデプロイされるコンポーネントを説明し、それらがやり取りするデータの形を示します。

Runtime Attestation UI を動作させるために、5 つの主要コンポーネントが連携します:
Runtime Attestation UI ポータル: ユーザが Runtime Attestation のプロセスを視覚化するためにアクセスするインタフェースです。この UI は iExec 側で既に https://trust.noxprotocol.io/ にデプロイ済みですが、ソースコード(https://github.com/iExec-Nox/nox-attestation-portal)を使って個人の PC で再ビルドし、デプロイすることもできます。UI は nox-cvms-exporter-aggregator を呼び出し、アクティブな CVM の一覧を取得します。さらに各 CVM について、直近で取得されたクォートと docker-compose も同時に取得します。アグリゲータ自体が各 CVM の dstack-quote-service に接続するため、UI は CVM に直接話しかけることはありません。
nox-cvms-exporter: dstack ハイパーバイザ(dstack-vmm)に接続して、ローカルの TDX マシン上のアクティブな CVM のリスト(それぞれの dstack-quote-service url)を収集し、それを nox-cvms-exporter-aggregator に送信するホストサービス。
nox-cvms-exporter-aggregator: 各個別の nox-cvms-exporter から受け取ったアクティブ CVM の一覧を集約する、Azure Kubernetes Service 上にデプロイされたサービスです。一覧にある各 CVM について、CVM dstack-quote-service に接続して、その新しいクォート(UI チャレンジにバインド)と docker-compose を取得し、エンリッチ済みリストを Runtime Attestation UI ポータルに返します。
Proof of Cloud trust server: Proof of Cloud のための iExec サーバ(http://github.com/proofofcloud/trust-server)。クォートがホワイトリストに登録された TDX マシンから発行されており、かつ取り消されていないかを確認します。Proof of Cloud のホワイトリスト化プロセスの詳細は、記事シリーズのパート I に記載されています。
Phala PCCS: コラテラル(TCB Infos、Intel の PCK 証明書、証明書失効リスト)を保存してクォート検証に用いるための、Phala ローカルキャッシュ。
参照環境
このセクションでは、Runtime Attestation UI に関わる各コンポーネントの正確なバージョンを固定し、記事の残りで説明される挙動を再現できるようにするとともに、これらのコンポーネントが進化した際に既知のベースラインと比較できるようにします。

シーケンス図
このセクションでは、Runtime Attestation UI が稼働中の CVM を発見し、それらをアテステーションするまでのエンドツーエンドの流れを追跡します。ポータルを開くところから、結果表示までです。

この図は、Runtime Attestation UI が TDX フリート全体で動作している Confidential VM(CVM)を発見し、それらをアテステーションする方法を説明しています。
ポータルを開く: ユーザは、iExec がホストするインスタンス https://trust.noxprotocol.io から直接開くか、ソースリポジトリを自分でビルドして起動します( (https://githu b.com/iExec-Nox/nox-attestation-portal ))。読み込み時に、UI は 1 つのランダムチャレンジ(32 バイト)を生成し、集めたクォートにそのチャレンジがバインドされていることが期待されます。
ディスカバリ要求: UI はアグリゲータの GET /cvms エンドポイントを呼び出し、そのチャレンジをクエリパラメータ (?challenge=...) として渡します。このパラメータは必須です。チャレンジは CVM に中継され、返されたクォートをバインドする必要があるためです。
エクスポータへの分岐(fan-out): 設定されたエクスポータ一覧の中にある各 TDX マシンについて、アグリゲータは GET {base_url}/cvms を呼び出します 並行して: この段階ではチャレンジは転送されません。チャレンジは後で、クォートを取得するときにのみ使用されます。
ローカル CVM 列挙: 各エクスポータはローカルの dstack-vmm(POST /prpc/Status?json)に問い合わせ、そのマシン上で動作している VM を一覧表示します。
VMM 応答: dstack-vmm は生の VM リストを返します。エクスポータは、ステータスが stopped/removed の VM を除外し、kms と dstack-gateway のシステム CVM を除外します。
エクスポータ応答: エクスポータは各 CVM の quote-service のベース URL を構築し、app_id ごとに CVM をグループ化して返します。各インスタンスには { instance_id, url, machine_id } が付与されます。
クォート要求(エンリッチ): アグリゲータは各インスタンスをその新しいクォートでエンリッチします。すべてのインスタンスについて、アグリゲータは CVM の quote-service に対して GET {url}/quote?data={challenge} を呼び出し、UI のチャレンジを中継して、返るクォートがそれにバインドされるようにします。
クォート応答: quote-service は { quote, event_log } を返します。UI は署名チェックにクォートが必要で、RTMR3 のリプレイにはイベントログが必要だからです。
マニフェスト要求: クォート要求と並行して、アグリゲータは同じ CVM の quote-service GET {url}/info を呼び出し、デプロイメント・マニフェストを取得します。
マニフェスト応答: quote-service はその /info ペイロードを返します。アグリゲータはそこから docker-compose マニフェスト(tcb_info.app_compose)を抽出します。
マージ & 応答:アグリゲータはエンリッチ済みインスタンスを app_id で再グループ化し、マージ済みリストを UI に返します。各インスタンスは { instance_id, machine_id, quote: { quote, event_log }, app_compose } を持つようになります。url フィールドはアグリゲータ内部に保持され、UI には一切公開されません。そのため、ブラウザは CVM に直接到達する方法を持ちません。以下の JSON ファイルは、nox-cvms-exporter-aggregator からアテステーション UI に送られる集約エントリの例を示します。
{
"app_id": "a1b2c3...",
"name": "nox-component-cvm",
"instances": [
{
"instance_id": "i-0abc123",
"machine_id": "Node 1",
"quote": {
"quote": "0x0400...", # TDX クォート(16進)
"event_log": [ ... ] # RTMR3 イベントログ
},
"app_compose": "..." # docker-compose(YAML)マニフェスト
},
{
"instance_id": "i-0def456",
"machine_id": "Node 2",
"quote": {
"quote": "0x0400...",
"event_log": [ ... ]
},
"app_compose": "..."
}
]
}
検証 & 表示:返ってきた各 CVM について、UI はローカルでアテステーションを検証し、結果とともに CVM を表示します。この検証プロトコルは、Nox コンポーネントのアテステーション手順セクションで詳述します。
ユーザインタフェースの表示
このセクションでは、Runtime Attestation UI と、ユーザに公開される 3 つのレベルのアテステーションを紹介します。

NOX で表示される Runtime Attestation UI · Chain of Trust https://trust.noxprotocol.io
上のスクリーンショットは Runtime Attestation UI を示しています。読み込み時、左側のパネルにはテストネットの TDX マシン上で動作する Nox コンポーネントが一覧表示され、それぞれがレプリカ数(例: nox-kms では 6)として注釈されています。このインタフェースは、Nox コンポーネントのアテステーションに 3 つのレベルを提供します:
完全検証: Verify all ボタンをクリックすると、すべての Nox コンポーネントのすべての CVM インスタンスが検証されます
.コンポーネント単位の検証: このレベルは、左側のパネルで Nox コンポーネントを選択した後に利用可能になります。Verify all をクリックすると、基盤となるマシンに関係なく、選択された Nox コンポーネントのすべての CVM インスタンスが検証されます。
インスタンス単位の検証: このレベルも、左側のパネルで Nox コンポーネントを選択すると利用可能になります。Verify をクリックすると、選択された Nox コンポーネントの特定のインスタンスのみが検証されます。
Nox コンポーネントのアテステーション手順
このセクションでは、単一の Nox コンポーネント CVM に適用される、ステップバイステップの検証プロトコルを詳述し、すべてのチェックに合格した後に UI が何を表示するかを説明します。

Nox コンポーネントの CVM に適用される検証プロトコルは次の通りです:
新しい見積もりを取得: そのUIはランダムなチャレンジを生成し、アグリゲータを通じて、そのチャレンジに紐づいた新しい引用符(クォート)を取得します(シーケンス図)。チャレンジは、クォートの report_data に埋め込まれていることが期待されます。
クォートの署名と証明書チェーンを確認: クォートの署名と、その証明書チェーンが Intel までの範囲で DCAP ベリファイアにより検証されます。現在の実装では、組み込みの Phala dcap-qvl(クォート検証ライブラリ: githubl)がブラウザ内でローカルに実行されます。qvl は検証用コラテラル(TCB 情報および Intel を起点とする証明書チェーン)を dstack PCCS(Phala がホストする Provisioning Certificate Caching Service)から取得し、同じく自分自身でチェックを実行します。並行して、クォートは Proof of Cloud trust server に送信され、このアテステーションされたマシンがホワイトリスト(認定済み)のクラウド・フリートに属するかどうかを報告します。この proof-of-cloud 結果は有益ですがブロッキングではありません。信頼サーバが利用不能、またはタイムアウトになった場合でも、アテステーションは継続されます。
クォートの鮮度を確認: ランダムに UI が生成したチャレンジがクォートの report_data に埋め込まれていることを検証することで、クォートの鮮度が確認されます。
RTMR 値を表示: 情報表示の手順で、クォートの RTMR 値を抽出して表示します。
RTMR3 をリプレイ: アグリゲータ応答と一緒に返されるイベントログ(event logs)を用いて、Intel の式に従い RTMR3 をリプレイします: RTMR3_new = SHA384(RTMR3_old || SHA384(event_log))。リプレイされた RTMR3 がクォート内のアテステーション対象と一致する場合、イベントログの os_image_hash と compose_hash は、実行された OS および docker-compose の代表として信頼できます。
OS イメージを確認: os_image_hash の RTMR3 イベントログを抽出し、必要に応じて画像とそのハッシュを手動で確認できるダウンロードリンクを提示します。iExec では、このイメージは dstackOS です。
compose-hash を確認: docker-compose(app_compose、アグリゲータ応答で提供されるもの)をハッシュ化し、その結果を RTMR3 イベントログとして埋め込まれている compose_hash と比較します。
これらの検証ステップが実行されると、アテステーションされた CVM の compose-hash に対応する docker-compose が、下の画像のように表示されます。

CVM の docker-compose には 3 つのサービスが含まれます:
nox-component: CVM 内で実行されるビジネスサービス(例: nox-kms)
quote-service: クォートと、CVM をアテステーションするために必要なイベントログを取得するために使われるサービス
fluent-bit: 内部観測用の iExec ログエクスポータサービス
今後の予定
このセクションでは、アテステーションフローの予定されている改善点(イメージの来歴、ユーザが供給するチャレンジ、追加のクォート検証者)を概説します。
イメージの来歴(プロビナンス)
現時点では、アテステーション対象の CVM 内で実行されたイメージを列挙している docker compose を表示した時点でアテステーションを停止します。次のステップとして、Sigstore 基盤を活用し、各イメージをビルドして生成した GitHub Actions ワークフローに署名を行い、その際にイメージの sha256 チェックサム(subject-name)で特定される SLSA(Supply-chain Levels for Software Artifacts)アテステーションを、GitHub とイメージの docker レジストリへ公開します。Rekor エントリも自然にプッシュされるでしょう。これにより、本記事で言及した検証ステップを拡張し、各 Nox イメージの来歴(つまりビルドワークフローと GitHub リポジトリのコミット)をアテステーションできるようになります。
ユーザ入力チャレンジ
現在、クォートの鮮度をテストするために、UI からクエリパラメータとしてアグリゲータに送られる自動生成チャレンジを使用し、アグリゲータがそれを各クォートサービスへ中継しています。このプロセスを強化し、UI ユーザが自分自身のチャレンジを入力できるようにして、クォートの鮮度にさらに信頼のレイヤを加えます。
複数のベリファイア
現在は、Phala qvl を唯一の検証手段として使用し、クォートの Intel 署名と証明書チェーンを確認しています。検証結果への信頼を高めるため、利用可能になり次第、追加の検証方法を(バックアップとして、または必須チェックとして)追加します。追加する可能性があるベリファイアは、iExec ホストの dstack-verifier と Intel Trust Authority です。

