本教程将引导您使用我们的无服务器计算平台 Cloudflare Workers 扩展 Cloudflare Access 的单点登录 (SSO) 功能。具体而言,本指南将演示如何修改发送到受保护源站的请求,以包含来自 Cloudflare Access 身份验证事件的附加信息。
完成所需时间: 45 分钟
Cloudflare Access 是一个身份验证代理,负责在用户连接到您的应用程序之前验证其身份。如下面的图表所示,Access 将 JWT 插入到请求中,然后源站服务器可以对其进行验证。
您可以通过使用 Cloudflare Worker 向请求中插入额外的 HTTP 标头来扩展此功能。在此示例中,我们将添加设备状态属性 firewall_activated 和 disk_encrypted,但您可以包含 Cloudflare Access 从身份验证事件中收集的任何属性。
这种方法允许您:
- 增强安全性:通过结合来自身份验证事件的附加信息,您可以实施更强大的安全措施。例如,您可以使用设备状态数据来根据设备合规性强制执行访问。
- 改善用户体验:您可以通过根据用户属性定制内容或功能来提供个性化的用户体验。例如,您您可以根据用户的角色或位置显示不同的内容。
- 简化开发:通过使用 Cloudflare Workers,您可以轻松扩展 Cloudflare Access 配置,而无需修改源站应用程序代码。
-
创建一个新的 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 身份验证事件中获取用户的完整身份。要查看可用数据字段的列表,请登录您的 Access 应用程序,并在 URL 后附加 /cdn-cgi/access/get-identity。例如,如果 www.example.com 位于 Access 后端,请转到 https://www.example.com/cdn-cgi/access/get-identity。
以下是包含 disk_encryption 和 firewall 状态检查的用户身份的示例。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 deployWorker 现在将在通过应用程序的 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"
}
}您可以验证源站服务器是否接收到了这些标头。