Skip to content

Commit 77c1940

Browse files
nouvellonstephranbel
authored andcommitted
PCX-12892 - New tutorial - Extend Cloudflare Access SSO capabilities with serverless (#16128)
* PCX-12892 - initial version of the tutorial * style guide revisions * edit file name * fix partial params * update workers partial to latest format --------- Co-authored-by: Ranbel Sun <[email protected]>
1 parent e735f11 commit 77c1940

File tree

3 files changed

+216
-0
lines changed

3 files changed

+216
-0
lines changed
45.4 KB
Loading
36.7 KB
Loading
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
---
2+
updated: 2024-09-30
3+
category: 🔐 Zero Trust
4+
difficulty: Advanced
5+
pcx_content_type: tutorial
6+
title: Send SSO attributes to Access-protected origins with Workers
7+
---
8+
9+
import { Render, GlossaryTooltip, PackageManagers } from "~/components"
10+
11+
This tutorial will walk you through extending the single-sign-on (SSO) capabilities of [Cloudflare Access](/cloudflare-one/policies/access/) with our serverless computing platform, [Cloudflare Workers](/workers/). Specifically, this guide will demonstrate how to modify requests sent to your secured origin to include additional information from the Cloudflare Access authentication event.
12+
13+
**Time to complete:** 45 minutes
14+
15+
## Authentication flow
16+
17+
[Cloudflare Access](/cloudflare-one/policies/access/) is an authentication proxy in charge of validating a user's identity before they connect to your application. As shown in the diagram below, Access inserts a [JWT](/cloudflare-one/identity/authorization-cookie/application-token/) into the request, which can then be [verified](/cloudflare-one/identity/authorization-cookie/validating-json/#validate-jwts) by the origin server.
18+
19+
![Standard authentication flow for a request to an Access application](~/assets/images/cloudflare-one/applications/access-standard-flow.png)
20+
21+
You can extend this functionality by using a Cloudflare Worker to insert additional HTTP headers into the request. In this example, we will add the [device posture attributes](/cloudflare-one/identity/devices/#enforce-device-posture) `firewall_activated` and `disk_encrypted`, but you can include any attributes that Cloudflare Access collects from the authentication event.
22+
23+
![Extended authentication flow uses a Worker to pass additional request headers to the origin](~/assets/images/cloudflare-one/applications/access-extended-flow-serverless.png)
24+
25+
## Benefits
26+
27+
This approach allows you to:
28+
29+
* **Enhance security:** By incorporating additional information from the authentication event, you can implement more robust security measures. For example, you can use device posture data to enforce access based on device compliance.
30+
* **Improve user experience:** You can personalize the user experience by tailoring content or functionality based on user attributes. For example, you can display different content based on the user's role or location.
31+
* **Simplify development:** By using Cloudflare Workers, you can easily extend your Cloudflare Access configuration without modifying your origin application code.
32+
33+
34+
## Before you begin
35+
36+
- Add a [self-hosted application](/cloudflare-one/applications/configure-apps/self-hosted-apps/) to Cloudflare Access.
37+
- Enable the [Disk encryption](/cloudflare-one/identity/devices/warp-client-checks/disk-encryption/) and [Firewall](/cloudflare-one/identity/devices/warp-client-checks/firewall/) device posture checks.
38+
- Install [Wrangler](/workers/wrangler/install-and-update/) on your local machine.
39+
40+
## 1. Create the Worker
41+
42+
1. Create a new Workers project:
43+
44+
<PackageManagers
45+
type="create"
46+
pkg="cloudflare@latest"
47+
args={"device-posture-worker"}
48+
/>
49+
50+
<Render
51+
file="c3-post-run-steps"
52+
product="workers"
53+
params={{
54+
category: "hello-world",
55+
type: "Hello World Worker",
56+
lang: "JavaScript",
57+
}}
58+
/>
59+
60+
2. Change to the project directory:
61+
62+
```sh
63+
$ cd device-posture-worker
64+
```
65+
66+
3. Copy-paste the following code into `src/index.js`. Be sure to replace `<your-team-name>` with your Zero Trust <GlossaryTooltip term="team name">team name</GlossaryTooltip>.
67+
68+
```js title="index.js"
69+
70+
import { parse } from "cookie";
71+
export default {
72+
async fetch(request, env, ctx) {
73+
// The name of the cookie
74+
const COOKIE_NAME = "CF_Authorization";
75+
const CF_GET_IDENTITY = "https://<your-team-name>.cloudflareaccess.com>/cdn-cgi/access/get-identity";
76+
const cookie = parse(request.headers.get("Cookie") || "");
77+
if (cookie[COOKIE_NAME] != null) {
78+
try {
79+
let id = await (await fetch(CF_GET_IDENTITY, request)).json()
80+
let diskEncryptionStatus = false;
81+
let firewallStatus = false;
82+
83+
for (const checkId in id.devicePosture) {
84+
const check = id.devicePosture[checkId];
85+
if (check.type === "disk_encryption") {
86+
console.log(check.type)
87+
diskEncryptionStatus = check.success;
88+
}
89+
if (check.type === "firewall") {
90+
console.log(check.type)
91+
firewallStatus = check.success;
92+
break;
93+
}
94+
}
95+
//clone request (immutable otherwise) and insert posture values in new header set
96+
let newRequest = await new Request(request)
97+
newRequest.headers.set("Cf-Access-Firewall-Activated", firewallStatus)
98+
newRequest.headers.set("Cf-Access-Disk-Encrypted", firewallStatus)
99+
100+
//sent modified request to origin
101+
return await fetch(newRequest)
102+
103+
} catch (e) {
104+
console.log(e)
105+
return await fetch(request)
106+
}
107+
}
108+
return await fetch(request)
109+
},
110+
};
111+
112+
```
113+
114+
## 2. View the user's identity
115+
116+
The script in `index.js` uses the [`get-identity`](/cloudflare-one/identity/authorization-cookie/application-token/#user-identity) endpoint to fetch a user's complete identity from a Cloudflare Access authentication event. To view a list of available data fields, log in to your Access application and append `/cdn-cgi/access/get-identity` to the URL. For example, if `www.example.com` is behind Access, go to `https://www.example.com/cdn-cgi/access/get-identity`.
117+
118+
Below is an example of a user identity that includes the `disk_encryption` and `firewall` posture checks. The Worker inserts the posture check results into the request headers **Cf-Access-Firewall-Activated** and **Cf-Access-Disk-Encrypted**.
119+
120+
```json title="Example user identity" {33,52}
121+
{
122+
"id": "P51Tuu01fWHMBjIBvrCK1lK-eUDWs2aQMv03WDqT5oY",
123+
"name": "John Doe",
124+
"email": "[email protected]",
125+
"amr": [
126+
"pwd"
127+
],
128+
"oidc_fields": {
129+
"principalName": "XXXXXX_cloudflare.com#EXT#@XXXXXXcloudflare.onmicrosoft.com"
130+
},
131+
"groups": [
132+
{
133+
"id": "fdaedb59-e9be-4ab7-8001-3e069da54185",
134+
"name": "XXXXX"
135+
}
136+
],
137+
"idp": {
138+
"id": "b9f4d68e-dac1-48b0-b728-ae05a5f0d4b2",
139+
"type": "azureAD"
140+
},
141+
"geo": {
142+
"country": "FR"
143+
},
144+
"user_uuid": "ce40d564-c72f-475f-a9b8-f395f19ad986",
145+
"account_id": "121287a0c6e6260ec930655e6b39a3a8",
146+
"iat": 1724056537,
147+
"devicePosture": {
148+
"f6f9391e-6776-4878-9c60-0cc807dc7dc8": {
149+
"id": "f6f9391e-6776-4878-9c60-0cc807dc7dc8",
150+
"schedule": "5m",
151+
"timestamp": "2024-08-19T08:31:59.274Z",
152+
"description": "",
153+
"type": "disk_encryption",
154+
"check": {
155+
"drives": {
156+
"C": {
157+
"encrypted": true
158+
}
159+
}
160+
},
161+
"success": false,
162+
"rule_name": "Disk Encryption - Windows",
163+
"input": {
164+
"requireAll": true,
165+
"checkDisks": []
166+
},
167+
"a0a8e83d-be75-4aa6-bfa0-5791da6e9186": {
168+
"id": "a0a8e83d-be75-4aa6-bfa0-5791da6e9186",
169+
"schedule": "5m",
170+
"timestamp": "2024-08-19T08:31:59.274Z",
171+
"description": "",
172+
"type": "firewall",
173+
"check": {
174+
"firewall": false
175+
},
176+
"success": false,
177+
"rule_name": "Local Firewall Check - Windows",
178+
"input": {
179+
"enabled": true
180+
}
181+
}
182+
...
183+
}
184+
```
185+
186+
## 3. Route the Worker to your application
187+
188+
In `wrangler.toml`, [set up a route](/workers/configuration/routing/routes/) that maps the Worker to your Access application domain:
189+
190+
```toml
191+
route = { pattern= "app.example.com/*", zone_name="example.com"}
192+
```
193+
194+
## 4. Deploy the Worker
195+
196+
```sh
197+
npx wrangler deploy
198+
```
199+
200+
The Worker will now insert the **Cf-Access-Firewall-Activated** and **Cf-Access-Disk-Encrypted** headers into requests that pass your application's Access policies.
201+
202+
```json title="Example request headers" {7,8}
203+
{
204+
"headers": {
205+
"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",
206+
"Accept-Encoding": "gzip",
207+
"Accept-Language": "en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-GB;q=0.6",
208+
"Cf-Access-Authenticated-User-Email": "[email protected]",
209+
"Cf-Access-Disk-Encrypted": "false",
210+
"Cf-Access-Firewall-Activated": "false",
211+
"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"
212+
}
213+
}
214+
```
215+
216+
You can verify that these headers are received by the origin server.

0 commit comments

Comments
 (0)