@infoxchange/make-it-so 2.10.0-internal-testing-vdt-199-add-oidc-auth.8 → 2.10.0-internal-testing-vdt-199-add-oidc-auth-3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -2
- package/dist/cdk-constructs/CloudFrontOidcAuth/auth-check.d.ts.map +1 -0
- package/dist/cdk-constructs/CloudFrontOidcAuth/auth-route.d.ts.map +1 -0
- package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-route.js +2 -5
- package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.d.ts +1 -1
- package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.d.ts.map +1 -1
- package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.js +5 -3
- package/dist/cdk-constructs/index.d.ts +1 -1
- package/dist/cdk-constructs/index.js +1 -1
- package/package.json +2 -3
- package/src/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-check.ts +12 -5
- package/src/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-route.ts +9 -14
- package/src/cdk-constructs/CloudFrontOidcAuth/cloudfront.d.ts +245 -0
- package/src/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.ts +21 -12
- package/src/cdk-constructs/index.ts +1 -1
- package/dist/cdk-constructs/CloudWatchOidcAuth/auth-check.d.ts.map +0 -1
- package/dist/cdk-constructs/CloudWatchOidcAuth/auth-route.d.ts.map +0 -1
- package/dist/lib/utils/source-code.d.ts +0 -2
- package/dist/lib/utils/source-code.d.ts.map +0 -1
- package/dist/lib/utils/source-code.js +0 -1
- package/src/cdk-constructs/CloudWatchOidcAuth/cloudfront.d.ts +0 -243
- package/src/lib/utils/source-code.ts +0 -0
- /package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-check.d.ts +0 -0
- /package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-check.js +0 -0
- /package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-route.d.ts +0 -0
package/README.md
CHANGED
|
@@ -13,8 +13,6 @@ npm --save-dev @infoxchange/make-it-so
|
|
|
13
13
|
yarn add --dev @infoxchange/make-it-so
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
16
|
## Features
|
|
19
17
|
|
|
20
18
|
### deployConfig
|
|
@@ -292,6 +290,30 @@ const vpcDetails = new IxVpcDetails(scope, "VpcDetails");
|
|
|
292
290
|
|
|
293
291
|
</details>
|
|
294
292
|
|
|
293
|
+
<details>
|
|
294
|
+
<summary><strong>CloudFrontOidcAuth</strong> - Adds OIDC authentication to a CloudFront distribution.</summary>
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import { CloudWatchOidcAuth } from "@infoxchange/make-it-so/cdk-constructs";
|
|
298
|
+
|
|
299
|
+
// You first create an instance of CloudFrontOidcAuth
|
|
300
|
+
const auth = new CloudFrontOidcAuth(stack, "CloudFrontOidcAuth", {
|
|
301
|
+
oidcIssuerUrl: "https://your-oidc-server.com/path/",
|
|
302
|
+
oidcClientId: "your-client-id",
|
|
303
|
+
oidcScope: "email",
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Then you apply it to the a CloudFront backed site when it's created
|
|
307
|
+
const site = new IxStaticSite(stack, "IxStaticSite", {
|
|
308
|
+
path: "path/to/site/files",
|
|
309
|
+
cdk: {
|
|
310
|
+
distribution: auth.addToDistributionDefinition(stack, {
|
|
311
|
+
distributionDefinition: {},
|
|
312
|
+
}),
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
295
317
|
## Full Example
|
|
296
318
|
|
|
297
319
|
To deploy a Next.js based site you would include a `sst.config.ts` file at the root of repo with contents like this:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-check.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudFrontOidcAuth/auth-check.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-route.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudFrontOidcAuth/auth-route.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,OAAO,4CAiCnB,CAAC"}
|
|
@@ -24,8 +24,7 @@ export const handler = addRequiredContext(AuthHandler({
|
|
|
24
24
|
issuer: await Issuer.discover(oidcIssuerConfigUrl.href),
|
|
25
25
|
clientID: oidcClientId,
|
|
26
26
|
scope: oidcScope,
|
|
27
|
-
onSuccess: async (tokenset
|
|
28
|
-
console.log("🟣", client);
|
|
27
|
+
onSuccess: async (tokenset) => {
|
|
29
28
|
// Payload to include in the token
|
|
30
29
|
const payload = {
|
|
31
30
|
userID: tokenset.claims().sub,
|
|
@@ -52,11 +51,9 @@ export const handler = addRequiredContext(AuthHandler({
|
|
|
52
51
|
}));
|
|
53
52
|
function addRequiredContext(handler) {
|
|
54
53
|
return async function (...args) {
|
|
55
|
-
const [event
|
|
54
|
+
const [event] = args;
|
|
56
55
|
// Used by AuthHandler to create callback url sent to oidc server
|
|
57
56
|
event.requestContext.domainName = event.headers["x-forwarded-host"];
|
|
58
|
-
console.log("🟢 event", event);
|
|
59
|
-
console.log("🔵 context", context);
|
|
60
57
|
return await handler(...args);
|
|
61
58
|
};
|
|
62
59
|
}
|
|
@@ -10,7 +10,7 @@ type Props = {
|
|
|
10
10
|
oidcClientId: string;
|
|
11
11
|
oidcScope: string;
|
|
12
12
|
};
|
|
13
|
-
export declare class
|
|
13
|
+
export declare class CloudFrontOidcAuth extends Construct {
|
|
14
14
|
readonly oidcIssuerUrl: string;
|
|
15
15
|
readonly oidcClientId: string;
|
|
16
16
|
readonly oidcScope: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudFrontOidcAuth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AASvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAI1E,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,OAAO,CAAC,CAAC,IAAI;IAChB,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC/B,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBAER,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;IAQhE,2BAA2B,CACzB,iBAAiB,SAAS,4BAA4B,EAEtD,KAAK,EAAE,cAAc,EACrB,EACE,sBAAsB,EACtB,MAAgB,GACjB,EAAE;QAAE,sBAAsB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAuC5E,OAAO,CAAC,sBAAsB;IA8H9B,OAAO,CAAC,sBAAsB;CA8E/B"}
|
|
@@ -9,7 +9,7 @@ import { Config as SSTInternalConfig } from "sst/config.js";
|
|
|
9
9
|
import CloudFrontOrigins from "aws-cdk-lib/aws-cloudfront-origins";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import fs from "node:fs";
|
|
12
|
-
export class
|
|
12
|
+
export class CloudFrontOidcAuth extends Construct {
|
|
13
13
|
oidcIssuerUrl;
|
|
14
14
|
oidcClientId;
|
|
15
15
|
oidcScope;
|
|
@@ -126,7 +126,9 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
126
126
|
}
|
|
127
127
|
fn.addEnvironment("NODE_OPTIONS", "--require=@aws-sdk/signature-v4-crt");
|
|
128
128
|
const authCheckFunction = new CloudFront.Function(scope, `${this.id}AuthCheckFunction`, {
|
|
129
|
-
code: CloudFront.FunctionCode.fromInline(fs
|
|
129
|
+
code: CloudFront.FunctionCode.fromInline(fs
|
|
130
|
+
.readFileSync(path.join(import.meta.dirname, "auth-check.js"), "utf8")
|
|
131
|
+
.replace("__placeholder-for-jwt-secret-key__", key)),
|
|
130
132
|
runtime: CloudFront.FunctionRuntime.JS_2_0,
|
|
131
133
|
keyValueStore: cfKeyValueStore,
|
|
132
134
|
});
|
|
@@ -172,7 +174,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
172
174
|
origin: new CloudFrontOrigins.HttpOrigin(CDK.Fn.parseDomainName(authRouteFunctionUrl.url)),
|
|
173
175
|
allowedMethods: CloudFront.AllowedMethods.ALLOW_ALL,
|
|
174
176
|
cachePolicy: new CloudFront.CachePolicy(scope, `${this.id}AllowAllCookiesPolicy`, {
|
|
175
|
-
cachePolicyName:
|
|
177
|
+
cachePolicyName: `${this.id}-AllowAllCookiesPolicy`,
|
|
176
178
|
comment: "Cache policy that forwards all cookies",
|
|
177
179
|
defaultTtl: CDK.Duration.seconds(1),
|
|
178
180
|
minTtl: CDK.Duration.seconds(1),
|
|
@@ -6,5 +6,5 @@ export * from "./IxStaticSite.js";
|
|
|
6
6
|
export * from "./IxElasticache.js";
|
|
7
7
|
export * from "./IxApi.js";
|
|
8
8
|
export * from "./IxQuicksightWorkspace.js";
|
|
9
|
-
export * from "./
|
|
9
|
+
export * from "./CloudFrontOidcAuth/index.js";
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infoxchange/make-it-so",
|
|
3
|
-
"version": "2.10.0-internal-testing-vdt-199-add-oidc-auth.
|
|
3
|
+
"version": "2.10.0-internal-testing-vdt-199-add-oidc-auth-3.1",
|
|
4
4
|
"description": "Makes deploying services to IX infra easy",
|
|
5
5
|
"repository": "github:infoxchange/make-it-so",
|
|
6
6
|
"type": "module",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"@commitlint/prompt-cli": "^19.3.1",
|
|
31
31
|
"@eslint/js": "^9.3.0",
|
|
32
32
|
"@tsconfig/node21": "^21.0.3",
|
|
33
|
+
"@types/aws-cloudfront-function": "^1.0.6",
|
|
33
34
|
"@types/jsonwebtoken": "^9.0.10",
|
|
34
35
|
"aws-cdk-lib": "2.142.1",
|
|
35
36
|
"constructs": "^10.3.0",
|
|
@@ -51,8 +52,6 @@
|
|
|
51
52
|
"sst": "^2.0.0"
|
|
52
53
|
},
|
|
53
54
|
"dependencies": {
|
|
54
|
-
"@aws-sdk/client-lambda": "^3.920.0",
|
|
55
|
-
"@types/aws-cloudfront-function": "^1.0.6",
|
|
56
55
|
"jsonwebtoken": "^9.0.2",
|
|
57
56
|
"zod": "^3.24.2"
|
|
58
57
|
}
|
|
@@ -72,7 +72,13 @@ function _constantTimeEquals(a: string, b: string) {
|
|
|
72
72
|
return 0 === xor;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
function _verify(
|
|
75
|
+
function _verify(
|
|
76
|
+
input: string,
|
|
77
|
+
key: string,
|
|
78
|
+
method: string,
|
|
79
|
+
type: string,
|
|
80
|
+
signature: string,
|
|
81
|
+
) {
|
|
76
82
|
if (type === "hmac") {
|
|
77
83
|
return _constantTimeEquals(signature, _sign(input, key, method));
|
|
78
84
|
} else {
|
|
@@ -97,7 +103,8 @@ async function handler(event: AWSCloudFrontFunction.Event) {
|
|
|
97
103
|
throw new Error("Error retrieving JWT secret key");
|
|
98
104
|
}
|
|
99
105
|
|
|
100
|
-
const jwtToken =
|
|
106
|
+
const jwtToken =
|
|
107
|
+
request.cookies["auth-token"] && request.cookies["auth-token"].value;
|
|
101
108
|
|
|
102
109
|
if (!jwtToken) {
|
|
103
110
|
log("Error: No JWT in the cookies");
|
|
@@ -130,18 +137,18 @@ const log: typeof console.log = function () {
|
|
|
130
137
|
|
|
131
138
|
// CloudFront Function runtime only prints first argument passed to console.log so add other args to the first one if given.
|
|
132
139
|
// eslint-disable-next-line prefer-rest-params -- We can't use spread or rest parameters in CloudFront Functions
|
|
133
|
-
let message = arguments[0]
|
|
140
|
+
let message = arguments[0];
|
|
134
141
|
if (arguments.length > 1) {
|
|
135
142
|
const otherArgs = [];
|
|
136
143
|
for (let i = 1; i < arguments.length; i++) {
|
|
137
144
|
// eslint-disable-next-line prefer-rest-params
|
|
138
|
-
otherArgs[i-1] = arguments[i];
|
|
145
|
+
otherArgs[i - 1] = arguments[i];
|
|
139
146
|
}
|
|
140
147
|
|
|
141
148
|
message += " - additional args: " + JSON.stringify(otherArgs);
|
|
142
149
|
}
|
|
143
150
|
console.log(message);
|
|
144
|
-
}
|
|
151
|
+
};
|
|
145
152
|
|
|
146
153
|
// This serves no purpose other than to make TypeScript and eslint happy by showing that that handler is used. We can't
|
|
147
154
|
// export handler as an alterative because CloudFront Functions don't support exports.
|
|
@@ -30,8 +30,7 @@ export const handler = addRequiredContext(
|
|
|
30
30
|
issuer: await Issuer.discover(oidcIssuerConfigUrl.href),
|
|
31
31
|
clientID: oidcClientId,
|
|
32
32
|
scope: oidcScope,
|
|
33
|
-
onSuccess: async (tokenset
|
|
34
|
-
console.log("🟣", client);
|
|
33
|
+
onSuccess: async (tokenset) => {
|
|
35
34
|
// Payload to include in the token
|
|
36
35
|
const payload = {
|
|
37
36
|
userID: tokenset.claims().sub,
|
|
@@ -39,14 +38,10 @@ export const handler = addRequiredContext(
|
|
|
39
38
|
const expiresInMs = 1000 * 60 * 60;
|
|
40
39
|
|
|
41
40
|
// Create the token
|
|
42
|
-
const token = jwt.sign(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
algorithm: "HS256",
|
|
47
|
-
expiresIn: expiresInMs / 1000,
|
|
48
|
-
}
|
|
49
|
-
);
|
|
41
|
+
const token = jwt.sign(payload, jwtSecret, {
|
|
42
|
+
algorithm: "HS256",
|
|
43
|
+
expiresIn: expiresInMs / 1000,
|
|
44
|
+
});
|
|
50
45
|
const expiryDate = new Date(Date.now() + expiresInMs);
|
|
51
46
|
return {
|
|
52
47
|
statusCode: 302,
|
|
@@ -63,13 +58,13 @@ export const handler = addRequiredContext(
|
|
|
63
58
|
}),
|
|
64
59
|
);
|
|
65
60
|
|
|
66
|
-
function addRequiredContext(
|
|
61
|
+
function addRequiredContext(
|
|
62
|
+
handler: ReturnType<typeof AuthHandler>,
|
|
63
|
+
): ReturnType<typeof AuthHandler> {
|
|
67
64
|
return async function (...args) {
|
|
68
|
-
const [event
|
|
65
|
+
const [event] = args;
|
|
69
66
|
// Used by AuthHandler to create callback url sent to oidc server
|
|
70
67
|
event.requestContext.domainName = event.headers["x-forwarded-host"];
|
|
71
|
-
console.log("🟢 event", event)
|
|
72
|
-
console.log("🔵 context", context)
|
|
73
68
|
|
|
74
69
|
return await handler(...args);
|
|
75
70
|
};
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// NOTE: once this is no longer needed we can remove typeRoots from tsconfig.json as well
|
|
2
|
+
|
|
3
|
+
// This is a copy of @types/aws-cloudfront-function but with optional kvsId in kvs() function. We can't just modify the
|
|
4
|
+
// kvs type since we can't modify the default export without messing up the rest of the types. Which is why we
|
|
5
|
+
// unfortunately have to duplicate the whole file here.
|
|
6
|
+
// But once https://github.com/DefinitelyTyped/DefinitelyTyped/issues/73959 is sorted we can get rid of this.
|
|
7
|
+
|
|
8
|
+
declare namespace AWSCloudFrontFunction {
|
|
9
|
+
interface Event {
|
|
10
|
+
version: "1.0";
|
|
11
|
+
context: Context;
|
|
12
|
+
viewer: Viewer;
|
|
13
|
+
request: Request;
|
|
14
|
+
response: Response;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface Context {
|
|
18
|
+
distributionDomainName: string;
|
|
19
|
+
distributionId: string;
|
|
20
|
+
eventType: "viewer-request" | "viewer-response";
|
|
21
|
+
requestId: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface Viewer {
|
|
25
|
+
ip: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Request {
|
|
29
|
+
method: string;
|
|
30
|
+
uri: string;
|
|
31
|
+
querystring: ValueObject;
|
|
32
|
+
headers: ValueObject;
|
|
33
|
+
cookies: ValueObject;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface Response {
|
|
37
|
+
statusCode: number;
|
|
38
|
+
statusDescription?: string;
|
|
39
|
+
headers?: ValueObject;
|
|
40
|
+
cookies?: ResponseCookie;
|
|
41
|
+
body?: string | ResponseBody;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface ResponseBody {
|
|
45
|
+
data: string;
|
|
46
|
+
encoding: "text" | "base64";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface ValueObject {
|
|
50
|
+
[name: string]: {
|
|
51
|
+
value: string;
|
|
52
|
+
multiValue?: Array<{
|
|
53
|
+
value: string;
|
|
54
|
+
}>;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface ResponseCookie {
|
|
59
|
+
[name: string]: {
|
|
60
|
+
value: string;
|
|
61
|
+
attributes: string;
|
|
62
|
+
multiValue?: Array<{
|
|
63
|
+
value: string;
|
|
64
|
+
attributes: string;
|
|
65
|
+
}>;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
declare module "cloudfront" {
|
|
71
|
+
/**
|
|
72
|
+
* Retrieves a reference to a CloudFront Key-Value Store (KVS) by its ID.
|
|
73
|
+
* @param kvsId The identifier of the KVS to use.
|
|
74
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.html
|
|
75
|
+
*/
|
|
76
|
+
function kvs(kvsId?: string): KVStore;
|
|
77
|
+
|
|
78
|
+
interface KVStore {
|
|
79
|
+
/**
|
|
80
|
+
* Retrieve a value from the store.
|
|
81
|
+
* @param key Key to retrieve.
|
|
82
|
+
* @throws If key does not exist.
|
|
83
|
+
*/
|
|
84
|
+
get(key: string): Promise<string>;
|
|
85
|
+
get(key: string, options: { format: "string" }): Promise<string>;
|
|
86
|
+
get(key: string, options: { format: "bytes" }): Promise<Uint8Array>;
|
|
87
|
+
get(key: string, options: { format: "json" }): Promise<unknown>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if the key exists in the store.
|
|
91
|
+
* @param key Key to check.
|
|
92
|
+
*/
|
|
93
|
+
exists(key: string): Promise<boolean>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Retrieve metadata about the key-value store.
|
|
97
|
+
*/
|
|
98
|
+
meta(): Promise<{
|
|
99
|
+
creationDateTime: string;
|
|
100
|
+
lastUpdatedDateTime: string;
|
|
101
|
+
keyCount: number;
|
|
102
|
+
}>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface OriginAccessControlConfig {
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
signingBehavior: "always" | "never" | "no-override";
|
|
108
|
+
signingProtocol: "sigv4";
|
|
109
|
+
originType: "s3" | "mediapackagev2" | "mediastore" | "lambda";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
interface OriginShield {
|
|
113
|
+
enabled: boolean;
|
|
114
|
+
region: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface Timeouts {
|
|
118
|
+
/**
|
|
119
|
+
* Max time (seconds) to wait for a response or next packet. (1–60)
|
|
120
|
+
*/
|
|
121
|
+
readTimeout?: number;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Max time (seconds) to keep the connection alive after response. (1–60)
|
|
125
|
+
*/
|
|
126
|
+
keepAliveTimeout?: number;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Max time (seconds) to wait for connection establishment. (1–10)
|
|
130
|
+
*/
|
|
131
|
+
connectionTimeout?: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface CustomOriginConfig {
|
|
135
|
+
/**
|
|
136
|
+
* Port number of the origin. e.g., 80 or 443
|
|
137
|
+
*/
|
|
138
|
+
port: number;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Protocol used to connect. Must be "http" or "https"
|
|
142
|
+
*/
|
|
143
|
+
protocol: "http" | "https";
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Minimum TLS/SSL version to use for HTTPS connections.
|
|
147
|
+
*/
|
|
148
|
+
sslProtocols: Array<"SSLv3" | "TLSv1" | "TLSv1.1" | "TLSv1.2">;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface UpdateRequestOriginParams {
|
|
152
|
+
/**
|
|
153
|
+
* New origin's domain name. Optional if reusing existing origin's domain.
|
|
154
|
+
*/
|
|
155
|
+
domainName?: string;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Path prefix to append when forwarding request to origin.
|
|
159
|
+
*/
|
|
160
|
+
originPath?: string;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Override or clear custom headers for the origin request.
|
|
164
|
+
*/
|
|
165
|
+
customHeaders?: Record<string, string>;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Number of connection attempts (1–3).
|
|
169
|
+
*/
|
|
170
|
+
connectionAttempts?: number;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Origin Shield configuration. Enables shield layer if specified.
|
|
174
|
+
*/
|
|
175
|
+
originShield?: OriginShield;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Origin Access Control (OAC) configuration.
|
|
179
|
+
*/
|
|
180
|
+
originAccessControlConfig?: OriginAccessControlConfig;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Response and connection timeout configurations.
|
|
184
|
+
*/
|
|
185
|
+
timeouts?: Timeouts;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Settings for non-S3 origins or S3 with static website hosting.
|
|
189
|
+
*/
|
|
190
|
+
customOriginConfig?: CustomOriginConfig;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Mutates the current request’s origin.
|
|
195
|
+
* You can specify a new origin (e.g., S3 or ALB), change custom headers, enable OAC, or enable Origin Shield.
|
|
196
|
+
* Missing fields will inherit values from the assigned origin.
|
|
197
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#update-request-origin-helper-function
|
|
198
|
+
*/
|
|
199
|
+
function updateRequestOrigin(params: UpdateRequestOriginParams): void;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Switches to another origin already defined in the distribution by origin ID.
|
|
203
|
+
* This is more efficient than defining a new one via `updateRequestOrigin()`.
|
|
204
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#select-request-origin-id-helper-function
|
|
205
|
+
*/
|
|
206
|
+
function selectRequestOriginById(originId: string): void;
|
|
207
|
+
|
|
208
|
+
interface CreateRequestOriginGroupParams {
|
|
209
|
+
/**
|
|
210
|
+
* Two origin IDs to form an origin group.
|
|
211
|
+
* The first is primary; the second is used for failover.
|
|
212
|
+
*/
|
|
213
|
+
originIds: [string, string];
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Failover selection strategy: default or media-quality-score.
|
|
217
|
+
*/
|
|
218
|
+
selectionCriteria?: "default" | "media-quality-score";
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* List of status codes that trigger failover to the secondary origin.
|
|
222
|
+
*/
|
|
223
|
+
failoverCriteria: {
|
|
224
|
+
statusCodes: number[];
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Creates a new origin group for failover logic.
|
|
230
|
+
* The origin group can be referenced later via origin ID.
|
|
231
|
+
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#create-request-origin-group-helper-function
|
|
232
|
+
*/
|
|
233
|
+
function createRequestOriginGroup(
|
|
234
|
+
params: CreateRequestOriginGroupParams,
|
|
235
|
+
): void;
|
|
236
|
+
|
|
237
|
+
const cf: {
|
|
238
|
+
kvs: typeof kvs;
|
|
239
|
+
updateRequestOrigin: typeof updateRequestOrigin;
|
|
240
|
+
selectRequestOriginById: typeof selectRequestOriginById;
|
|
241
|
+
createRequestOriginGroup: typeof createRequestOriginGroup;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export default cf;
|
|
245
|
+
}
|
|
@@ -24,7 +24,7 @@ type Props = {
|
|
|
24
24
|
oidcScope: string;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
export class
|
|
27
|
+
export class CloudFrontOidcAuth extends Construct {
|
|
28
28
|
readonly oidcIssuerUrl: string;
|
|
29
29
|
readonly oidcClientId: string;
|
|
30
30
|
readonly oidcScope: string;
|
|
@@ -192,7 +192,12 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
192
192
|
`${this.id}AuthCheckFunction`,
|
|
193
193
|
{
|
|
194
194
|
code: CloudFront.FunctionCode.fromInline(
|
|
195
|
-
fs
|
|
195
|
+
fs
|
|
196
|
+
.readFileSync(
|
|
197
|
+
path.join(import.meta.dirname, "auth-check.js"),
|
|
198
|
+
"utf8",
|
|
199
|
+
)
|
|
200
|
+
.replace("__placeholder-for-jwt-secret-key__", key),
|
|
196
201
|
),
|
|
197
202
|
runtime: CloudFront.FunctionRuntime.JS_2_0,
|
|
198
203
|
keyValueStore: cfKeyValueStore,
|
|
@@ -210,16 +215,20 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
210
215
|
jwtSecret: SecretsManager.Secret,
|
|
211
216
|
prefix: string,
|
|
212
217
|
): CloudFront.BehaviorOptions {
|
|
213
|
-
const authRouteFunction = new SST.Function(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
218
|
+
const authRouteFunction = new SST.Function(
|
|
219
|
+
scope,
|
|
220
|
+
`${this.id}AuthRouteFunction`,
|
|
221
|
+
{
|
|
222
|
+
runtime: "nodejs20.x",
|
|
223
|
+
handler: path.join(import.meta.dirname, "auth-route.handler"),
|
|
224
|
+
environment: {
|
|
225
|
+
OIDC_ISSUER_URL: this.oidcIssuerUrl,
|
|
226
|
+
OIDC_CLIENT_ID: this.oidcClientId,
|
|
227
|
+
OIDC_SCOPE: this.oidcScope,
|
|
228
|
+
JWT_SECRET: jwtSecret.secretValue.toString(),
|
|
229
|
+
},
|
|
221
230
|
},
|
|
222
|
-
|
|
231
|
+
);
|
|
223
232
|
|
|
224
233
|
// authRouteFunction uses SST's AuthHandler construct which is normally run inside a lambda that's
|
|
225
234
|
// created by SST's Auth construct. AuthHandler expects certain environment variables to be set
|
|
@@ -258,7 +267,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
258
267
|
scope,
|
|
259
268
|
`${this.id}AllowAllCookiesPolicy`,
|
|
260
269
|
{
|
|
261
|
-
cachePolicyName:
|
|
270
|
+
cachePolicyName: `${this.id}-AllowAllCookiesPolicy`,
|
|
262
271
|
comment: "Cache policy that forwards all cookies",
|
|
263
272
|
defaultTtl: CDK.Duration.seconds(1),
|
|
264
273
|
minTtl: CDK.Duration.seconds(1),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth-check.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/auth-check.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth-route.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/auth-route.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,OAAO,4CAsCnB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"source-code.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/source-code.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
// NOTE: once this is no longer needed we can remove typeRoots from tsconfig.json as well
|
|
2
|
-
|
|
3
|
-
// This is a copy of @types/aws-cloudfront-function but with optional kvsId in kvs() function. We can't just modify the
|
|
4
|
-
// kvs type since we can't modify the default export without messing up the rest of the types. Which is why we
|
|
5
|
-
// unfortunately have to duplicate the whole file here.
|
|
6
|
-
// But once https://github.com/DefinitelyTyped/DefinitelyTyped/issues/73959 is sorted we can get rid of this.
|
|
7
|
-
|
|
8
|
-
declare namespace AWSCloudFrontFunction {
|
|
9
|
-
interface Event {
|
|
10
|
-
version: "1.0";
|
|
11
|
-
context: Context;
|
|
12
|
-
viewer: Viewer;
|
|
13
|
-
request: Request;
|
|
14
|
-
response: Response;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface Context {
|
|
18
|
-
distributionDomainName: string;
|
|
19
|
-
distributionId: string;
|
|
20
|
-
eventType: "viewer-request" | "viewer-response";
|
|
21
|
-
requestId: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface Viewer {
|
|
25
|
-
ip: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface Request {
|
|
29
|
-
method: string;
|
|
30
|
-
uri: string;
|
|
31
|
-
querystring: ValueObject;
|
|
32
|
-
headers: ValueObject;
|
|
33
|
-
cookies: ValueObject;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface Response {
|
|
37
|
-
statusCode: number;
|
|
38
|
-
statusDescription?: string;
|
|
39
|
-
headers?: ValueObject;
|
|
40
|
-
cookies?: ResponseCookie;
|
|
41
|
-
body?: string | ResponseBody;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface ResponseBody {
|
|
45
|
-
data: string;
|
|
46
|
-
encoding: "text" | "base64";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
interface ValueObject {
|
|
50
|
-
[name: string]: {
|
|
51
|
-
value: string;
|
|
52
|
-
multiValue?: Array<{
|
|
53
|
-
value: string;
|
|
54
|
-
}>;
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
interface ResponseCookie {
|
|
59
|
-
[name: string]: {
|
|
60
|
-
value: string;
|
|
61
|
-
attributes: string;
|
|
62
|
-
multiValue?: Array<{
|
|
63
|
-
value: string;
|
|
64
|
-
attributes: string;
|
|
65
|
-
}>;
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
declare module "cloudfront" {
|
|
71
|
-
/**
|
|
72
|
-
* Retrieves a reference to a CloudFront Key-Value Store (KVS) by its ID.
|
|
73
|
-
* @param kvsId The identifier of the KVS to use.
|
|
74
|
-
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.html
|
|
75
|
-
*/
|
|
76
|
-
function kvs(kvsId?: string): KVStore;
|
|
77
|
-
|
|
78
|
-
interface KVStore {
|
|
79
|
-
/**
|
|
80
|
-
* Retrieve a value from the store.
|
|
81
|
-
* @param key Key to retrieve.
|
|
82
|
-
* @throws If key does not exist.
|
|
83
|
-
*/
|
|
84
|
-
get(key: string): Promise<string>;
|
|
85
|
-
get(key: string, options: { format: "string" }): Promise<string>;
|
|
86
|
-
get(key: string, options: { format: "bytes" }): Promise<Uint8Array>;
|
|
87
|
-
get(key: string, options: { format: "json" }): Promise<unknown>;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Check if the key exists in the store.
|
|
91
|
-
* @param key Key to check.
|
|
92
|
-
*/
|
|
93
|
-
exists(key: string): Promise<boolean>;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Retrieve metadata about the key-value store.
|
|
97
|
-
*/
|
|
98
|
-
meta(): Promise<{
|
|
99
|
-
creationDateTime: string;
|
|
100
|
-
lastUpdatedDateTime: string;
|
|
101
|
-
keyCount: number;
|
|
102
|
-
}>;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
interface OriginAccessControlConfig {
|
|
106
|
-
enabled: boolean;
|
|
107
|
-
signingBehavior: "always" | "never" | "no-override";
|
|
108
|
-
signingProtocol: "sigv4";
|
|
109
|
-
originType: "s3" | "mediapackagev2" | "mediastore" | "lambda";
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
interface OriginShield {
|
|
113
|
-
enabled: boolean;
|
|
114
|
-
region: string;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
interface Timeouts {
|
|
118
|
-
/**
|
|
119
|
-
* Max time (seconds) to wait for a response or next packet. (1–60)
|
|
120
|
-
*/
|
|
121
|
-
readTimeout?: number;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Max time (seconds) to keep the connection alive after response. (1–60)
|
|
125
|
-
*/
|
|
126
|
-
keepAliveTimeout?: number;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Max time (seconds) to wait for connection establishment. (1–10)
|
|
130
|
-
*/
|
|
131
|
-
connectionTimeout?: number;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
interface CustomOriginConfig {
|
|
135
|
-
/**
|
|
136
|
-
* Port number of the origin. e.g., 80 or 443
|
|
137
|
-
*/
|
|
138
|
-
port: number;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Protocol used to connect. Must be "http" or "https"
|
|
142
|
-
*/
|
|
143
|
-
protocol: "http" | "https";
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Minimum TLS/SSL version to use for HTTPS connections.
|
|
147
|
-
*/
|
|
148
|
-
sslProtocols: Array<"SSLv3" | "TLSv1" | "TLSv1.1" | "TLSv1.2">;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
interface UpdateRequestOriginParams {
|
|
152
|
-
/**
|
|
153
|
-
* New origin's domain name. Optional if reusing existing origin's domain.
|
|
154
|
-
*/
|
|
155
|
-
domainName?: string;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Path prefix to append when forwarding request to origin.
|
|
159
|
-
*/
|
|
160
|
-
originPath?: string;
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Override or clear custom headers for the origin request.
|
|
164
|
-
*/
|
|
165
|
-
customHeaders?: Record<string, string>;
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Number of connection attempts (1–3).
|
|
169
|
-
*/
|
|
170
|
-
connectionAttempts?: number;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Origin Shield configuration. Enables shield layer if specified.
|
|
174
|
-
*/
|
|
175
|
-
originShield?: OriginShield;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Origin Access Control (OAC) configuration.
|
|
179
|
-
*/
|
|
180
|
-
originAccessControlConfig?: OriginAccessControlConfig;
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Response and connection timeout configurations.
|
|
184
|
-
*/
|
|
185
|
-
timeouts?: Timeouts;
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Settings for non-S3 origins or S3 with static website hosting.
|
|
189
|
-
*/
|
|
190
|
-
customOriginConfig?: CustomOriginConfig;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Mutates the current request’s origin.
|
|
195
|
-
* You can specify a new origin (e.g., S3 or ALB), change custom headers, enable OAC, or enable Origin Shield.
|
|
196
|
-
* Missing fields will inherit values from the assigned origin.
|
|
197
|
-
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#update-request-origin-helper-function
|
|
198
|
-
*/
|
|
199
|
-
function updateRequestOrigin(params: UpdateRequestOriginParams): void;
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Switches to another origin already defined in the distribution by origin ID.
|
|
203
|
-
* This is more efficient than defining a new one via `updateRequestOrigin()`.
|
|
204
|
-
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#select-request-origin-id-helper-function
|
|
205
|
-
*/
|
|
206
|
-
function selectRequestOriginById(originId: string): void;
|
|
207
|
-
|
|
208
|
-
interface CreateRequestOriginGroupParams {
|
|
209
|
-
/**
|
|
210
|
-
* Two origin IDs to form an origin group.
|
|
211
|
-
* The first is primary; the second is used for failover.
|
|
212
|
-
*/
|
|
213
|
-
originIds: [string, string];
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Failover selection strategy: default or media-quality-score.
|
|
217
|
-
*/
|
|
218
|
-
selectionCriteria?: "default" | "media-quality-score";
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* List of status codes that trigger failover to the secondary origin.
|
|
222
|
-
*/
|
|
223
|
-
failoverCriteria: {
|
|
224
|
-
statusCodes: number[];
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Creates a new origin group for failover logic.
|
|
230
|
-
* The origin group can be referenced later via origin ID.
|
|
231
|
-
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#create-request-origin-group-helper-function
|
|
232
|
-
*/
|
|
233
|
-
function createRequestOriginGroup(params: CreateRequestOriginGroupParams): void;
|
|
234
|
-
|
|
235
|
-
const cf: {
|
|
236
|
-
kvs: typeof kvs;
|
|
237
|
-
updateRequestOrigin: typeof updateRequestOrigin;
|
|
238
|
-
selectRequestOriginById: typeof selectRequestOriginById;
|
|
239
|
-
createRequestOriginGroup: typeof createRequestOriginGroup;
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
export default cf;
|
|
243
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|