Cloudflare Zero TrustのAccess機能 を使って、Cloudflare Workersで構築したAPIに認証を設定する

Posts

Cloudflare Workersで構築したAPIを、特定のユーザーやクライアントからのみ実行させたい場合、Cloudflare Zero TrustのAccess機能を使うことで、コード不要でAPIに認証を設定できる。

Cloudflare Workersで構築したAPIは、URLが分かれば、誰でもAPIを呼び出すことができてしまう。
特定のユーザーかクライアントからのみ実行させたい場合、APIに認証をかける必要がある。
Cloudflare Zero TrustのAccess機能を使うと、Cloudflareが管理するネットワーク上にあるサービスに対してCloudflare Dashboardで設定するだけで認証機能を付与できる。

ただし、Cloudflare Workersにデプロイしたリソース自体にはAccess機能を設定できない。
そのため、Cloudflare WorkersのリソースのURLに割り当てたCNAMEレコードのドメインに対してAccess機能を設定する必要がある。

必要なもの

  • Cloudflareで管理している独自ドメイン
  • Cloudflare WorkersにデプロイしたAPI

事前準備

Cloudflare Workersにデプロイするテスト用のAPIを作成する。
テスト用のAPIはHonoのスターターテンプレートを使って作ることにする。

  1. npm create honoコマンドを実行して、Honoのプロジェクトを生成する。
    この記事ではプロジェクト名を「example-api」とする。

    npm create hono@latest example-api
    
     Using target directory example-api
     Which template do you want to use? cloudflare-workers
    cloned honojs/starter#main to /Users/chick-p/Desktop/example-api
     Copied project files
    
  2. 依存パッケージをインストールする。

    cd example-api
    npm install
    
  3. src/index.tsを次の内容に置き換える。
    /helloにGETリクエストを送信すると「Hello World」というJSONを返すエンドポイントを作成する。

    src/index.ts
    import { Hono } from "hono";
    
    const app = new Hono();
    
    app.get("/hello", (c) => {
      return c.json(
        {
          message: "Hello World",
        }
      );
    });
    
    export default app;
    
  4. npm run devコマンドを実行し、ローカルサーバーを起動する。

    npm run dev
    
    > dev
    > wrangler dev src/index.ts
    
    ⛅️ wrangler 3.22.2
    -------------------
     Starting local server...
    [wrangler:inf] Ready on http://localhost:8787
    
  5. /helloに対してGETリクエストを送信し、「Hello World」というJSONが返ってくることを確認する。

    curl http://localhost:8787/hello
    
    {"message":"Hello World"}
    
  6. npm run deployコマンドを実行し、APIをデプロイする。
    デプロイに成功すると、https://<PROJECT_NAME>.<USER>.workers.dev/helloにアクセスできるようになる。

    npm run deploy
    
    > deploy
    > wrangler deploy --minify src/index.ts
    
    ⛅️ wrangler 3.22.2
    -------------------
    Total Upload: 21.95 KiB / gzip: 8.06 KiB
    Uploaded example-api (1.14 sec)
    Published example-api (3.77 sec)
      https://example-api.<USER-IDENTIFER>.workers.dev
    Current Deployment ID: f91e0bc6-f081-4589-b4d1-9b557766eff8
    
  7. デプロイしたAPIに対しても、/helloに対してGETリクエストを送信し、「Hello World」というJSONが返ってくることを確認する。

    curl https://example-api.<USER-IDENTIFER>.workers.dev/hello
    
    {"message":"Hello World"}
    

設定手順

本題の、Cloudflare WorkersにCloudflare Zero TrustのAccess機能を使って認証を設定する手順を説明する。

STEP1:CNAMEレコードの登録

Clouflare WorkersへデプロイしたAPIにドメインを割り当てる。

  1. Cloudflare Dashboardにアクセスし、[Websites]を開く。

  2. CNAMEレコードを登録するドメインを選択する。

  3. [DNS]>[Record]の順でサイドメニューを展開し、[Add record]をクリックする。

  4. 次の内容を入力する。

    • Type:CNAME
    • Name:サブドメインに当たる部分
      この記事では「example-api」を入力する
    • Target:デプロイしたCloudflare WorkerのFQDN
      <PROJECT>.<USER-IDENTIFER>.workers.dev
    • Proxy status:有効にする

    スクリーンショット:CNAME レコードの設定項目を入力している

  5. [Save]をクリックする。

STEP2:ルートの設定

  1. Dashboardのサイドメニューから[Workers & Pages]を開く。

  2. デプロイしたAPIを選択する。

  3. [Triggers]タブを選択する。

  4. 「Routes」セクションの[Add route]をクリックする。

  5. 次の内容を入力する。

    • Route:CNAMEレコードに登録したドメインのBase URL
      ここでは「https://example-api.<DOMAIN_NAME>/*」を入力する
    • Zone:NAMEレコードを登録したドメイン名

    スクリーンショット:ルートの設定項目を入力している

  6. [Add route]をクリックする

  7. あらかじめ録されていたルートを無効化する。
    <PROJECT_NAME>.<USER-IDENTIFER>.workers.dev<USER-IDENTIFER>.workers.devの[…]をクリックし、[Disable]をクリックする。
    この設定をすることで、元々のCloudflare WorkersのURLにリクエストを送信しても、APIが実行されなくなる。

    スクリーンショット:すでに登録されていたルートが解除されている

  8. 次の2点について動作を確認する。

    • <PROJECT_NAME>.<USER-IDENTIFER>.workers.devに対するリクエストが失敗すること

      curl https://example-api.<USER-IDENTIFER>.workers.dev/hello
      
      error code: 1042
      
    • CNAMEレコードを登録したドメインに対するリクエストが成功すること

      curl https://example-api.example.com/hello
      
      {"message":"Hello World"}
      

STEP3:Service Tokenの生成

Zero TrustのService Tokenを生成する。
ここで生成したService TokenのクライアントIDとクライアントシークレットをAPIのリクエストヘッダーに付与すると、APIへアクセスできるようになる。

  1. Dashboardのサイドメニューから[Zero Trust]を開く。
    (初回アクセス時はZero Trustを有効化する必要があるので、手順に沿って有効化する。)

  2. [Access]>[Service Auth]の順でサイドメニューを展開し、[Create Service Token]をクリックする。

  3. 次の内容を入力する。

    • Service token name:任意の名前を入力する
      この記事では「example-api」と入力する
    • Service Token Duration:Non-expiring
  4. [Generate token]をクリックする。

  5. クライアントIDとクライアントシークレットが表示されるので、メモする。

    スクリーンショット:クライアントIDとクライアントシークレットが表示されている

STEP4:アプリケーションの作成

Cloudflare Workersに割り当てたドメインをService Tokenと関連づける。

  1. [Access]>[Application]の順でサイドメニューを展開し、[Add an application]をクリックする。

  2. [Self-Hosted]をクリックする

  3. 「Configure app」画面でアプリケーションの基本設定をする。
    まずは「Application Configuration」セクションで、次の内容を入力する。

    • Application name:任意の名前を入力する
      この記事では「example-api」と入力する
    • Session Duration:24 hours
    • Subdomain domain:CNAMEレコードに登録したサブドメイン
      この記事では「example-api」を入力する
    • Domain:CNAMEレコードを登録したドメイン名を選択する

    スクリーンショット:Application Configurationの設定項目が表示されている

  4. 「Application Appearance」「Tags」「Block pages」セクションはデフォルトのままにする

  5. 「Identity providers」セクションで、次の内容を入力する。

    • Accept all available identity providers:無効にする
    • Instant Auth:無効にする

スクリーンショット:Identity providersの設定項目が表示されている

  1. [Next]をクリックする

  2. 「Add policies」画面でポリシーの設定をする。
    まずは次の内容を入力する。

    • Policy name:任意の名前を入力する
      この記事では「example-api」と入力する
    • Action:Service Auth
    • Session duration:Same as application session timeout

    スクリーンショット:ポリシーの設定項目が表示されている

  3. 「401 Response」を有効にする。

  4. 「Configure rules」セクションの「Include」で、次の内容を入力する。

    • Selector:「Everyone」を選択する
  5. [Add require]をクリックする。

    • Selector:「Service Token」を選択する
    • Value:「example-api」を選択する(作成したService Tokenの名前)

スクリーンショット:Service Tokenの設定項目が表示されている

  1. [Next]をクリックする。

  2. 「Setup」画面でそのほかの設定をする。要件に応じて設定する。

    • 「CORS」セクション:すべてデフォルトのまま
    • 「Cookie settings」セクション:「HTTP Only」を有効にする
    • 「Additional settings」セクション:すべてデフォルトのまま

スクリーンショット:Setupの設定項目が表示されている

  1. [Add application]をクリックする。

STEP5:動作確認

最後に、作成したAPIに対して、Service Tokenを付与したリクエストを送信し、APIにアクセスできることを確認する。

  1. まずはヘッダーを付与せずAPIにリクエストを送信すると、403エラーが返ってくることを確認する。

    curl -I https://example-api.example.com/hello
    
    HTTP/2 403
    
  2. STEP2でメモしたService TokenのクライアントIDとクライアントシークレットをヘッダーを付与すると、レスポンスが返ってくることを確認する。

    curl https://example-api.example.com/hello \
      -H 'CF-Access-Client-Id: YOUR_CLIENT_ID' \
      -H 'CF-Access-Client-Secret: YOUR_CLIENT_SECRET'
    
    {"message":"Hello World"}