ドキュメントサイトの Cloudflare Access (Entra ID) セットアップ手順
docs.bizlp.dev(社内ドキュメントサイト)と docs.bizlp.dev/api/*(docs-search-worker:検索 / RAG / inject.js 配信)を、Cloudflare Access の Entra ID (Office 365) ログインで保護するためのダッシュボード作業手順。
リポジトリ側のコード対応(worker の Basic 認証撤去・Worker Route 設定・GitHub Actions の CF Access service token 切替)は PR1 で完了済み。本書は Cloudflare / Azure ダッシュボードの手作業(ユーザー担当)の手順。完了すると https://docs.bizlp.dev/ が Entra ID ログインで開けるようになる。
認証の仕組み(実装済みの挙動)
- docs サイト本体(CF Pages)と検索 API(
docs-search-worker)は 同一ホストdocs.bizlp.devに同居する。/api/*だけ Worker Route で docs-search-worker に振り、それ以外は Pages がドキュメントを配信する。
- Access ポリシーは
docs.bizlp.dev1 個に対して掛ければ、ページ・worker の両方をまとめて保護できる。 - ブラウザは同一オリジン fetch で Access cookie を自動添付するため、worker 側で JWT 検証コードを持たない(エッジ完結)。
- headless ingest(
scripts/docs-vectorize.mjs←.github/workflows/docs-vectorize.yml)は CF Access service token で通過する。
手順
1. Zero Trust の有効化(既に OCR Bench で完了済なら 4. に進む)
Cloudflare ダッシュボード → Zero Trust → 初回オンボーディングで team 名 を決める(既に bizlp を採用済 → team domain は bizlp.cloudflareaccess.com)。Free プラン(50 ユーザーまで)で可。
2. Entra ID 側:IdP として OCR Bench と同じものを再利用
ocr/docs/cf-access-setup.md で登録済の Entra App と Cloudflare 側 IdP 設定を そのまま再利用 する。docs 用に別 App を切る必要はない(同一 tenant・同一 Cloudflare team domain のため)。
未登録の場合のみ、
ocr/docs/cf-access-setup.md§2-3(Azure App registration → Cloudflare IdP 登録)を先に完了させる。
3. CF Pages カスタムドメインの追加
Cloudflare ダッシュボード → Workers & Pages → bizlp-gas-accounting Pages プロジェクト → Custom domains → Set up a custom domain → docs.bizlp.dev を入力 → Continue。
- DNS は同じアカウントの
bizlp.devゾーンに自動で CNAME(proxied)が作成される。 - 数分で証明書がプロビジョニングされる。完了後
https://docs.bizlp.dev/がドキュメントの index にリダイレクトされる(この時点ではまだ Access 未保護で誰でも見られる)。
4. Worker Route の追加(/api/* → docs-search-worker)
docs-search-worker/wrangler.toml には既に下記の routes が定義済み:
routes = [
{ pattern = "docs.bizlp.dev/api/*", zone_name = "bizlp.dev" }
]
workers_dev = false
PR1 の main merge で .github/workflows/deploy-docs-search-worker.yml が自動デプロイを走らせるため、merge した時点で Worker Route が反映される(手動ダッシュボード作業は不要)。
deploy 後、
https://docs.bizlp.dev/api/healthが JSON を返せば Route 反映完了の目安。
5. Access アプリケーション作成
Zero Trust → Access → Applications → Add an application → Self-hosted:
- Application name:
bizlp docs - Session duration: 24h 推奨(OCR Bench に揃える)
- Application domain:
docs.bizlp.dev(path は空 = 全体保護。/api/*も含めて 1 ポリシーで覆う) - Identity providers: 手順 2 の Entra ID のみ ON(One-time PIN は OFF 推奨)
- Policies(2 つ作成):
- Allow human users(Action = Allow)
- Include → Emails → 許可するメールアドレスを列挙(
[email protected]ほか)
- Include → Emails → 許可するメールアドレスを列挙(
- Allow ingest service token(Action = Service Auth)
- Include → Service Token → 手順 6 で発行するトークンを選択
- Allow human users(Action = Allow)
- 作成後、アプリの Audience (AUD) タグ を控える(Overview に表示。Worker 側で JWT 検証はしないため必須ではないが、将来コード側検証を入れる場合に必要)。
6. Service Token の発行(ingest 用)
Zero Trust → Access → Service Auth → Service Tokens → Create Service Token:
- Name:
docs-search-vectorize-ci - Duration: 1 year(運用ルールで翌年 rotate)
- 作成後の Client ID と Client Secret を即控える(Secret は再表示不可)。
控えた 2 値を Allow Service Tokens ポリシー(手順 5)に紐付けるのを忘れずに。
7. GitHub Secret 投入
# 控えた値を投入
gh secret set DOCS_SEARCH_CF_ACCESS_CLIENT_ID --body "<Client ID>"
gh secret set DOCS_SEARCH_CF_ACCESS_CLIENT_SECRET --body "<Client Secret>"
.github/workflows/docs-vectorize.yml がこの 2 つを scripts/docs-vectorize.mjs に渡し、/api/ingest を service token 経由で叩く。
旧 secret の掃除(PR2 で実施予定):
DOCS_SEARCH_AUTH_USER/DOCS_SEARCH_AUTH_PASSは不要になるため、運用が安定したらgh secret deleteする。
8. 動作確認
- シークレットウィンドウで
https://docs.bizlp.dev/→ Entra ID ログイン画面 → ログイン後ドキュメント index が表示される。 - ポリシー外のアカウントでログイン → Access がブロックする。
https://docs.bizlp.dev/api/health→ Access 経由でログイン →{ok: true, ...}JSON。- docs ページ内の 🔍 ボタンで検索 → 結果が返る(Authorization ヘッダ無しでも通る)。
gh workflow run docs-vectorize.yml→ 全 batch が 200 で完了する。
9. (任意).pages.dev 直叩きの遮断
https://bizlp-gas-accounting.pages.dev/ は Pages の標準 URL として残るため、放置すると認証を素通りする裏口になる。Zero Trust → Access → Applications で bizlp-gas-accounting.pages.dev 用に Block 専用の Self-hosted アプリ を 1 つ追加して塞ぐ(Allow policy 無し)。
トラブルシュート
/api/inject.jsの script タグが 302 → ログイン画面 HTML を返してきて検索 UI が出ない: ブラウザがまだ Access cookie を持っていない(初回アクセス時)。docs サイト本体に先にアクセスしてログインを通せばよい。両者が同一オリジンなので、ページ読込が完了した時点で cookie は確実に揃っている(→ 通常運用で発生しない)。gh workflow run docs-vectorize.ymlが 401/403 で fail: service token の Client ID/Secret がgh secretに正しく入っているか、Access アプリのポリシーに該当 token が紐付いているかを確認。- Pages preview URL(
<hash>.bizlp-gas-accounting.pages.dev)で検索が動かない: preview pages は Access 範囲外 + 異なるホストのため、docs.bizlp.dev/api/*への fetch が cross-origin かつ cookie 無しになり 302 で失敗する。Preview の検索機能は仕様上断念(本番docs.bizlp.devで検証する)。 .pages.dev直叩きで認証を素通りされる: 手順 9 の Block アプリで塞ぐ。
関連
- 既存の OCR Bench 版手順(Worker 側 JWT 検証コードを含む完全版):
ocr/docs/cf-access-setup.md - DRP の同種事例: ADR-0110 /
drp/docs/cf-access-setup.md - Worker Route 定義:
docs-search-worker/wrangler.toml - ingest スクリプト:
scripts/docs-vectorize.mjs/.github/workflows/docs-vectorize.yml