Phase 1: Remote Attestation

概要

Remote Attestation(RA)では、TEE環境と実行内容を同時に検証します:

  • TEE環境の検証: AttesterとWorkerのMRENCLAVE/MRSIGNERを検証

  • 実行内容の検証: Work-IDにより関数、ユーザー権限、パラメータを検証

前提:ユーザーの実行状況

ユーザーは apc cleanroom deploy を実行済みです。

この時点で:

  • 計算実行サーバー上にWorkerコンテナが起動済み

  • TEE環境の検証はこれから実行

検証の対象

1. Attester(TEE内の常駐コンテナ)

  • Remote Attestation (RA) により検証

  • AttesterのMRENCLAVE/MRSIGNERをチェック

  • Attesterの検証により、TEE環境の正当性を確認

2. Worker(TEE内の実行環境)

  • Local Attestation (LA) でAttesterが検証済み

  • WorkerのMRENCLAVEはAttesterにハードコーディング済み

  • ユーザーはAttesterを信頼することでWorkerも信頼

Note

WorkerのMRENCLAVE検証は、Attesterが内部で行います。 ユーザーが直接Workerを検証するわけではありません。

Worker自体は実行内容(関数)に依らず同一のコンテナイメージであるため、 MRENCLAVEの値は固定です。この固定値をAttesterにハードコーディングすることで、 Attester起動時にWorkerのMRENCLAVEを検証できます。

3. 実行内容(関数、ユーザー、パラメータ)

  • Work-IDにより検証

  • Work-IDはQuoteに含まれ、RAと同時に検証される

なぜWork-ID検証が必要か

動的な情報をMRENCLAVEの対象外とした理由

RAではMRENCLAVE(初期状態のハッシュ値)を検証しますが、 MRENCLAVEは静的な値です。 実行関数の内容は含まれません。

動的な情報(実行関数、ユーザー権限、パラメータ)をMRENCLAVEの検証対象に含めることも技術的には可能ですが、 その場合、実行関数ごとにMRENCLAVEの値が変わるため、ユーザーは都度MRENCLAVEを計算する必要があります。 MRENCLAVEの計算は非常に複雑で大変な作業です。

そのため、本システムでは静的な部分と動的な部分を分けて検証する方針を採用しています:

  • 静的な部分 (MRENCLAVEで検証): AttesterとWorkerのコンテナ

  • 動的な部分 (Work-IDで検証): 実行関数、ユーザー権限、パラメータ

Work-IDの構成

Work-IDは以下の情報のハッシュ値であり、サーバー側で計算されます:

work_id = hash(function_id, user_ids, params, nonce)
  • function_id: 実行関数のハッシュ値

  • user_ids: 入出力データへのアクセスが許可されたユーザーID一覧

  • params: 実行パラメータ(encrypted-files.yamlの内容など)

  • nonce: リプレイ攻撃防止用(クリーンルームデプロイ時に生成)

Note

work_idはクリーンルームデプロイ時にサーバー側で計算され、クライアントに返されます。 クライアントはこのwork_idを使ってQuote検証を行います。

Remote Attestationのフロー

        sequenceDiagram
    participant Client as クライアント<br/>(APC CLI)
    participant Controller as Controller
    participant Attester as Attester<br/>(TEE内)
    participant Worker as Worker<br/>(TEE内)

    Note over Client,Worker: Workerは既にデプロイ済み

    rect rgb(230, 240, 255)
    Note over Client,Attester: 1. Worker署名用公開鍵の取得
    Client->>Controller: Worker公開鍵の取得を要求
    Controller->>Attester: Worker公開鍵を要求
    Note right of Attester: AttesterはLAで<br/>Workerを検証済み
    Attester->>Worker: Worker公開鍵を取得
    Worker-->>Attester: Worker公開鍵
    Attester-->>Controller: Worker公開鍵
    Controller-->>Client: Worker公開鍵を転送
    end

    rect rgb(240, 248, 255)
    Note over Client,Attester: 2. Quote生成と検証
    Client->>Controller: Quote生成を要求<br/>(work_idとnonceを含む)
    Controller->>Attester: Quote生成要求
    Note right of Attester: QuoteにWorker公開鍵、<br/>work_id、nonceをバインド
    Attester->>Attester: SGX Quote生成
    Attester-->>Controller: Quote
    Controller-->>Client: Quoteを転送
    Client->>Client: MAA経由でQuote検証
    Client->>Client: MRENCLAVE/MRSIGNER検証
    Client->>Client: Quote内のwork_idが<br/>期待値と一致するか確認
    end
    

検証内容の詳細

MRENCLAVE検証

Attesterの初期状態のハッシュ値です。

  • ユーザーが事前に計算した期待値と比較

  • 一致すれば、Attesterのコードが改ざんされていない

  • 静的な値 (実行関数の内容は含まれない)

MRSIGNER検証

Attesterの署名者です。

  • 期待する署名者(Acompany等)かを確認

Work-ID検証

実行内容の整合性を検証します。

検証手順

  1. work_idを取得: クリーンルームデプロイ時にサーバーから返される work_id を使用

  2. Quote取得: サーバーにwork_idを送信してQuoteを取得(Quote内にwork_idが含まれる)

  3. Quote検証: MAA経由でQuoteの署名を検証

  4. work_id確認: Quote内のwork_idが送信したものと一致するか確認

なぜWork-IDが必要か

  • パラメータの改ざん: function-idが同じでも、パラメータが変更される可能性

  • リプレイ攻撃: 過去の正当な要求を再送信される可能性

  • ユーザーなりすまし: 別のユーザーが実行を要求する可能性

Work-IDは、これら全ての情報を1つのハッシュ値にまとめます。

function-id検証

実行される関数が意図したものか検証します。

  • function-id: 関数のハッシュ値

  • デプロイ時に指定: apc cleanroom deploy --source <関数ディレクトリ>

  • Worker内で検証: 実行前にfunction-idと実際の関数を照合

ユーザー認証検証

認証の必要性

複数のユーザーがデータを共有する際、誰がどのデータにアクセスできるかを制御する必要があります。 例えば、ユーザーAの入力データにはユーザーAのみがアクセスでき、ユーザーBがなりすましてアクセスすることを防ぐ必要があります。

アクセス権限の定義

ユーザーは encrypted-files.yaml でアクセス可能なユーザーを定義します:

# encrypted-files.yaml
inputs:
  input_1: &user_a_id a4QGvPmFlDiVqf1_APi1KN5RWSOehhFIRAmkd64JaCY=
  input_2: &user_b_id 7WKyA8NxynAw2_v5ZIZnob4wD65mKoY7y7ifY4LL6VQ=

outputs:
  output_1: *user_a_id
  output_2: *user_b_id

input_1input_2 などのキーに対して、user_id(署名用公開鍵のハッシュ値)を指定します。 この定義は work_id に含まれるため、ユーザーはRemote Attestation時に検証できます。

user_idの仕組み

user_idは署名用公開鍵のハッシュ値です:

user_id = hash(signing_public_key)

なりすまし防止

他のユーザーがなりすましを試みても、以下の理由で失敗します:

  • user_idは公開鍵のハッシュ値なので、誰でも知ることができます

  • しかし、その公開鍵に対応する秘密鍵を持っていなければ署名を作成できません

  • 公開鍵のハッシュ値がuser_idと一致するような秘密鍵を作ることは暗号学の観点から現実的に非常に困難です

検証の流れ

Workerは実行前に以下を確認します:

  1. クライアントから送られた署名を、登録された公開鍵で検証

  2. 公開鍵からuser_idを計算

  3. user_idが encrypted-files.yaml で指定されたuser_idと一致するか確認

これにより、正しい秘密鍵を持つユーザーのみがデータにアクセスできます。

コンテナの再現性とMR values

AttesterとWorkerはコンテナとして実行されます。

MR valuesの特性

  • コンテナイメージで一意に決まる

  • 実行するマシン(VM)には依存しない

利点

  • 一度MR valuesを検証すれば、どのマシンでも有効

  • サービス提供者がVMを作り直しても再検証不要

  • ユーザーはコンテナの内容のみを信頼すればよい

これにより、インフラの変更に対してユーザーの検証作業が不要になります。

Local Attestation(内部処理)

AttesterとWorker間でLocal Attestation (LA) が行われます:

  1. Workerが起動時に公開鍵を生成

  2. WorkerがLAでAttesterに公開鍵を登録

  3. AttesterがWorkerのMRENCLAVEを検証

  4. 検証済みのWorkerの公開鍵をAttesterが保持

ユーザーはこのプロセスを意識する必要はありません。 AttesterがRA済み = Workerも検証済みです。

次のフェーズ

TEE環境と実行内容が検証されました。 次は Phase 2: 鍵交換とデータ送信 で安全な通信路を確立します。