Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

イメージ署名

AWS Signer によるプローバーコンテナイメージの署名と実行前検証を解説します。

STARK 証明は「特定のゲストプログラムが正しく実行された」ことを保証しますが、そもそもそのゲストプログラムを含むコンテナイメージ自体が改ざんされていないことも保証する必要があります。イメージ署名は、信頼されたビルドパイプラインが生成したイメージのみが証明生成に使用されることを担保するセキュリティゲートです。

脅威モデル

イメージ署名が防止する攻撃シナリオを示します。

flowchart TD
  subgraph "署名なしの場合"
    A1["攻撃者が ECR イメージを<br/>改ざんしたものに置換"] --> B1["改ざんされたプローバーが<br/>不正な集計結果を生成"]
    B1 --> C1["不正な結果に対して<br/>有効な STARK 証明が存在"]
  end

  subgraph "署名ありの場合"
    A2["攻撃者が ECR イメージを<br/>改ざんしたものに置換"] --> B2["Step Functions が<br/>署名検証を実行"]
    B2 --> C2["署名不一致を検出<br/>タスク起動を拒否"]
  end

STARK 証明は Image ID(ゲストバイナリの暗号的識別子)に紐づきますが、イメージ署名はそれとは別のレイヤで「コンテナイメージ全体の完全性」を保証します。両者は相補的な防御を形成します。

保証の種類メカニズム検出対象
ゲストプログラムの同一性Image ID(RISC Zero)ゲストバイナリの改変
コンテナイメージの完全性AWS Signerイメージ全体の改変(ホスト含む)

署名フロー

ビルドと署名

CodeBuild がプローバーコンテナイメージをビルドして ECR に push し、Step Functions 実行時に署名ステータスを検証します。 ECR マネージド署名が有効な環境では、push 後に AWS Signer プロファイルに基づく署名ステータスが付与されます。

sequenceDiagram
  participant GH as GitHub
  participant CB as CodeBuild
  participant ECR as ECR
  participant SGN as AWS Signer

  GH->>CB: ソースコード取得
  CB->>CB: Docker イメージビルド<br/>(ARM64)
  CB->>ECR: イメージをプッシュ<br/>(ダイジェスト付き)
  ECR->>SGN: (ECR managed signing 有効時)署名処理
  SGN->>ECR: 署名ステータス更新
  Note over ECR: イメージ + 署名が<br/>一体で保存される

注: このリポジトリでコード化されているのは署名ステータス検証(DescribeImageSigningStatus)です。
署名付与そのもの(ECR managed signing の有効化)は、ECR 側の設定・運用が前提です。

ECR のイメージ URI は常にダイジェスト固定(@sha256:<64-hex>)で参照されます。タグベースの参照は使用しません。これにより、タグの上書きによるイメージのすり替えを防止します。

実行前検証

Step Functions ステートマシンの最初のステートで、check-image-signature Lambda がイメージの署名ステータスを検証します。

stateDiagram-v2
  [*] --> VerifyImageSignature: Step Functions 開始
  VerifyImageSignature --> CheckSignatureResult

  state CheckSignatureResult <<choice>>
  CheckSignatureResult --> RunProver: status = COMPLETE
  CheckSignatureResult --> SignatureFailed: status ≠ COMPLETE

  state SignatureFailed {
    [*] --> CallbackFailed: エラー情報を通知
  }

  state RunProver {
    [*] --> ECSTask: 署名検証済みイメージで実行
  }

check-image-signature Lambda は以下の処理を行います。

  1. ECR の DescribeImageSigningStatus API を呼び出す
  2. 指定されたリポジトリ名とイメージダイジェストに対する署名ステータスを取得
  3. 取得した statusCOMPLETE / それ以外)を Step Functions に返す

署名ステータスが COMPLETE でない場合、Step Functions の Choice ステートが FinalizeSignatureFailed に遷移し、コールバック Lambda に ImageSignatureVerificationFailed エラーを通知します。ECS タスクは一切起動されません。

ECR リポジトリとイメージ管理

リポジトリ構成

リポジトリ用途ライフサイクル
stark-ballot-simulator/zkvm-prover-{env}プローバーコンテナイメージ最新 10 イメージを保持
stark-ballot-simulator/risc0-toolchainRISC Zero ツールチェーンベースイメージ最新 5 イメージを保持

両リポジトリとも、プッシュ時の脆弱性スキャン(Scan on Push)が有効です。

ダイジェスト固定

Terraform の ecs_image_uri 変数には、ダイジェスト固定の URI のみが許可されます。バリデーションルールにより @sha256:<64-hex> 形式が強制されます。

Step Functions の定義に含まれるイメージダイジェストは、Terraform の変数から以下のように抽出されます。

  • リポジトリ名: URI の @ より前の部分からレジストリホストを除去
  • ダイジェスト: URI の @ より後の部分(sha256:...

この分解により、check-image-signature Lambda は正確なリポジトリとダイジェストの組み合わせで署名を検証できます。

ビルドパイプライン

CodeBuild プロジェクト

2 つの CodeBuild プロジェクトがイメージのビルドを担当します。

プロジェクトビルド対象タイムアウトインスタンス
stark-ballot-simulator-fargate-prover-{env}プローバーイメージ30 分ARM64 Small
stark-ballot-simulator-risc0-toolchain-builderベースイメージ120 分ARM64 Large

RISC Zero ツールチェーンのビルドは低頻度(ツールチェーンバージョン更新時のみ)ですが、ビルドに時間を要するため Large インスタンスと長いタイムアウトが設定されています。

CodeBuild の IAM 権限

CodeBuild ロールには以下の権限が付与されています。

権限カテゴリ対象 API目的
ECRGetAuthorizationToken, PutImageイメージのプッシュ
AWS SignerSignPayload, GetSigningProfile署名連携用の権限(運用/拡張時)
CloudWatch LogsCreateLogGroup, PutLogEventsビルドログの出力
S3GetObject, PutObjectビルドアーティファクト
CodeStar Connectionscodestar-connections:UseConnection, GetConnectionToken接続方式切り替えに備えた権限(現行 CodeBuild source は GITHUB

DS-202 準拠

本システムのイメージ署名アーキテクチャは、デジタル署名に関する DS-202 ガイドラインの以下の原則に準拠しています。

原則実装
署名の完全性AWS Signer による暗号学的署名
署名の検証可能性ECR の DescribeImageSigningStatus API による検証
実行前のゲートStep Functions の Choice ステートによる強制
不変な参照ダイジェスト固定によるイメージ URI
監査証跡CloudTrail + Step Functions 実行ログ

Image ID との関係

イメージ署名と Image ID は異なるレイヤのセキュリティメカニズムですが、共に「正しいプログラムが実行されたこと」の信頼チェーンを構成します。

flowchart TD
  subgraph "ビルド時"
    BUILD["コンテナイメージ<br/>ビルド"] --> SIGN["AWS Signer で<br/>イメージ署名"]
    BUILD --> IMGID["Image ID 計算<br/>(ゲストバイナリから導出)"]
    IMGID --> MAP["imageId-mapping.json<br/>に記録"]
  end

  subgraph "実行時"
    VERIFY_SIG["イメージ署名検証<br/>(Step Functions)"] --> RUN["プローバー実行"]
    RUN --> RECEIPT["レシート生成<br/>(Image ID を含む)"]
  end

  subgraph "検証時"
    RECEIPT --> VERIFY_RECEIPT["レシート検証<br/>(verifier-service)"]
    MAP --> VERIFY_RECEIPT
    VERIFY_RECEIPT --> MATCH{"Image ID<br/>一致?"}
  end

  SIGN --> VERIFY_SIG
検証ポイントタイミング検証主体失敗時の動作
イメージ署名証明生成前Step Functions + LambdaECS タスクの起動拒否
Image ID 照合検証時verifier-service検証失敗の報告