4. Cloudflare 認証(cloudflare):Workers
概要
3. Cloudflare 認証 — Pagesの機能(KV の .kasc・R2 秘匿データ配信)に加えて、静的ファイル自体も含めて全リクエストを認証ゲートする方式です。Worker スクリプトが全リクエストを処理し(run_worker_first)、ログイン時に発行される署名トークンの Cookie(HttpOnly・12時間有効)を持たないアクセスには静的ファイルも返しません。
秘匿データがすべて Functions/Worker 経由になる設計では Pages の「静的ファイル無料無制限」の利点が薄いため、静的ファイルまで保護できる本方式が適しています。
control を 4 に設定するとこの方式が選択されます(クライアント実装は cloudflare と共通で、r2:// 書き換えも有効)。
構成
workers/
wrangler.toml … assets=../web、KV/R2バインド、run_worker_first=true
worker.js … /api/* ルーティング+静的ファイル認証ゲート
functions/
api/auth.js・api/kasc.js・api/data/ … 認証・保存API(Cloud Run 版と同一契約)
api/gemini.js … 内蔵AI向け Gemini プロキシ(サーバーキー注入)
api/capabilities.js・health.js … 能力通知 {tier:"workers"}・起動確認
worker.js は functions/api/*・functions/_lib/* のハンドラをそのまま再利用します。二重実装ではありません。
POST /api/gemini は内蔵AI(ブラウザ)向けの薄いキー隠蔽プロキシで、ブラウザの generateContent リクエストにサーバーキー(wrangler secret put GEMINI_API_KEY)を注入して Gemini へ転送します。推論ループ・地図操作はブラウザの内蔵AIが担うため、サーバー側にエージェント実装はありません。BYO キーがあるユーザーはブラウザから直接 Gemini を呼ぶためプロキシは使いません。ANTIGRAVITY_TOKEN(Bearer 必須化)・GEMINI_MODELS(許可モデル・カンマ区切り)・ANTIGRAVITY_RATE_LIMIT(KV バインド時の IP 毎時間制限)で制御できます。
認証前に公開されるのはログイン画面に必要な最小限のみです(index.html・styles.css・favicon.ico・auth-*.js・auth-methods.json・i18n.js・i18n/・PLUGIN/auth-*/)。それ以外のファイル(app.js・projects/・DATA/ 等)はすべて未認証では 401 になります。
デプロイ手順
以下の手順はリポジトリルートで python run-workers.py を実行すると自動化できます(ログイン確認・KV/R2 バインド記入・secret 確認・control=4 設定・deploy・簡易検証まで。control はデプロイ後に 0 に戻します。未ログイン時の wrangler login とパスワード入力のみ手動です)。
前提:wrangler(Cloudflare の CLI)が使えること。初回のみ wrangler login でブラウザ認証しておきます。
-
KV / R2 を用意します(Pages ですでに作成済みならこの手順はスキップ。同じものをバインドし直すだけでデータ移行は不要です)。
作成済みならcd workers wrangler kv namespace create KASUGAI_KV # → 発行された id を控える wrangler r2 bucket create kasugai-data # → バケット名を控えるwrangler kv namespace list/wrangler r2 bucket listで id・バケット名を確認できます。 -
workers/wrangler.tomlにバインドを書きます。[[kv_namespaces]]/[[r2_buckets]]のコメントを外して、手順1の id・バケット名を記入します。ユーザーIDをadminから変える場合は[vars]のKASUGAI_AUTH_USERもここで編集します。 -
パスワードをシークレット登録します(
wrangler.tomlには書きません)。
値は引数には書かず、コマンド実行後の対話プロンプトで入力します。wrangler secret put KASUGAI_AUTH_PASSEnter a secret value: ← ここでパスワードを打ち込んで Enter ✨ Success! Uploaded secret KASUGAI_AUTH_PASS- 入力中は画面に何も表示されません(パスワード入力と同じ)。貼り付けも可
- 対話式なのは、端末の履歴にもファイルにも値を残さないためです
- 登録済みかは
wrangler secret listで確認できます(名前だけ出て値は読み出せません)。間違えたら同じコマンドで上書きします - ダッシュボードからも設定できます:Worker → Settings → Variables and Secrets → Add(Type: Secret)
-
web/auth-methods.jsonのcontrolを4にします(このファイルは静的アセットとして一緒にデプロイされます)。 -
デプロイします。
Pages のwrangler deploy--project-nameや配信ディレクトリのような引数は不要です。wrangler.tomlが宣言的な設定ファイルになっており、以下がそこに書かれています。
初回 deploy でPages のコマンド引数 Workers での相当設定 --project-name <プロジェクト名>wrangler.tomlのname = "kasugai-canvas"web(配信ディレクトリ)[assets]のdirectory = "../web"functions/(自動検出)main = "worker.js"nameの Worker が自動作成され、以降は同名 Worker の更新になります。 -
動作確認します。
https://kasugai-canvas.<アカウント>.workers.devを開き、ログイン画面 → ID/PASS でログインできることを確認します。未ログインでapp.js等に直接アクセスして 401 になることも確認すると確実です。
再デプロイの目安:
web/・workers/・functions/のファイルを変更した →wrangler deployを再実行- secret(パスワード)を変えた →
wrangler secret putのみ(再デプロイ不要・即反映) - KV の中身(
.kasc)を更新した → デプロイ不要(インスペクターの「適用」やwrangler kv key putで即反映・伝播は最大60秒)
.kasc の登録・R2 データ・r2:// 記法は 3 のページと同じです。
Pages(方式3)との設定の違い
クライアント側(web/・認証プラグイン・API 呼び出し)は方式3と完全に共通で、違いはサーバー側のデプロイ・設定方法だけです。functions/api/* のハンドラも worker.js が import して再利用するため、API 実装の二重管理はありません。
| 項目 | Pages(方式3) | Workers(方式4) |
|---|---|---|
| デプロイ先 | Pages プロジェクトwrangler pages deploy web(ルートで実行・functions/ を自動検出) |
Workers プロジェクトcd workers && wrangler deploy |
| KV/R2 バインド | Pages → Settings → Bindings → Functions で GUI 設定 | workers/wrangler.toml の [[kv_namespaces]] / [[r2_buckets]] |
| 環境変数・シークレット | Pages → Settings → Environment variables(Production/Preview 別) | 非秘密は wrangler.toml の [vars]、パスワード系は wrangler secret put |
| 静的ファイル | 認証なしで公開(無料・無制限) | run_worker_first = true で全リクエスト認証ゲート(Worker のリクエスト枠を消費) |
| セッション | 署名トークンのみ(?token= / Bearer) |
HttpOnly Cookie(kasugai_session)+署名トークン |
| デフォルトドメイン | *.pages.dev |
*.workers.dev |
| control 値 | 3 |
4(同じ auth-cloudflare プラグインを使用) |
Pages からの移行手順
KV 名前空間・R2 バケットはアカウント配下のリソースなので、データ移行は不要です。同じものを Worker にバインドし直すだけです。
- Pages プロジェクトの Settings → Bindings で KV 名前空間 ID・R2 バケット名を確認し、
workers/wrangler.tomlの[[kv_namespaces]]/[[r2_buckets]]に転記します(wrangler kv namespace list/wrangler r2 bucket listでも確認可)。 - シークレットを再登録します。値は Pages から読み出せないため再入力です(忘れた場合は新しいパスワードを登録すればよく、既存トークンが無効化されるだけです)。
cd workers
wrangler secret put KASUGAI_AUTH_PASS
wrangler secret put KASUGAI_TOKEN_SECRET # Pages で設定していた場合のみ
wrangler deploy
https://kasugai-canvas.<アカウント>.workers.devでログイン・/api/data/*の動作を確認します。web/auth-methods.jsonのcontrolを4にして再デプロイします。- カスタムドメインを Pages に付けている場合は Worker の Settings → Domains & Routes で付け替えます(同時に1箇所にしか向けられません)。動作確認が済むまで Pages プロジェクトは残しておけば切り戻し可能です。
無料枠の消費
- 全リクエストが Worker 呼び出しとして無料枠(10万回/日)を消費します — 静的ファイル・ログイン画面も含む
- 起動時に数十ファイルを読む構成のため、少人数利用なら十分ですが不特定多数への公開には向きません
- KV/R2 のオペレーション枠は別途あり(R2 読み出し 1,000万回/月 等)
資産ごとの秘匿状況
| 資産 | 未ログインの第三者 | ログイン済みユーザー |
|---|---|---|
| ID/PASS | ✅ 秘匿 | ✅ 秘匿 |
| 環境変数(secret)にのみ存在し、照合は Worker 内で実施。ブラウザには合否とトークンしか返りません。ただし推測可能な値は総当たり・推測でログインされ得ます。 | ||
| .kasc 設定(KV) | ✅ 秘匿/api/kasc の認証ゲート内 |
❌ 全量が見える ログイン時に全プロジェクト分を一括取得 |
| HTML/JS/CSS(アプリ本体) | ✅ 秘匿 未ログインは 401 |
❌ 見える |
未ログインで公開されるのはログイン画面に必要な最小限のみ(index.html・styles.css・auth-*.js・i18n.js・i18n/・PLUGIN/auth-*/)。app.js・projects/・DATA/ 等はすべて 401 です。 |
||
| データ(web/) URL が公開情報から分かる |
✅ 秘匿 未ログインは 401 |
❌ 見える |
| データ(web/) URL が非公開・推測困難 |
✅ 秘匿 未ログインは 401 |
❌ 見える |
| 方式3 との違いはここです。Worker が全リクエストを検査するため、URL が公開・推測可能かどうかに関係なく、未ログインでは静的ファイルは一切取得できません(obscurity に依存しない実際の認証ゲート)。 | ||
| データ(R2・r2:// 経由) | ✅ 秘匿 署名トークン必須 |
◐ 取得可 セッション Cookie / トークン付き /api/data/* 経由 |
セッションは HttpOnly Cookie(kasugai_session・SameSite=Strict・12時間)で管理され JS からは読み取れません。ただし r2:// の書き換えにより /api/data/...?token=… の URL にトークンが現れるため、ログイン済みブラウザのデベロッパーツールからは読み取り得ます。 |
||
✅ 秘匿 ◐ 条件付き ❌ 公開 ——「ログインした人」からは .kasc・データ・アプリ本体はすべて見えます。秘匿が効くのは未ログインの第三者に対してです。
セキュリティ上の注意
- 保護できるもの:静的ファイルすべて(HTML/JS/CSS/DATA/ 等)、
.kasc、R2 内の秘匿データ - 保護できないもの:公開許可リストのファイル(ログイン画面系)、
PLUGIN/auth-*/の内容(ID/PASS を直書きするプラグインの中身は見えます — 本番では cloudflare 系のみ使用してください) - セッションは HttpOnly Cookie(
kasugai_session・SameSite=Strict・12時間)で管理され、JS から読み取れません - Cloud Run で同様の全ゲート構成を取る場合は 6. Cloud Run 認証 — cloudrun-gate(
control: 6)、組織アカウント運用ができる場合はcontrol: 7(Cloud IAP)があります