Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

Workers で SSO 属性を Access で保護したオリジンへ送る

最終更新 Markdown で表示Agent セットアップ

このチュートリアルでは、サーバーレスコンピューティングプラットフォームである Cloudflare Workers を使い、Cloudflare Access のシングルサインオン(SSO)機能を拡張します。具体的には、保護したオリジンへ送るリクエストを変更し、Cloudflare Access の認証イベントから得た追加情報を含めます。

所要時間: 45 分

認証フロー

Cloudflare Access は、ユーザーがアプリケーションに接続する前に ID を検証する認証プロキシです。次の図のとおり、Access はリクエストに JWT を挿入します。オリジンサーバーは、この JWT を 検証 できます。

Access アプリケーションへのリクエストの標準的な認証フロー

Cloudflare Worker を使い、リクエストに追加の HTTP ヘッダーを挿入すると、この機能を拡張できます。この例では、デバイスポスチャ属性firewall_activateddisk_encrypted を追加します。Cloudflare Access が認証イベントから収集する属性であれば、ほかの属性も含められます。

拡張した認証フローでは、Worker が追加のリクエストヘッダーをオリジンへ渡します

メリット

この方法では、次のことができます。

  • セキュリティを強化する: 認証イベントから得た追加情報を取り込むと、より堅牢なセキュリティ対策を実装できます。たとえば、デバイスポスチャデータを使い、デバイスのコンプライアンスに基づいてアクセスを強制できます。
  • ユーザー体験を改善する: ユーザー属性に応じてコンテンツや機能を調整し、体験をパーソナライズできます。たとえば、ユーザーのロールや所在地に応じて、異なるコンテンツを表示できます。
  • 開発を簡素化する: Cloudflare Workers を使うと、オリジンアプリケーションのコードを変更せずに、Cloudflare Access の構成を拡張できます。

始める前に

1. Worker を作成する

  1. 新しい Workers プロジェクトを作成します。

    npm create cloudflare@latest -- device-posture-worker

    セットアップでは、次のオプションを選びます。

    • What would you like to start with? では、Hello World example を選びます。
    • Which template would you like to use? では、Worker only を選びます。
    • Which language do you want to use? では、JavaScript を選びます。
    • Do you want to use git for version control? では、Yes を選びます。
    • Do you want to deploy your application? では、No を選びます(デプロイ前にいくつか変更します)。
  2. プロジェクトディレクトリへ移動します。

    $ cd device-posture-worker
  3. 次のコードを src/index.js にコピーします。<your-team-name> は、Zero Trust の チーム名 に置き換えてください。

    index.jsjs
    import { parse } from "cookie";
    export default {
    	async fetch(request, env, ctx) {
    		// The name of the cookie
    		const COOKIE_NAME = "CF_Authorization";
    		const CF_GET_IDENTITY =
    			"https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/get-identity";
    		const cookie = parse(request.headers.get("Cookie") || "");
    		if (cookie[COOKIE_NAME] != null) {
    			try {
    				let id = await (await fetch(CF_GET_IDENTITY, request)).json();
    				let diskEncryptionStatus = false;
    				let firewallStatus = false;
    
    				for (const checkId in id.devicePosture) {
    					const check = id.devicePosture[checkId];
    					if (check.type === "disk_encryption") {
    						console.log(check.type);
    						diskEncryptionStatus = check.success;
    					}
    					if (check.type === "firewall") {
    						console.log(check.type);
    						firewallStatus = check.success;
    						break;
    					}
    				}
    				//clone request (immutable otherwise) and insert posture values in new header set
    				let newRequest = await new Request(request);
    				newRequest.headers.set(
    					"Cf-Access-Firewall-Activated",
    					firewallStatus,
    				);
    				newRequest.headers.set("Cf-Access-Disk-Encrypted", firewallStatus);
    
    				//sent modified request to origin
    				return await fetch(newRequest);
    			} catch (e) {
    				console.log(e);
    				return await fetch(request);
    			}
    		}
    		return await fetch(request);
    	},
    };

2. ユーザーの ID を確認する

index.js のスクリプトは、get-identity エンドポイントを使い、Cloudflare Access の認証イベントからユーザーの完全な ID を取得します。利用できるデータフィールドの一覧を確認するには、Access アプリケーションにログインし、URL の末尾に /cdn-cgi/access/get-identity を付けます。たとえば、www.example.com が Access の背後にある場合は、https://www.example.com/cdn-cgi/access/get-identity を開きます。

次は、disk_encryptionfirewall のポスチャチェックを含むユーザー ID の例です。Worker は、ポスチャチェックの結果をリクエストヘッダー Cf-Access-Firewall-ActivatedCf-Access-Disk-Encrypted に挿入します。

Example user identityjson
{
  "id": "P51Tuu01fWHMBjIBvrCK1lK-eUDWs2aQMv03WDqT5oY",
  "name": "John Doe",
  "email": "john.doe@cloudflare.com",
  "amr": [
    "pwd"
  ],
  "oidc_fields": {
    "principalName": "XXXXXX_cloudflare.com#EXT#@XXXXXXcloudflare.onmicrosoft.com"
  },
  "groups": [
    {
      "id": "fdaedb59-e9be-4ab7-8001-3e069da54185",
      "name": "XXXXX"
    }
  ],
  "idp": {
    "id": "b9f4d68e-dac1-48b0-b728-ae05a5f0d4b2",
    "type": "azureAD"
  },
  "geo": {
    "country": "FR"
  },
  "user_uuid": "ce40d564-c72f-475f-a9b8-f395f19ad986",
  "account_id": "121287a0c6e6260ec930655e6b39a3a8",
  "iat": 1724056537,
  "devicePosture": {
    "f6f9391e-6776-4878-9c60-0cc807dc7dc8": {
      "id": "f6f9391e-6776-4878-9c60-0cc807dc7dc8",
      "schedule": "5m",
      "timestamp": "2024-08-19T08:31:59.274Z",
      "description": "",
      "type": "disk_encryption",
      "check": {
        "drives": {
          "C": {
            "encrypted": true
          }
        }
      },
      "success": false,
      "rule_name": "Disk Encryption - Windows",
      "input": {
        "requireAll": true,
        "checkDisks": []
    },
    "a0a8e83d-be75-4aa6-bfa0-5791da6e9186": {
      "id": "a0a8e83d-be75-4aa6-bfa0-5791da6e9186",
      "schedule": "5m",
      "timestamp": "2024-08-19T08:31:59.274Z",
      "description": "",
      "type": "firewall",
      "check": {
        "firewall": false
      },
      "success": false,
      "rule_name": "Local Firewall Check - Windows",
      "input": {
        "enabled": true
      }
    }
    ...
  }

3. Worker をアプリケーションへルーティングする

Wrangler 設定ファイル で、Worker を Access アプリケーションのドメインへマッピングする ルートを設定 します。

{
	"route": {
		"pattern": "app.example.com/*",
		"zone_name": "example.com"
	}
}
[route]
pattern = "app.example.com/*"
zone_name = "example.com"

4. Worker をデプロイする

npx wrangler deploy

これで Worker は、アプリケーションの Access ポリシーを通過したリクエストに、Cf-Access-Firewall-ActivatedCf-Access-Disk-Encrypted ヘッダーを挿入します。

Example request headersjson
{
	"headers": {
		"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
		"Accept-Encoding": "gzip",
		"Accept-Language": "en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-GB;q=0.6",
		"Cf-Access-Authenticated-User-Email": "John.Doe@cloudflare.com",
		"Cf-Access-Disk-Encrypted": "false",
		"Cf-Access-Firewall-Activated": "false",
		"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
	}
}

オリジンサーバーがこれらのヘッダーを受信していることを確認できます。

役に立ちましたか?