@aws/nx-plugin 0.0.0
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 +63 -0
- package/generators.json +52 -0
- package/package.json +27 -0
- package/src/cloudscape-website/app/README.md +253 -0
- package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +539 -0
- package/src/cloudscape-website/app/files/app/src/config.ts.template +4 -0
- package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +132 -0
- package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +8 -0
- package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +18 -0
- package/src/cloudscape-website/app/files/app/src/main.tsx.template +22 -0
- package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +25 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +317 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +4 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/static-website.ts.template +237 -0
- package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +301 -0
- package/src/cloudscape-website/app/files/e2e/cypress/src/e2e/app.cy.ts.template +13 -0
- package/src/cloudscape-website/app/files/e2e/cypress/src/support/app.po.ts.template +1 -0
- package/src/cloudscape-website/app/files/e2e/playwright/src/example.spec.ts.template +6 -0
- package/src/cloudscape-website/app/generator.d.ts +4 -0
- package/src/cloudscape-website/app/generator.js +177 -0
- package/src/cloudscape-website/app/generator.js.map +1 -0
- package/src/cloudscape-website/app/schema.d.js +6 -0
- package/src/cloudscape-website/app/schema.d.js.map +1 -0
- package/src/cloudscape-website/app/schema.d.ts +35 -0
- package/src/cloudscape-website/app/schema.json +189 -0
- package/src/cloudscape-website/cognito-auth/README.md +172 -0
- package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +238 -0
- package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +50 -0
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +4 -0
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +69 -0
- package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +70 -0
- package/src/cloudscape-website/cognito-auth/generator.d.ts +4 -0
- package/src/cloudscape-website/cognito-auth/generator.js +100 -0
- package/src/cloudscape-website/cognito-auth/generator.js.map +1 -0
- package/src/cloudscape-website/cognito-auth/schema.d.js +6 -0
- package/src/cloudscape-website/cognito-auth/schema.d.js.map +1 -0
- package/src/cloudscape-website/cognito-auth/schema.d.ts +4 -0
- package/src/cloudscape-website/cognito-auth/schema.json +36 -0
- package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +112 -0
- package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +46 -0
- package/src/cloudscape-website/runtime-config/generator.d.ts +4 -0
- package/src/cloudscape-website/runtime-config/generator.js +74 -0
- package/src/cloudscape-website/runtime-config/generator.js.map +1 -0
- package/src/cloudscape-website/runtime-config/schema.d.js +6 -0
- package/src/cloudscape-website/runtime-config/schema.d.js.map +1 -0
- package/src/cloudscape-website/runtime-config/schema.d.ts +3 -0
- package/src/cloudscape-website/runtime-config/schema.json +19 -0
- package/src/gitlab/files/.gitlab-ci.yml.template +26 -0
- package/src/gitlab/generator.d.ts +4 -0
- package/src/gitlab/generator.js +26 -0
- package/src/gitlab/generator.js.map +1 -0
- package/src/gitlab/schema.d.js +6 -0
- package/src/gitlab/schema.d.js.map +1 -0
- package/src/gitlab/schema.d.ts +5 -0
- package/src/gitlab/schema.json +52 -0
- package/src/index.d.ts +0 -0
- package/src/index.js +3 -0
- package/src/index.js.map +1 -0
- package/src/infra/app/README.md +175 -0
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +864 -0
- package/src/infra/app/files/cdk.json +67 -0
- package/src/infra/app/files/src/main.ts.template +37 -0
- package/src/infra/app/files/src/stacks/application-stack.ts.template +10 -0
- package/src/infra/app/generator.d.ts +4 -0
- package/src/infra/app/generator.js +75 -0
- package/src/infra/app/generator.js.map +1 -0
- package/src/infra/app/schema.d.js +6 -0
- package/src/infra/app/schema.d.js.map +1 -0
- package/src/infra/app/schema.d.ts +6 -0
- package/src/infra/app/schema.json +35 -0
- package/src/trpc/backend/README.md +549 -0
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +110 -0
- package/src/trpc/backend/files/backend/src/index.ts.template +1 -0
- package/src/trpc/backend/files/backend/src/lambdas/index.ts.template +1 -0
- package/src/trpc/backend/files/backend/src/lambdas/middleware.ts.template +146 -0
- package/src/trpc/backend/files/backend/src/lambdas/router.ts.template +36 -0
- package/src/trpc/backend/files/common/constructs/src/__apiNameKebabCase__/index.ts.template +64 -0
- package/src/trpc/backend/files/schema/src/index.ts.template +7 -0
- package/src/trpc/backend/generator.d.ts +4 -0
- package/src/trpc/backend/generator.js +128 -0
- package/src/trpc/backend/generator.js.map +1 -0
- package/src/trpc/backend/schema.d.js +6 -0
- package/src/trpc/backend/schema.d.js.map +1 -0
- package/src/trpc/backend/schema.d.ts +8 -0
- package/src/trpc/backend/schema.json +44 -0
- package/src/trpc/react/README.md +320 -0
- package/src/trpc/react/__snapshots__/generator.spec.ts.snap +98 -0
- package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +34 -0
- package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +5 -0
- package/src/trpc/react/generator.d.ts +4 -0
- package/src/trpc/react/generator.js +81 -0
- package/src/trpc/react/generator.js.map +1 -0
- package/src/trpc/react/schema.d.js +6 -0
- package/src/trpc/react/schema.d.js.map +1 -0
- package/src/trpc/react/schema.d.ts +5 -0
- package/src/trpc/react/schema.json +32 -0
- package/src/ts/cjs-to-esm/generator.d.ts +8 -0
- package/src/ts/cjs-to-esm/generator.js +201 -0
- package/src/ts/cjs-to-esm/generator.js.map +1 -0
- package/src/ts/cjs-to-esm/schema.d.js +6 -0
- package/src/ts/cjs-to-esm/schema.d.js.map +1 -0
- package/src/ts/cjs-to-esm/schema.d.ts +5 -0
- package/src/ts/cjs-to-esm/schema.json +28 -0
- package/src/ts/lib/README.md +149 -0
- package/src/ts/lib/__snapshots__/generator.spec.ts.snap +260 -0
- package/src/ts/lib/eslint.d.ts +3 -0
- package/src/ts/lib/eslint.js +41 -0
- package/src/ts/lib/eslint.js.map +1 -0
- package/src/ts/lib/files/src/index.ts.template +3 -0
- package/src/ts/lib/generator.d.ts +21 -0
- package/src/ts/lib/generator.js +61 -0
- package/src/ts/lib/generator.js.map +1 -0
- package/src/ts/lib/schema.d.js +6 -0
- package/src/ts/lib/schema.d.js.map +1 -0
- package/src/ts/lib/schema.d.ts +13 -0
- package/src/ts/lib/schema.json +46 -0
- package/src/ts/lib/ts-project-utils.d.ts +6 -0
- package/src/ts/lib/ts-project-utils.js +107 -0
- package/src/ts/lib/ts-project-utils.js.map +1 -0
- package/src/ts/lib/types.d.ts +10 -0
- package/src/ts/lib/types.js +6 -0
- package/src/ts/lib/types.js.map +1 -0
- package/src/ts/lib/vitest.d.ts +3 -0
- package/src/ts/lib/vitest.js +67 -0
- package/src/ts/lib/vitest.js.map +1 -0
- package/src/utils/files/common/constructs/src/index.ts.template +1 -0
- package/src/utils/files/common/constructs/src/runtime-config/index.ts.template +1 -0
- package/src/utils/files/common/constructs/src/runtime-config/runtime-config.ts.template +33 -0
- package/src/utils/files/common/types/src/index.ts.template +1 -0
- package/src/utils/files/common/types/src/runtime-config.ts.template +13 -0
- package/src/utils/npm-scope.d.ts +7 -0
- package/src/utils/npm-scope.js +37 -0
- package/src/utils/npm-scope.js.map +1 -0
- package/src/utils/paths.d.ts +3 -0
- package/src/utils/paths.js +32 -0
- package/src/utils/paths.js.map +1 -0
- package/src/utils/shared-constructs.d.ts +7 -0
- package/src/utils/shared-constructs.js +72 -0
- package/src/utils/shared-constructs.js.map +1 -0
- package/src/utils/versions.d.ts +31 -0
- package/src/utils/versions.js +49 -0
- package/src/utils/versions.js.map +1 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Route, Routes as ReactRoutes } from "react-router-dom";
|
|
5
|
+
import Home from "../../pages/Home";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Defines the Routes.
|
|
9
|
+
*/
|
|
10
|
+
const Routes: React.FC = () => {
|
|
11
|
+
return (
|
|
12
|
+
<ReactRoutes>
|
|
13
|
+
<Route key={0} path="/" element={<Home />} />
|
|
14
|
+
</ReactRoutes>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default Routes;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
3
|
+
import { NorthStarThemeProvider } from "@aws-northstar/ui";
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { createRoot } from "react-dom/client";
|
|
6
|
+
import { BrowserRouter } from "react-router-dom";
|
|
7
|
+
import { I18nProvider } from '@cloudscape-design/components/i18n';
|
|
8
|
+
import messages from '@cloudscape-design/components/i18n/messages/all.en';
|
|
9
|
+
import App from "./layouts/App";
|
|
10
|
+
|
|
11
|
+
const root = document.getElementById("root");
|
|
12
|
+
root && createRoot(root).render(
|
|
13
|
+
<React.StrictMode>
|
|
14
|
+
<NorthStarThemeProvider>
|
|
15
|
+
<I18nProvider locale="en" messages={[messages]}>
|
|
16
|
+
<BrowserRouter>
|
|
17
|
+
<App />
|
|
18
|
+
</BrowserRouter>
|
|
19
|
+
</I18nProvider>
|
|
20
|
+
</NorthStarThemeProvider>
|
|
21
|
+
</React.StrictMode>
|
|
22
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
3
|
+
import {
|
|
4
|
+
Container,
|
|
5
|
+
ContentLayout,
|
|
6
|
+
Header,
|
|
7
|
+
SpaceBetween,
|
|
8
|
+
} from "@cloudscape-design/components";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Component to render the home "/" route.
|
|
12
|
+
*/
|
|
13
|
+
const Home: React.FC = () => {
|
|
14
|
+
return (
|
|
15
|
+
<ContentLayout header={<Header>Home</Header>}>
|
|
16
|
+
<SpaceBetween size="l">
|
|
17
|
+
<Container>
|
|
18
|
+
Hello World!
|
|
19
|
+
</Container>
|
|
20
|
+
</SpaceBetween>
|
|
21
|
+
</ContentLayout>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default Home;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
3
|
+
import * as url from "url";
|
|
4
|
+
import { PDKNag } from "@aws/pdk/pdk-nag";
|
|
5
|
+
import { CustomResource, Duration, Stack } from "aws-cdk-lib";
|
|
6
|
+
import {
|
|
7
|
+
Effect,
|
|
8
|
+
PolicyDocument,
|
|
9
|
+
PolicyStatement,
|
|
10
|
+
Role,
|
|
11
|
+
ServicePrincipal,
|
|
12
|
+
} from "aws-cdk-lib/aws-iam";
|
|
13
|
+
import { Runtime } from "aws-cdk-lib/aws-lambda";
|
|
14
|
+
import { Provider } from "aws-cdk-lib/custom-resources";
|
|
15
|
+
import { NagSuppressions } from "cdk-nag";
|
|
16
|
+
import { Construct } from "constructs";
|
|
17
|
+
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents a WAF V2 managed rule.
|
|
21
|
+
*/
|
|
22
|
+
export interface ManagedRule {
|
|
23
|
+
/**
|
|
24
|
+
* The name of the managed rule group vendor. You use this, along with the rule group name, to identify the rule group.
|
|
25
|
+
*/
|
|
26
|
+
readonly vendor: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The name of the managed rule group. You use this, along with the vendor name, to identify the rule group.
|
|
30
|
+
*/
|
|
31
|
+
readonly name: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Type of Cidr.
|
|
36
|
+
*/
|
|
37
|
+
export type CidrType = "IPV4" | "IPV6";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Representation of a CIDR range.
|
|
41
|
+
*/
|
|
42
|
+
export interface CidrAllowList {
|
|
43
|
+
/**
|
|
44
|
+
* Type of CIDR range.
|
|
45
|
+
*/
|
|
46
|
+
readonly cidrType: CidrType;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Specify an IPv4 address by using CIDR notation. For example:
|
|
50
|
+
* To configure AWS WAF to allow, block, or count requests that originated from the IP address 192.0.2.44, specify 192.0.2.44/32 .
|
|
51
|
+
* To configure AWS WAF to allow, block, or count requests that originated from IP addresses from 192.0.2.0 to 192.0.2.255, specify 192.0.2.0/24 .
|
|
52
|
+
*
|
|
53
|
+
* For more information about CIDR notation, see the Wikipedia entry Classless Inter-Domain Routing .
|
|
54
|
+
*
|
|
55
|
+
* Specify an IPv6 address by using CIDR notation. For example:
|
|
56
|
+
* To configure AWS WAF to allow, block, or count requests that originated from the IP address 1111:0000:0000:0000:0000:0000:0000:0111, specify 1111:0000:0000:0000:0000:0000:0000:0111/128 .
|
|
57
|
+
* To configure AWS WAF to allow, block, or count requests that originated from IP addresses 1111:0000:0000:0000:0000:0000:0000:0000 to 1111:0000:0000:0000:ffff:ffff:ffff:ffff, specify 1111:0000:0000:0000:0000:0000:0000:0000/64 .
|
|
58
|
+
*/
|
|
59
|
+
readonly cidrRanges: string[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Properties to configure the web acl.
|
|
64
|
+
*/
|
|
65
|
+
export interface CloudFrontWebAclProps {
|
|
66
|
+
/**
|
|
67
|
+
* List of managed rules to apply to the web acl.
|
|
68
|
+
*
|
|
69
|
+
* @default - [{ vendor: "AWS", name: "AWSManagedRulesCommonRuleSet" }]
|
|
70
|
+
*/
|
|
71
|
+
readonly managedRules?: ManagedRule[];
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* List of cidr ranges to allow.
|
|
75
|
+
*
|
|
76
|
+
* @default - undefined
|
|
77
|
+
*/
|
|
78
|
+
readonly cidrAllowList?: CidrAllowList;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Set to true to prevent creation of a web acl for the static website
|
|
82
|
+
* @default false
|
|
83
|
+
*/
|
|
84
|
+
readonly disable?: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* This construct creates a WAFv2 Web ACL for cloudfront in the us-east-1 region (required for cloudfront) no matter the
|
|
89
|
+
* region of the parent cdk stack.
|
|
90
|
+
*/
|
|
91
|
+
export class CloudfrontWebAcl extends Construct {
|
|
92
|
+
public readonly webAclId: string;
|
|
93
|
+
public readonly webAclArn: string;
|
|
94
|
+
|
|
95
|
+
constructor(scope: Construct, id: string, props?: CloudFrontWebAclProps) {
|
|
96
|
+
super(scope, id);
|
|
97
|
+
|
|
98
|
+
const stack = Stack.of(this);
|
|
99
|
+
const aclName = `${stack.stackName}-${id}-${this.node.addr.slice(-4)}`;
|
|
100
|
+
const onEventHandler = this.createOnEventHandler(stack, aclName);
|
|
101
|
+
const customResource = this.createAclCustomResource(
|
|
102
|
+
stack,
|
|
103
|
+
aclName,
|
|
104
|
+
onEventHandler,
|
|
105
|
+
props
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
this.webAclId = customResource.getAttString("WebAclId");
|
|
109
|
+
this.webAclArn = customResource.getAttString("WebAclArn");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Creates an event handler for managing an ACL in us-east-1.
|
|
114
|
+
*
|
|
115
|
+
* @param stack containing Stack instance.
|
|
116
|
+
* @param aclName name of the ACL to manage.
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
private createOnEventHandler(stack: Stack, aclName: string): NodejsFunction {
|
|
120
|
+
// NB without manually defining a name, the cdk generated name for the Provider function can become too long and
|
|
121
|
+
// deployments fail. This is because the Provider's name references the onEvent handler name and appends "-Provider"
|
|
122
|
+
// rather than being generated by cdk and truncated appropriately
|
|
123
|
+
const onEventHandlerName = `${PDKNag.getStackPrefix(stack)
|
|
124
|
+
.split("/")
|
|
125
|
+
.join("-")}AclEvent-${this.node.addr.slice(-6)}`;
|
|
126
|
+
const onEventHandlerRole = new Role(this, "OnEventHandlerRole", {
|
|
127
|
+
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
|
|
128
|
+
inlinePolicies: {
|
|
129
|
+
logs: new PolicyDocument({
|
|
130
|
+
statements: [
|
|
131
|
+
new PolicyStatement({
|
|
132
|
+
effect: Effect.ALLOW,
|
|
133
|
+
actions: [
|
|
134
|
+
"logs:CreateLogGroup",
|
|
135
|
+
"logs:CreateLogStream",
|
|
136
|
+
"logs:PutLogEvents",
|
|
137
|
+
],
|
|
138
|
+
resources: [
|
|
139
|
+
`arn:aws:logs:${stack.region}:${stack.account}:log-group:/aws/lambda/${onEventHandlerName}`,
|
|
140
|
+
`arn:aws:logs:${stack.region}:${stack.account}:log-group:/aws/lambda/${onEventHandlerName}:*`,
|
|
141
|
+
],
|
|
142
|
+
}),
|
|
143
|
+
],
|
|
144
|
+
}),
|
|
145
|
+
wafv2: new PolicyDocument({
|
|
146
|
+
statements: [
|
|
147
|
+
new PolicyStatement({
|
|
148
|
+
effect: Effect.ALLOW,
|
|
149
|
+
actions: [
|
|
150
|
+
"wafv2:CreateWebACL",
|
|
151
|
+
"wafv2:DeleteWebACL",
|
|
152
|
+
"wafv2:UpdateWebACL",
|
|
153
|
+
"wafv2:GetWebACL",
|
|
154
|
+
],
|
|
155
|
+
resources: [
|
|
156
|
+
`arn:aws:wafv2:us-east-1:${stack.account}:global/ipset/${aclName}-IPSet/*`,
|
|
157
|
+
`arn:aws:wafv2:us-east-1:${stack.account}:global/webacl/${aclName}/*`,
|
|
158
|
+
`arn:aws:wafv2:us-east-1:${stack.account}:global/managedruleset/*/*`,
|
|
159
|
+
],
|
|
160
|
+
}),
|
|
161
|
+
new PolicyStatement({
|
|
162
|
+
effect: Effect.ALLOW,
|
|
163
|
+
actions: [
|
|
164
|
+
"wafv2:CreateIPSet",
|
|
165
|
+
"wafv2:DeleteIPSet",
|
|
166
|
+
"wafv2:UpdateIPSet",
|
|
167
|
+
"wafv2:GetIPSet",
|
|
168
|
+
],
|
|
169
|
+
resources: [
|
|
170
|
+
`arn:aws:wafv2:us-east-1:${stack.account}:global/ipset/${aclName}-IPSet/*`,
|
|
171
|
+
],
|
|
172
|
+
}),
|
|
173
|
+
],
|
|
174
|
+
}),
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const onEventHandler = new NodejsFunction(
|
|
179
|
+
this,
|
|
180
|
+
"CloudfrontWebAclOnEventHandler",
|
|
181
|
+
{
|
|
182
|
+
entry: url.fileURLToPath(new URL('./webacl_event_handler/index.ts', import.meta.url)),
|
|
183
|
+
role: onEventHandlerRole,
|
|
184
|
+
functionName: onEventHandlerName,
|
|
185
|
+
handler: "onEvent",
|
|
186
|
+
runtime: Runtime.NODEJS_18_X,
|
|
187
|
+
timeout: Duration.seconds(300),
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
["AwsSolutions-IAM5", "AwsPrototyping-IAMNoWildcardPermissions"].forEach(
|
|
192
|
+
(RuleId) => {
|
|
193
|
+
NagSuppressions.addResourceSuppressions(
|
|
194
|
+
onEventHandlerRole,
|
|
195
|
+
[
|
|
196
|
+
{
|
|
197
|
+
id: RuleId,
|
|
198
|
+
reason:
|
|
199
|
+
"WafV2 resources have been scoped down to the ACL/IPSet level, however * is still needed as resource id's are created just in time.",
|
|
200
|
+
appliesTo: [
|
|
201
|
+
{
|
|
202
|
+
regex: `/^Resource::arn:aws:wafv2:us-east-1:${PDKNag.getStackAccountRegex(
|
|
203
|
+
stack
|
|
204
|
+
)}:global/(.*)$/g`,
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: RuleId,
|
|
210
|
+
reason:
|
|
211
|
+
"Cloudwatch resources have been scoped down to the LogGroup level, however * is still needed as stream names are created just in time.",
|
|
212
|
+
appliesTo: [
|
|
213
|
+
{
|
|
214
|
+
regex: `/^Resource::arn:aws:logs:${PDKNag.getStackRegionRegex(
|
|
215
|
+
stack
|
|
216
|
+
)}:${PDKNag.getStackAccountRegex(
|
|
217
|
+
stack
|
|
218
|
+
)}:log-group:/aws/lambda/${onEventHandlerName}:*/g`,
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
true
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
return onEventHandler;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Creates a Custom resource to manage the deployment of the ACL.
|
|
233
|
+
*
|
|
234
|
+
* @param stack containing Stack instance.
|
|
235
|
+
* @param aclName name of the ACL to manage.
|
|
236
|
+
* @param onEventHandler event handler to use for deployment.
|
|
237
|
+
* @param props user provided properties for configuring the ACL.
|
|
238
|
+
* @private
|
|
239
|
+
*/
|
|
240
|
+
private createAclCustomResource(
|
|
241
|
+
stack: Stack,
|
|
242
|
+
aclName: string,
|
|
243
|
+
onEventHandler: NodejsFunction,
|
|
244
|
+
props?: CloudFrontWebAclProps
|
|
245
|
+
): CustomResource {
|
|
246
|
+
const providerFunctionName = `${onEventHandler.functionName}-Provider`;
|
|
247
|
+
const providerRole = new Role(this, "CloudfrontWebAclProviderRole", {
|
|
248
|
+
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
|
|
249
|
+
inlinePolicies: {
|
|
250
|
+
logs: new PolicyDocument({
|
|
251
|
+
statements: [
|
|
252
|
+
new PolicyStatement({
|
|
253
|
+
effect: Effect.ALLOW,
|
|
254
|
+
actions: [
|
|
255
|
+
"logs:CreateLogGroup",
|
|
256
|
+
"logs:CreateLogStream",
|
|
257
|
+
"logs:PutLogEvents",
|
|
258
|
+
],
|
|
259
|
+
resources: [
|
|
260
|
+
`arn:aws:logs:${stack.region}:${stack.account}:log-group:/aws/lambda/${providerFunctionName}`,
|
|
261
|
+
`arn:aws:logs:${stack.region}:${stack.account}:log-group:/aws/lambda/${providerFunctionName}:*`,
|
|
262
|
+
],
|
|
263
|
+
}),
|
|
264
|
+
],
|
|
265
|
+
}),
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
const provider = new Provider(this, "CloudfrontAclProvider", {
|
|
269
|
+
onEventHandler,
|
|
270
|
+
role: providerRole,
|
|
271
|
+
providerFunctionName,
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
["AwsSolutions-IAM5", "AwsPrototyping-IAMNoWildcardPermissions"].forEach(
|
|
275
|
+
(RuleId) => {
|
|
276
|
+
NagSuppressions.addResourceSuppressions(
|
|
277
|
+
providerRole,
|
|
278
|
+
[
|
|
279
|
+
{
|
|
280
|
+
id: RuleId,
|
|
281
|
+
reason:
|
|
282
|
+
"Cloudwatch resources have been scoped down to the LogGroup level, however * is still needed as stream names are created just in time.",
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
true
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
["AwsSolutions-L1", "AwsPrototyping-LambdaLatestVersion"].forEach(
|
|
291
|
+
(RuleId) => {
|
|
292
|
+
NagSuppressions.addResourceSuppressions(
|
|
293
|
+
provider,
|
|
294
|
+
[
|
|
295
|
+
{
|
|
296
|
+
id: RuleId,
|
|
297
|
+
reason:
|
|
298
|
+
"Latest runtime cannot be configured. CDK will need to upgrade the Provider construct accordingly.",
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
true
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
return new CustomResource(this, "CFAclCustomResource", {
|
|
307
|
+
serviceToken: provider.serviceToken,
|
|
308
|
+
properties: {
|
|
309
|
+
ID: aclName,
|
|
310
|
+
MANAGED_RULES: props?.managedRules ?? [
|
|
311
|
+
{ vendor: "AWS", name: "AWSManagedRulesCommonRuleSet" },
|
|
312
|
+
],
|
|
313
|
+
CIDR_ALLOW_LIST: props?.cidrAllowList,
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
SPDX-License-Identifier: Apache-2.0 */
|
|
3
|
+
import * as url from 'url';
|
|
4
|
+
import { PDKNag } from '@aws/pdk/pdk-nag';
|
|
5
|
+
import { CfnOutput, RemovalPolicy, Stack } from 'aws-cdk-lib';
|
|
6
|
+
import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
|
|
7
|
+
import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
8
|
+
import {
|
|
9
|
+
BlockPublicAccess,
|
|
10
|
+
Bucket,
|
|
11
|
+
BucketEncryption,
|
|
12
|
+
IBucket,
|
|
13
|
+
ObjectOwnership,
|
|
14
|
+
} from 'aws-cdk-lib/aws-s3';
|
|
15
|
+
import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
|
|
16
|
+
import { NagSuppressions } from 'cdk-nag';
|
|
17
|
+
import { Construct } from 'constructs';
|
|
18
|
+
import { CloudfrontWebAcl } from './cloudfront-web-acl.js';
|
|
19
|
+
import { RuntimeConfig } from '../runtime-config/index.js';
|
|
20
|
+
|
|
21
|
+
const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
|
|
25
|
+
*
|
|
26
|
+
* This construct configures a webAcl containing rules that are generally applicable to web applications. This
|
|
27
|
+
* provides protection against exploitation of a wide range of vulnerabilities, including some of the high risk
|
|
28
|
+
* and commonly occurring vulnerabilities described in OWASP publications such as OWASP Top 10.
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
export class StaticWebsite extends Construct {
|
|
32
|
+
public readonly websiteBucket: IBucket;
|
|
33
|
+
public readonly cloudFrontDistribution: Distribution;
|
|
34
|
+
public readonly bucketDeployment: BucketDeployment;
|
|
35
|
+
|
|
36
|
+
constructor(scope: Construct, id: string) {
|
|
37
|
+
super(scope, id);
|
|
38
|
+
|
|
39
|
+
this.node.setContext(
|
|
40
|
+
'@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
|
|
41
|
+
true
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
|
|
45
|
+
versioned: false,
|
|
46
|
+
enforceSSL: true,
|
|
47
|
+
autoDeleteObjects: true,
|
|
48
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
49
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
50
|
+
objectOwnership: ObjectOwnership.OBJECT_WRITER,
|
|
51
|
+
publicReadAccess: false,
|
|
52
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// S3 Bucket to hold website files
|
|
56
|
+
this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
|
|
57
|
+
versioned: true,
|
|
58
|
+
enforceSSL: true,
|
|
59
|
+
autoDeleteObjects: true,
|
|
60
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
61
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
62
|
+
objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
|
|
63
|
+
publicReadAccess: false,
|
|
64
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
65
|
+
serverAccessLogsPrefix: 'website-access-logs',
|
|
66
|
+
serverAccessLogsBucket: accessLogsBucket,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Web ACL
|
|
70
|
+
const webAclArn = new CloudfrontWebAcl(this, 'WebsiteAcl').webAclArn;
|
|
71
|
+
|
|
72
|
+
// Cloudfront Distribution
|
|
73
|
+
const logBucket = new Bucket(this, 'DistributionLogBucket', {
|
|
74
|
+
enforceSSL: true,
|
|
75
|
+
autoDeleteObjects: true,
|
|
76
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
77
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
78
|
+
objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
|
|
79
|
+
publicReadAccess: false,
|
|
80
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
81
|
+
serverAccessLogsPrefix: 'distribution-access-logs',
|
|
82
|
+
serverAccessLogsBucket: accessLogsBucket,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const defaultRootObject = 'index.html';
|
|
86
|
+
this.cloudFrontDistribution = new Distribution(
|
|
87
|
+
this,
|
|
88
|
+
'CloudfrontDistribution',
|
|
89
|
+
{
|
|
90
|
+
webAclId: webAclArn,
|
|
91
|
+
enableLogging: true,
|
|
92
|
+
logBucket: logBucket,
|
|
93
|
+
defaultBehavior: {
|
|
94
|
+
origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
|
|
95
|
+
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
96
|
+
},
|
|
97
|
+
defaultRootObject,
|
|
98
|
+
errorResponses: [
|
|
99
|
+
{
|
|
100
|
+
httpStatus: 404, // We need to redirect "key not found errors" to index.html for single page apps
|
|
101
|
+
responseHttpStatus: 200,
|
|
102
|
+
responsePagePath: `/${defaultRootObject}`,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Deploy Website
|
|
109
|
+
const runtimeConfig = RuntimeConfig.ensure(this).config;
|
|
110
|
+
this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
|
|
111
|
+
sources: [
|
|
112
|
+
Source.asset(url.fileURLToPath(new URL('../../../../../<%= websiteContentPath %>', import.meta.url))),
|
|
113
|
+
...(Object.keys(runtimeConfig).length > 0
|
|
114
|
+
? [
|
|
115
|
+
Source.jsonData(DEFAULT_RUNTIME_CONFIG_FILENAME, runtimeConfig),
|
|
116
|
+
]
|
|
117
|
+
: []),
|
|
118
|
+
],
|
|
119
|
+
destinationBucket: this.websiteBucket,
|
|
120
|
+
// Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
|
|
121
|
+
distribution: this.cloudFrontDistribution,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
new CfnOutput(this, 'DistributionDomainName', {
|
|
125
|
+
value: this.cloudFrontDistribution.domainName,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
this.suppressCDKNagViolations();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private suppressCDKNagViolations = () => {
|
|
132
|
+
const stack = Stack.of(this);
|
|
133
|
+
|
|
134
|
+
NagSuppressions.addResourceSuppressions(
|
|
135
|
+
this,
|
|
136
|
+
[
|
|
137
|
+
{
|
|
138
|
+
id: 'AwsPrototyping-CloudFrontDistributionGeoRestrictions',
|
|
139
|
+
reason:
|
|
140
|
+
'Suppressed to allow unrestricted access. Not recommended in production.',
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
true
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
[
|
|
147
|
+
'AwsSolutions-CFR4',
|
|
148
|
+
'AwsPrototyping-CloudFrontDistributionHttpsViewerNoOutdatedSSL',
|
|
149
|
+
].forEach((RuleId) => {
|
|
150
|
+
NagSuppressions.addResourceSuppressions(this.cloudFrontDistribution, [
|
|
151
|
+
{
|
|
152
|
+
id: RuleId,
|
|
153
|
+
reason:
|
|
154
|
+
'Certificate is not mandatory therefore the Cloudfront certificate will be used.',
|
|
155
|
+
},
|
|
156
|
+
]);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
['AwsSolutions-L1', 'AwsPrototyping-LambdaLatestVersion'].forEach(
|
|
160
|
+
(RuleId) => {
|
|
161
|
+
NagSuppressions.addResourceSuppressions(
|
|
162
|
+
this,
|
|
163
|
+
[
|
|
164
|
+
{
|
|
165
|
+
id: RuleId,
|
|
166
|
+
reason:
|
|
167
|
+
'Latest runtime cannot be configured. CDK will need to upgrade the BucketDeployment construct accordingly.',
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
true
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
['AwsSolutions-IAM5', 'AwsPrototyping-IAMNoWildcardPermissions'].forEach(
|
|
176
|
+
(RuleId) => {
|
|
177
|
+
NagSuppressions.addResourceSuppressions(
|
|
178
|
+
this,
|
|
179
|
+
[
|
|
180
|
+
{
|
|
181
|
+
id: RuleId,
|
|
182
|
+
reason:
|
|
183
|
+
'All Policies have been scoped to a Bucket. Given Buckets can contain arbitrary content, wildcard resources with bucket scope are required.',
|
|
184
|
+
appliesTo: [
|
|
185
|
+
{
|
|
186
|
+
regex: '/^Action::s3:.*$/g',
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
regex: `/^Resource::.*$/g`,
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
true
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
['AwsSolutions-IAM4', 'AwsPrototyping-IAMNoManagedPolicies'].forEach(
|
|
200
|
+
(RuleId) => {
|
|
201
|
+
NagSuppressions.addResourceSuppressions(
|
|
202
|
+
this,
|
|
203
|
+
[
|
|
204
|
+
{
|
|
205
|
+
id: RuleId,
|
|
206
|
+
reason:
|
|
207
|
+
'Buckets can contain arbitrary content, therefore wildcard resources under a bucket are required.',
|
|
208
|
+
appliesTo: [
|
|
209
|
+
{
|
|
210
|
+
regex: `/^Policy::arn:${PDKNag.getStackPartitionRegex(
|
|
211
|
+
stack
|
|
212
|
+
)}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole$/g`,
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
true
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
['AwsSolutions-S1', 'AwsPrototyping-S3BucketLoggingEnabled'].forEach(
|
|
223
|
+
(RuleId) => {
|
|
224
|
+
NagSuppressions.addResourceSuppressions(
|
|
225
|
+
this,
|
|
226
|
+
[
|
|
227
|
+
{
|
|
228
|
+
id: RuleId,
|
|
229
|
+
reason: 'Access Log buckets should not have s3 bucket logging',
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
true
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
};
|
|
237
|
+
}
|