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 へ入る

本番環境(main)では、利用者はページを開くときも投票するときも同じ公開ホスト名へ接続し、Cloudflare を経由して CloudFront へ入ります。CloudFront は静的ファイルを S3 から配信し、/api/* の要求を API Gateway へ転送します。S3 への読み取りは CloudFront の OAC(Origin Access Control)で許可し、バケットを直接公開しません。ブラウザは保存先のバケットや内部のワーカーを選びません。

flowchart TB
  B["ブラウザ"] --> F["Cloudflare"]
  F -->|本番の入口認証| C["CloudFront"]
  C -->|ページ・静的ファイル| S["非公開S3"]
  C -->|/api/*| G["API Gateway"]
  G --> A["public-api Lambda"]

拡張子のない画面URLは index.html へ解決し、その後の画面遷移を React Router が処理します。API Gateway の先では、Hono がルート定義に従ってハンドラーを呼び出します。外部向けのパスと応答形式は packages/api-contract/src/routes/inventory.ts が定義し、apps/api/src/server/api/routes/definitions.ts が実行環境へ接続します。

入口の許可と一票の許可

本番の経路には二つの認証があります。CloudFront は、ページ・静的ファイル・API のいずれでも、公開ホスト名と Cloudflare が付ける専用トークンを確認し、入口の迂回を拒否します。トークンはハッシュで照合し、転送前に取り除きます。さらに CloudFront は API へ専用の origin-verification header を付け、API はその値が欠落・不一致なら拒否します。API Gateway の直接URLも、この確認を通過しなければ利用できません。

利用者の IP も、この認証済み経路を前提に扱います。CloudFront は単一の CF-Connecting-IP があり、形式条件を満たすことを確認します。API は TRUSTED_PROXY=cloudflare でその値を有効な IPv4 / IPv6 アドレスとして検証し、欠落・不正な値を別の転送ヘッダーやプロキシの IP で補いません。

main では公開セッションの作成時に、サーバーで Turnstile を検証します。token がない場合、検証に失敗した場合、用途やホスト名が一致しない場合は作成しません。

開発環境(develop)は Cloudflare を経由せず、CloudFront の署名付き Cookie で運用者向けに入口を制限します。対象はページ、静的ファイル、/api、/api/* です。CloudFront へ登録するのは公開鍵だけで、署名用の秘密鍵は KMS 内に残ります。この Cookie による制限は main にはありません。

どちらの環境でも、特定のセッションを操作する権限は別に確かめます。セッションに属する API は、URL の sessionId と X-Session-Capability を照合します。入口を通過しても、別の人のセッションを操作できるわけではありません。各ルートでは、必要な capability、Turnstile、レート制限、入力検証を定められた順序で適用します。

証拠のダウンロードにも同じセッション権限が必要です。「公開可能なバンドル」は再配布できる内容の分類であり、保存バケットを誰でも読めるという意味ではありません。ブラウザと CLI は capability で保護された API から取得し、S3 の直接URLや署名付きURLを通常の取得経路にしません。具体的な配布条件は公開境界に定義しています。

実行環境を一組で選ぶ

ローカルで画面を試すときに本物の証明生成を待つ必要はありません。ただし、模擬証拠を AWS の証明と取り違えないように、保存方式や証明方式を独立したフラグで混ぜず、実行プロファイルを一つ選びます。

サーバーは RUNTIME_PROFILE、ブラウザのビルドは VITE_RUNTIME_PROFILE を使います。サーバーはアダプターを作る前に選択を解決し、保存先、証明方式、集計方式、証拠配信、レート制限、Turnstile の設定を一組として検証・固定します。

プロファイル保存先証明の種類集計・証拠保存
local-demoメモリ模擬証拠同期・ローカル。ブラウザの模擬APIで画面を試す
static-mock-e2eファイル模擬証拠同期・ローカル。静的ビルドと Hono で E2E を行う
local-proof-developmentメモリ開発用の偽レシート同期・ローカル。Rust host との接続を確かめる
local-proof-productionメモリ本物の STARK 証明同期・ローカル
target-aws-asyncDynamoDB本物の STARK 証明非同期・S3
target-aws-async-quiescedDynamoDB本物の STARK 証明非同期・S3。develop の復旧時に新規公開セッションを拒否する

AWS 用プロファイルは DynamoDB、S3、非同期処理、DynamoDB のレート制限、Turnstile の迂回禁止をまとめて選びます。模擬証拠や開発用レシートへ切り替えることはできません。休止用の target-aws-async-quiesced はサーバー専用で、ブラウザには対応する値を公開しません。復旧時のキュー消費停止は、停止して復旧先を切り替える手順で明示的に制御します。

AWS のデプロイ先は RUNTIME_DEPLOYMENT_ENV=develop|main で指定し、アカウント、リージョン、テーブル、キューなどの識別子を別途検証します。秘密値はプロファイルへ直接渡さず、許可された参照先から解決します。参照を解決する処理も、最初に確定したアカウント・リージョン・環境に固定されます。

REST Gateway の入力境界

リポジトリの構成は Regional REST API と live stage を使います。CloudFront が stage を origin path に加えるため、公開 URL は変わりません。共有 request schema から生成したモデルで、投票、finalization 作成・cancel、verification 開始・観測の POST 本文を Lambda より先に検査します。session 作成の本文省略は維持します。 Gateway の拒否は capability 認証を済ませた証拠ではなく、本文と認証が両方不正なら 400 が先になる場合があります。Hono の認証・本文上限・意味の検証は残ります。

相関には利用者が上書きできない extendedRequestId を使い、ログには resource template と固定分類だけを記録します。共通 CloudWatch role は App から変更しません。 JSON 本文をバイナリ扱いしないよう binary media type は指定せず、応答には Lambda の レスポンスストリーミングを使います。Hono の応答を元の bytes に戻して送るため、ZIP は Accept の順序に依存しません。artifact の読み出し上限は維持し、API cache は無効です。 モデル拒否、CORS、binary 配信と metrics の実測は、別途承認された AWS 切り替え後に確認します。この source の記述は配備済みであることを意味しません。