Skip to content

Commit 1235267

Browse files
PCX-12892 - initial version of the tutorial
1 parent 09ec545 commit 1235267

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed
45.4 KB
Loading
36.7 KB
Loading
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
---
2+
updated: 2024-08-13
3+
category: 🔐 Zero Trust
4+
difficulty: Advanced
5+
pcx_content_type: tutorial
6+
content_type: 📝 Tutorial
7+
title: Augment Clouflare Access SSO capabilities with Cloudflare Workers
8+
---
9+
10+
## Introduction
11+
12+
This tutorial will walk you through extending the single-sign-on (SSO) capabilities of Cloudflare Access with Serverless. Specifically, this guide will demonstrate how to modify requests sent to your secured origin to include additional information from the Cloudflare Access authentication event.
13+
14+
Time to complete: **45 minutes**
15+
16+
## Cloudflare Access authentication flow
17+
18+
Cloudflare Access is an authentication proxy in charge of authenticating and authorization users for your exposed app before they reach it. When anthentication and authorization steps are successful, Cloudflare will insert a [JWT](https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/application-token/) inside the request before it reaches the origin. That is the standard flow and that JWT can then be [verifed on the origin side](https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/validating-json/#validate-jwts).
19+
20+
![extendedflow](~/assets/images/cloudflare-one/applications/access-standard-flow.png)
21+
22+
Sometimes, it is necessary to modify the request or overload it with some extra information coming from that authentication event. Cloudflare Workers is a perfect fit for that task and we'll see in this tutorial how to make that happen.
23+
24+
![standardflow](~/assets/images/cloudflare-one/applications/access-extended-flow-serverless.png)
25+
26+
:::note
27+
28+
This example shows how workers is running right after Access and is in charge of inserting new request headers: **risk_score** and **disk_encrypted**
29+
30+
The [posture](https://developers.cloudflare.com/cloudflare-one/identity/devices/#enforce-device-posture) element serves as a prime example in this article, but the use and application of that concept extends far beyond that. You can indeed modify the request or overload it with anything Clouflare Access is collecting from the authentication event the user has passed before reaching the application.
31+
32+
:::
33+
34+
## Why is this useful?
35+
36+
This approach allows you to:
37+
38+
* **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.
39+
* **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.
40+
* **Simplify development:** By using Cloudflare Workers, you can easily extend your Cloudflare Access configuration without modifying your origin application code.
41+
42+
## Before you begin
43+
44+
45+
Make sure your have:
46+
47+
* An active subscription for [Cloudflare Access](https://developers.cloudflare.com/cloudflare-one/policies/access/) (Zero-trust)
48+
* An active [Workers](https://developers.cloudflare.com/workers/#cloudflare-workers) plan
49+
* An active [self-hosted](https://developers.cloudflare.com/cloudflare-one/applications/configure-apps/self-hosted-apps/#add-a-self-hosted-application) application exposed with an active authentication and authorization policy
50+
* [Cloudflare Wrangler](https://developers.cloudflare.com/workers/wrangler/#wrangler) installed on your machine
51+
52+
53+
## Get started
54+
55+
56+
1. Create a new Workers script
57+
58+
```sh
59+
wrangler init
60+
```
61+
62+
2. Paste the script below in the `~/src/index.js` file
63+
64+
:::note
65+
You can retrieve your Cloudflare Zero-Trust tenant name via Zero-trust > Setting > Custom Pages in the **Team Domain** section
66+
:::
67+
68+
```javascript
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://justalittlebyte.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+
The script uses the [`get-identity`](https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/application-token/#user-identity) endpoint to expand the authentication event using an authenticated method. Once fetched, you get to see the complete disposition of the authentication for the given authentication event, see an example below
115+
116+
```json
117+
{
118+
"id": "P51Tuu01fWHMBjIBvrCK1lK-eUDWs2aQMv03WDqT5oY",
119+
"name": "John Doe",
120+
"email": "[email protected]",
121+
"amr": [
122+
"pwd"
123+
],
124+
"oidc_fields": {
125+
"principalName": "XXXXXX_cloudflare.com#EXT#@XXXXXXcloudflare.onmicrosoft.com"
126+
},
127+
"groups": [
128+
{
129+
"id": "fdaedb59-e9be-4ab7-8001-3e069da54185",
130+
"name": "XXXXX"
131+
}
132+
],
133+
"idp": {
134+
"id": "b9f4d68e-dac1-48b0-b728-ae05a5f0d4b2",
135+
"type": "azureAD"
136+
},
137+
"geo": {
138+
"country": "FR"
139+
},
140+
"user_uuid": "ce40d564-c72f-475f-a9b8-f395f19ad986",
141+
"account_id": "121287a0c6e6260ec930655e6b39a3a8",
142+
"iat": 1724056537,
143+
"devicePosture": {
144+
"f6f9391e-6776-4878-9c60-0cc807dc7dc8": {
145+
"id": "f6f9391e-6776-4878-9c60-0cc807dc7dc8",
146+
"schedule": "5m",
147+
"timestamp": "2024-08-19T08:31:59.274Z",
148+
"description": "",
149+
"type": "disk_encryption",
150+
"check": {
151+
"drives": {
152+
"C": {
153+
"encrypted": true
154+
}
155+
}
156+
},
157+
"success": false,
158+
"rule_name": "Disk Encryption - Windows",
159+
"input": {
160+
"requireAll": true,
161+
"checkDisks": []
162+
},
163+
"a0a8e83d-be75-4aa6-bfa0-5791da6e9186": {
164+
"id": "a0a8e83d-be75-4aa6-bfa0-5791da6e9186",
165+
"schedule": "5m",
166+
"timestamp": "2024-08-19T08:31:59.274Z",
167+
"description": "",
168+
"type": "firewall",
169+
"check": {
170+
"firewall": false
171+
},
172+
"success": false,
173+
"rule_name": "Local Firewall Check - Windows",
174+
"input": {
175+
"enabled": true
176+
}
177+
}
178+
...
179+
}
180+
```
181+
182+
The script is inserting in particular the posture data status into the request header names **Cf-Access-Firewall-Activated** and **Cf-Access-Disk-Encrypted**.
183+
184+
:::note
185+
To view a list of [identity-based](https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/application-token/#user-identity) 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, visit https://www.example.com/cdn-cgi/access/get-identity.
186+
:::
187+
188+
1. Map the script to a route matching your authenticated application by adding the following to the `wrangler.toml` file
189+
190+
```toml
191+
route = { pattern= "app.example.com/*", zone_name="example.com"}
192+
```
193+
194+
4. Deploy the script
195+
196+
```sh
197+
wrangler deploy
198+
```
199+
200+
5. Verify that the header is present for requests succeeding Cloudflare Access Authentication
201+
202+
Below are the request headers as received by the origin
203+
204+
```json
205+
{
206+
"headers": {
207+
"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",
208+
"Accept-Encoding": "gzip",
209+
"Accept-Language": "en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-GB;q=0.6",
210+
"Cf-Access-Authenticated-User-Email": "[email protected]",
211+
"Cf-Access-Disk-Encrypted": "false",
212+
"Cf-Access-Firewall-Activated": "false",
213+
"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"
214+
}
215+
}
216+
```
217+
218+
Voila! 🎉

0 commit comments

Comments
 (0)