跳转到内容
搜索文档

使用 Workers 将 SSO 属性发送到受 Access 保护的源站

最后更新 查看 MarkdownAgent 设置

本教程将引导您使用我们的无服务器计算平台 Cloudflare Workers 扩展 Cloudflare Access 的单点登录 (SSO) 功能。具体而言,本指南将演示如何修改发送到受保护源站的请求,以包含来自 Cloudflare Access 身份验证事件的附加信息。

完成所需时间: 45 分钟

身份验证流程

Cloudflare Access 是一个身份验证代理,负责在用户连接到您的应用程序之前验证其身份。如下面的图表所示,Access 将 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. 查看用户身份

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_encryptionfirewall 状态检查的用户身份的示例。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"
	}
}

您可以验证源站服务器是否接收到了这些标头。

这篇文档对您有帮助吗?