このチュートリアルでは、サーバーレスコンピューティングプラットフォームである Cloudflare Workers を使い、Cloudflare Access のシングルサインオン(SSO)機能を拡張します。具体的には、保護したオリジンへ送るリクエストを変更し、Cloudflare Access の認証イベントから得た追加情報を含めます。
所要時間: 45 分
Cloudflare Access は、ユーザーがアプリケーションに接続する前に ID を検証する認証プロキシです。次の図のとおり、Access はリクエストに JWT を挿入します。オリジンサーバーは、この JWT を 検証 できます。
Cloudflare Worker を使い、リクエストに追加の HTTP ヘッダーを挿入すると、この機能を拡張できます。この例では、デバイスポスチャ属性 の firewall_activated と disk_encrypted を追加します。Cloudflare Access が認証イベントから収集する属性であれば、ほかの属性も含められます。
この方法では、次のことができます。
- セキュリティを強化する: 認証イベントから得た追加情報を取り込むと、より堅牢なセキュリティ対策を実装できます。たとえば、デバイスポスチャデータを使い、デバイスのコンプライアンスに基づいてアクセスを強制できます。
- ユーザー体験を改善する: ユーザー属性に応じてコンテンツや機能を調整し、体験をパーソナライズできます。たとえば、ユーザーのロールや所在地に応じて、異なるコンテンツを表示できます。
- 開発を簡素化する: Cloudflare Workers を使うと、オリジンアプリケーションのコードを変更せずに、Cloudflare Access の構成を拡張できます。
- Cloudflare Access に セルフホストアプリケーション を追加します。
- ディスク暗号化 と ファイアウォール のデバイスポスチャチェックを有効にします。
- ローカルマシンに Wrangler をインストールします。
-
新しい Workers プロジェクトを作成します。
npm create cloudflare@latest -- device-posture-workeryarn create cloudflare device-posture-workerpnpm 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を選びます(デプロイ前にいくつか変更します)。
- What would you like to start with? では、
-
プロジェクトディレクトリへ移動します。
$ cd device-posture-worker -
次のコードを
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); }, };
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_encryption と firewall のポスチャチェックを含むユーザー ID の例です。Worker は、ポスチャチェックの結果をリクエストヘッダー Cf-Access-Firewall-Activated と Cf-Access-Disk-Encrypted に挿入します。
{
"id": "P51Tuu01fWHMBjIBvrCK1lK-eUDWs2aQMv03WDqT5oY",
"name": "John Doe",
"email": "[email protected]",
"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
}
}
...
}Wrangler 設定ファイル で、Worker を Access アプリケーションのドメインへマッピングする ルートを設定 します。
{
"route": {
"pattern": "app.example.com/*",
"zone_name": "example.com"
}
}[route]
pattern = "app.example.com/*"
zone_name = "example.com"npx wrangler deployこれで Worker は、アプリケーションの Access ポリシーを通過したリクエストに、Cf-Access-Firewall-Activated と Cf-Access-Disk-Encrypted ヘッダーを挿入します。
{
"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": "[email protected]",
"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"
}
}オリジンサーバーがこれらのヘッダーを受信していることを確認できます。