アルアカ - Arcadia Academia

Arcadia Academiaは「エンジニアリングを楽しむ」を合言葉に日本のデジタル競争力を高めることをミッションとするテックコミュニティです。

Cloudflare AccessでGoogle認証の会員制(限定公開)サイトをノーコードで作る【ハンズオン】

Featured image of the post

「社内ツールや会員限定のページを、手軽にGoogleログインで守りたい」——そんなときに最速なのが Cloudflare Access(Zero Trust)です。

Accessは、サイトの前段にCloudflareが立って認証を代行する仕組みです。Googleを認証元(IdP)に設定すれば、コードを書かずに「Googleでログインした許可ユーザーだけ」にアクセスを限定できます。

この記事は Cloudflareとは?初心者向けガイド の関連記事です。コード不要で会員制(限定公開)サイトを作る手順をハンズオンで解説します。「登録・課金まで含む本格的な会員サイト」を自作したい場合は、姉妹記事の Workers + Google OAuthで会員サイトを自作する もあわせてご覧ください。


[目次を開く]

Cloudflare Access(Zero Trust)とは?

Cloudflare Accessは、CloudflareのZero Trust製品の一つで、アプリやサイトの手前に認証ゲートを置くサービスです。訪問者はまずCloudflareのログイン画面を通り、認証に成功した人だけが背後のサイトに到達できます。

最大の利点は、アプリ側に認証コードを書かなくてよいことです。既存の静的サイトやアプリに、あとから認証を被せられます。

訪問者 → Cloudflare Access(Googleでログイン)→ 許可ユーザーのみ → あなたのサイト
                          ↑
                  未認証・限外ユーザーはここでブロック

こんな用途に向く

  • 社内ツール・管理画面の保護
  • 顧客・会員限定のクローズドなページ
  • 公開前のステージング環境を関係者だけに公開
注意:Accessは「入れる/入れない」を判定するアクセス制御です。会員登録フロー、プロフィール管理、課金などを持つ「本格的な会員サイト」を作りたい場合は、Workersでの自作(姉妹記事)が適しています。

料金

Accessを含むZero Trustには無料プランがあり、少人数なら無料で始められます(目安として3050人規模までの無料枠が提供されてきました。最新の人数・条件は公式で確認してください)。社内ツールや小規模な会員ゲートなら、まず無料枠で十分なケースが多いです。

事前に準備するもの

  • Cloudflareで管理しているドメイン(ネームサーバー変更済み。未だなら入門記事を参照)
  • 保護したいサイト/アプリ(例:Cloudflare Pagesで公開したサイト)
  • Googleアカウント(認証に使う。Google CloudでOAuthクライアントを作成します)

ハンズオン:Google認証でサイトを守る

1. Zero Trustを有効化する

Cloudflareダッシュボードから「Zero Trust」を開き、初回はチーム名(例 your-team.cloudflareaccess.com)を設定します。これがログイン画面のドメインになります。

2. Googleを認証元(IdP)として追加する

まず Google Cloud Console で OAuth 2.0 クライアントを作成し、クライアントID / シークレットを取得します。リダイレクトURIには、Accessのコールバックを指定します。

https://<チーム名>.cloudflareaccess.com/cdn-cgi/access/callback

次にZero Trustの「Settings → Authentication → Login methods」で Google を追加し、上記のクライアントID/シークレットを登録します。(Google Workspaceを使えば、社内ドメイン全体を対象にできます。)

3. 保護するアプリを追加する

「Access → Applications → Add an application → Self-hosted」を選び、保護したいドメインやパスを指定します(例 members.example.comexample.com/members)。

4. ポリシー(許可ルール)を作る

「誰を入れるか」をポリシーで定義します。代表的な条件は次のとおりです。

条件(Include)
Emails 特定のメールアドレスを個別許可
Emails ending in @example.com ドメイン全員を許可
Google Groups 特定のGoogleグループのメンバーを許可

例えば「@example.com のメールを持つ人だけ許可」とすれば、社内メンバー限定のサイトが完成します。

5. 動作を確認する

保護したドメインにアクセスすると、Cloudflareのログイン画面が表示され、Googleログインを要求されます。許可ユーザーでログインすればサイトが表示され、限外ユーザーは拒否されます。

ブラウザは以前のログイン状態(Cookie)を持っているので、「保護できているか」は Cookie を持たない curl で確かめるのが確実です。保護したホスト名を変数に入れて実行します。

HOST=members.example.com   # 保護したホスト名に置き換える
curl -sI "https://$HOST/" | grep -iE '^(HTTP|location)'

期待する結果は次の2行です。ステータスが 302 で、location にチーム名ドメインの /cdn-cgi/access/login/ が出ていれば、Access が前段で止めています。

HTTP/2 302
location: https://<チーム名>.cloudflareaccess.com/cdn-cgi/access/login/...

ここで 200 とサイト本体の HTML が返るなら、そのホスト名は保護されていません。次の表で切り分けます。

設定したのに入れてしまう/ログイン画面が出ない時の切り分け表

症状 まず疑う原因 確認する場所
curl200 が返り、サイトが素通しになる DNS レコードがプロキシ(オレンジ雲)になっていない。Access は Cloudflare を経由した通信にしか掛からない DNS の該当レコードが「Proxied」になっているか
別のホスト名では 302 になるのに、このホスト名だけ 200 Application の対象ドメイン/パスと、実際にアクセスしているホスト名が違う(www の有無、サブパスの綴り) Access → Applications の Application domain
Google 側で Error 400: redirect_uri_mismatch Google Cloud の OAuth クライアントに登録したリダイレクト URI が、Access のコールバック(/cdn-cgi/access/callback)と1文字でも違う Google Cloud Console → 認証情報 → 承認済みのリダイレクト URI
Google ログイン後に「アクセスが拒否されました」になる ポリシーの Include にそのメールアドレスが当たっていない(個人の Gmail なのに Emails ending in で会社ドメインだけ許可している、など) Zero Trust → Logs → Access で拒否されたリクエストの理由を見る
ログイン画面が何度も出る(ループする) ブラウザがサードパーティ Cookie をブロックしている、または Application のドメインとアクセス先ホスト名が食い違い、Cookie が別ホストに発行されている シークレットウィンドウで再現するか試す。Application domain を見直す
curl や CI からのアクセスだけ常にログイン画面へ飛ばされる 人間向けの Google ログインは自動化からは通れない Service Token を発行し、ID とシークレットをヘッダーで送る(次のコマンド)

自動化からの疎通確認は、Zero Trust → Access → Service Auth でトークンを発行し、ポリシーに Service Auth の許可を足したうえで次のように呼びます。

curl -sI "https://$HOST/" \
  -H "CF-Access-Client-Id: $CF_CLIENT_ID" \
  -H "CF-Access-Client-Secret: $CF_CLIENT_SECRET" | head -1

200 が返れば、トークン経由で Access を通過しています。ブラウザで 302 が返るのにここで 200 になる状態が正常です。

ログインできたのに「誰が来たか」がアプリで取れない時

Access を通ったリクエストにはヘッダー Cf-Access-Jwt-Assertion が付きます。アプリ側のログにこのヘッダーの有無を1行出力し、空なら「Access を経由していない経路」を疑ってください。オリジンサーバーが IP 直打ちで届く構成では Access は迂回できるので、オリジン側で Cloudflare の IP レンジ以外を拒否するか、Cloudflare Tunnel 経由でオリジンを公開するのが定石です。

アプリ側でログインユーザーを識別する

Accessを通過したリクエストには、Cloudflareが署名付きのJWTを付与します。アプリ側で「誰がログインしているか」を知りたい場合は、リクエストヘッダー Cf-Access-Jwt-Assertion を検証します。簡易的には、Accessが提供するエンドポイントからユーザー情報を取得できます。

GET https://<チーム名>.cloudflareaccess.com/cdn-cgi/access/get-identity

これにより、ログインしたユーザーのメールアドレスなどをアプリで受け取り、「さん、ようこそ」のような個別表示も可能になります。

よくあるつまずき(FAQ)

Q. 設定したのに誰でも入れてしまう

ポリシーの Include が広すぎる可能性があります。「Emails ending in」や個別メールなど、絞り込み条件を見直してください。ポリシーが未設定だとアプリは保護されません。

Q. 一部のページだけ保護したい

Applicationのパス指定で example.com/members のようにサブパスを対象にできます。公開部分と会員部分をパスで分けましょう。

Q. ログアウトさせたい

/cdn-cgi/access/logout へのリンクでセッションを終了できます。セッションの有効期間はApplication設定で調整可能です。

Q. Accessだけで会員サイトは完成する?

「限定公開(許可した人だけ見られる)」ならAccessだけで完成します。一方で、一般ユーザーのセルフ登録やプロフィール・課金が必要なら、次の姉妹記事の自作アプローチが適しています。

まとめ

Cloudflare Accessを使えば、コードを書かずに、Googleログインでゲートした限定公開サイトを最短で作れます。要点を振り返ります。

  • Accessはアプリの前段で認証を代行し、コード不要
  • GoogleをIdPに設定し、ポリシーで許可ユーザーを絞る
  • 少人数なら無料枠で始められる
  • アプリ側では Cf-Access-Jwt-Assertion や get-identity でユーザーを識別できる

「まずは限定公開だけで十分」ならAccess、「登録・課金もある本格的な会員サイト」なら次の記事へ進みましょう。

あわせて読みたい:

プログラミング学習でお悩みですか?

現役エンジニアがあなたの学習をマンツーマンでサポートします。

  • 学習の進め方がわからない
  • ポートフォリオの作り方を知りたい
  • 現場で使える技術を学びたい
まずは30分の無料相談

相談は完全無料・オンラインで気軽に

あなたを爆速で成長させるメンタリングプログラムはこちら

メンタープログラムバナー

学習・開発のお悩みは現役エンジニアに相談

メンタープログラムの詳細を見る

エンジニアの基礎学習ゲーム

プログラミング学習支援

無料相談はこちら