@composurecdk/wafv2 0.0.0-stage → 0.13.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/LICENSE +21 -0
- package/README.md +240 -2
- package/dist/commonjs/alarm-config.d.ts +60 -0
- package/dist/commonjs/alarm-config.d.ts.map +1 -0
- package/dist/commonjs/alarm-config.js +3 -0
- package/dist/commonjs/alarm-config.js.map +1 -0
- package/dist/commonjs/alarm-defaults.d.ts +34 -0
- package/dist/commonjs/alarm-defaults.d.ts.map +1 -0
- package/dist/commonjs/alarm-defaults.js +37 -0
- package/dist/commonjs/alarm-defaults.js.map +1 -0
- package/dist/commonjs/alarms.d.ts +18 -0
- package/dist/commonjs/alarms.d.ts.map +1 -0
- package/dist/commonjs/alarms.js +94 -0
- package/dist/commonjs/alarms.js.map +1 -0
- package/dist/commonjs/association.d.ts +21 -0
- package/dist/commonjs/association.d.ts.map +1 -0
- package/dist/commonjs/association.js +61 -0
- package/dist/commonjs/association.js.map +1 -0
- package/dist/commonjs/custom-response.d.ts +52 -0
- package/dist/commonjs/custom-response.d.ts.map +1 -0
- package/dist/commonjs/custom-response.js +137 -0
- package/dist/commonjs/custom-response.js.map +1 -0
- package/dist/commonjs/defaults.d.ts +89 -0
- package/dist/commonjs/defaults.d.ts.map +1 -0
- package/dist/commonjs/defaults.js +90 -0
- package/dist/commonjs/defaults.js.map +1 -0
- package/dist/commonjs/index.d.ts +30 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +35 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/logging-filter.d.ts +27 -0
- package/dist/commonjs/logging-filter.d.ts.map +1 -0
- package/dist/commonjs/logging-filter.js +17 -0
- package/dist/commonjs/logging-filter.js.map +1 -0
- package/dist/commonjs/logging.d.ts +59 -0
- package/dist/commonjs/logging.d.ts.map +1 -0
- package/dist/commonjs/logging.js +91 -0
- package/dist/commonjs/logging.js.map +1 -0
- package/dist/commonjs/metrics.d.ts +58 -0
- package/dist/commonjs/metrics.d.ts.map +1 -0
- package/dist/commonjs/metrics.js +67 -0
- package/dist/commonjs/metrics.js.map +1 -0
- package/dist/commonjs/names.d.ts +46 -0
- package/dist/commonjs/names.d.ts.map +1 -0
- package/dist/commonjs/names.js +140 -0
- package/dist/commonjs/names.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/commonjs/rule-builder.d.ts +123 -0
- package/dist/commonjs/rule-builder.d.ts.map +1 -0
- package/dist/commonjs/rule-builder.js +163 -0
- package/dist/commonjs/rule-builder.js.map +1 -0
- package/dist/commonjs/scope.d.ts +15 -0
- package/dist/commonjs/scope.d.ts.map +1 -0
- package/dist/commonjs/scope.js +35 -0
- package/dist/commonjs/scope.js.map +1 -0
- package/dist/commonjs/web-acl-builder.d.ts +152 -0
- package/dist/commonjs/web-acl-builder.d.ts.map +1 -0
- package/dist/commonjs/web-acl-builder.js +205 -0
- package/dist/commonjs/web-acl-builder.js.map +1 -0
- package/dist/esm/alarm-config.d.ts +60 -0
- package/dist/esm/alarm-config.d.ts.map +1 -0
- package/dist/esm/alarm-config.js +2 -0
- package/dist/esm/alarm-config.js.map +1 -0
- package/dist/esm/alarm-defaults.d.ts +34 -0
- package/dist/esm/alarm-defaults.d.ts.map +1 -0
- package/dist/esm/alarm-defaults.js +34 -0
- package/dist/esm/alarm-defaults.js.map +1 -0
- package/dist/esm/alarms.d.ts +18 -0
- package/dist/esm/alarms.d.ts.map +1 -0
- package/dist/esm/alarms.js +90 -0
- package/dist/esm/alarms.js.map +1 -0
- package/dist/esm/association.d.ts +21 -0
- package/dist/esm/association.d.ts.map +1 -0
- package/dist/esm/association.js +58 -0
- package/dist/esm/association.js.map +1 -0
- package/dist/esm/custom-response.d.ts +52 -0
- package/dist/esm/custom-response.d.ts.map +1 -0
- package/dist/esm/custom-response.js +133 -0
- package/dist/esm/custom-response.js.map +1 -0
- package/dist/esm/defaults.d.ts +89 -0
- package/dist/esm/defaults.d.ts.map +1 -0
- package/dist/esm/defaults.js +87 -0
- package/dist/esm/defaults.js.map +1 -0
- package/dist/esm/index.d.ts +30 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +23 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/logging-filter.d.ts +27 -0
- package/dist/esm/logging-filter.d.ts.map +1 -0
- package/dist/esm/logging-filter.js +14 -0
- package/dist/esm/logging-filter.js.map +1 -0
- package/dist/esm/logging.d.ts +59 -0
- package/dist/esm/logging.d.ts.map +1 -0
- package/dist/esm/logging.js +88 -0
- package/dist/esm/logging.js.map +1 -0
- package/dist/esm/metrics.d.ts +58 -0
- package/dist/esm/metrics.d.ts.map +1 -0
- package/dist/esm/metrics.js +63 -0
- package/dist/esm/metrics.js.map +1 -0
- package/dist/esm/names.d.ts +46 -0
- package/dist/esm/names.d.ts.map +1 -0
- package/dist/esm/names.js +132 -0
- package/dist/esm/names.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/rule-builder.d.ts +123 -0
- package/dist/esm/rule-builder.d.ts.map +1 -0
- package/dist/esm/rule-builder.js +160 -0
- package/dist/esm/rule-builder.js.map +1 -0
- package/dist/esm/scope.d.ts +15 -0
- package/dist/esm/scope.d.ts.map +1 -0
- package/dist/esm/scope.js +32 -0
- package/dist/esm/scope.js.map +1 -0
- package/dist/esm/web-acl-builder.d.ts +152 -0
- package/dist/esm/web-acl-builder.d.ts.map +1 -0
- package/dist/esm/web-acl-builder.js +202 -0
- package/dist/esm/web-acl-builder.js.map +1 -0
- package/package.json +78 -4
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.associate = associate;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const aws_wafv2_1 = require("aws-cdk-lib/aws-wafv2");
|
|
6
|
+
const constructs_1 = require("constructs");
|
|
7
|
+
function isStage(target) {
|
|
8
|
+
return typeof target === "object" && "stageArn" in target;
|
|
9
|
+
}
|
|
10
|
+
/** 32-bit FNV-1a, as 8 hex digits. */
|
|
11
|
+
function fnv1a(value) {
|
|
12
|
+
let hash = 0x811c9dc5;
|
|
13
|
+
for (let i = 0; i < value.length; i++) {
|
|
14
|
+
hash = Math.imul(hash ^ value.charCodeAt(i), 0x01000193) >>> 0;
|
|
15
|
+
}
|
|
16
|
+
return hash.toString(16).padStart(8, "0");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A construct id suffix that follows the target, not its position: an id that
|
|
20
|
+
* moved when another target was removed would replace the association, and
|
|
21
|
+
* CloudFormation deletes the old one last, disassociating the resource.
|
|
22
|
+
*/
|
|
23
|
+
function targetKey(scope, target) {
|
|
24
|
+
const identity = constructs_1.Construct.isConstruct(target)
|
|
25
|
+
? target.node.path
|
|
26
|
+
: JSON.stringify(aws_cdk_lib_1.Stack.of(scope).resolve(target));
|
|
27
|
+
return fnv1a(identity);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates one `AWS::WAFv2::WebACLAssociation` per target, each depending on
|
|
31
|
+
* the one before it: AWS allows one `AssociateWebACL` call every two seconds
|
|
32
|
+
* per account and Region, so parallel associations throttle themselves.
|
|
33
|
+
*
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
function associate(scope, id, webAclArn, targets) {
|
|
37
|
+
const associations = [];
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
for (const target of targets) {
|
|
40
|
+
const resourceArn = isStage(target) ? target.stageArn : target;
|
|
41
|
+
const key = targetKey(scope, target);
|
|
42
|
+
if (seen.has(key)) {
|
|
43
|
+
throw new Error(`WebAclBuilder "${id}": associateWith() was given the same resource twice.`);
|
|
44
|
+
}
|
|
45
|
+
seen.add(key);
|
|
46
|
+
const association = new aws_wafv2_1.CfnWebACLAssociation(scope, `${id}Association${key}`, {
|
|
47
|
+
webAclArn,
|
|
48
|
+
resourceArn,
|
|
49
|
+
});
|
|
50
|
+
// The ARN references the resource, which already orders the association
|
|
51
|
+
// after it; a construct is depended on explicitly in case it does not.
|
|
52
|
+
if (constructs_1.Construct.isConstruct(target))
|
|
53
|
+
association.node.addDependency(target);
|
|
54
|
+
const previous = associations.at(-1);
|
|
55
|
+
if (previous)
|
|
56
|
+
association.node.addDependency(previous);
|
|
57
|
+
associations.push(association);
|
|
58
|
+
}
|
|
59
|
+
return associations;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=association.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"association.js","sourceRoot":"","sources":["../../src/association.ts"],"names":[],"mappings":";;AAgDA,8BA2BC;AA3ED,6CAAoC;AAEpC,qDAA6F;AAC7F,2CAAwD;AAaxD,SAAS,OAAO,CAAC,MAA+B;IAC9C,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,UAAU,IAAI,MAAM,CAAC;AAC5D,CAAC;AAED,sCAAsC;AACtC,SAAS,KAAK,CAAC,KAAa;IAC1B,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,KAAiB,EAAE,MAA+B;IACnE,MAAM,QAAQ,GAAG,sBAAS,CAAC,WAAW,CAAC,MAAM,CAAC;QAC5C,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;QAClB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,SAAS,CACvB,KAAiB,EACjB,EAAU,EACV,SAAiB,EACjB,OAAkC;IAElC,MAAM,YAAY,GAA2B,EAAE,CAAC;IAChD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/D,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,kBAAkB,EAAE,uDAAuD,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,MAAM,WAAW,GAAG,IAAI,gCAAoB,CAAC,KAAK,EAAE,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE;YAC5E,SAAS;YACT,WAAW;SACZ,CAAC,CAAC;QACH,wEAAwE;QACxE,uEAAuE;QACvE,IAAI,sBAAS,CAAC,WAAW,CAAC,MAAM,CAAC;YAAE,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC1E,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,QAAQ;YAAE,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACvD,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { CfnWebACL } from "aws-cdk-lib/aws-wafv2";
|
|
2
|
+
/**
|
|
3
|
+
* The body of a custom response. `json` is serialised with `JSON.stringify`
|
|
4
|
+
* unless it is already a string.
|
|
5
|
+
*/
|
|
6
|
+
export type CustomResponseBody = {
|
|
7
|
+
json: unknown;
|
|
8
|
+
} | {
|
|
9
|
+
text: string;
|
|
10
|
+
} | {
|
|
11
|
+
html: string;
|
|
12
|
+
};
|
|
13
|
+
/** A custom response for a Block action: status, optional body and headers. */
|
|
14
|
+
export interface CustomResponse {
|
|
15
|
+
readonly status: number;
|
|
16
|
+
readonly body?: CustomResponseBody;
|
|
17
|
+
readonly headers?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The status codes WAF accepts in a custom response. `410` is not among them,
|
|
21
|
+
* and `402` is reserved for the Monetize action.
|
|
22
|
+
*
|
|
23
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/customizing-the-response-status-codes.html
|
|
24
|
+
*/
|
|
25
|
+
export declare const SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES: readonly number[];
|
|
26
|
+
/**
|
|
27
|
+
* Collects the custom response bodies of a web ACL's default action and rules
|
|
28
|
+
* into the ACL-level `CustomResponseBodies` map CloudFormation requires.
|
|
29
|
+
* Identical bodies share one key; a body's key is derived from the first rule
|
|
30
|
+
* that uses it.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export declare class CustomResponseBodies {
|
|
35
|
+
#private;
|
|
36
|
+
constructor(owner: string);
|
|
37
|
+
/**
|
|
38
|
+
* Validates `response` and turns it into the `CustomResponse` CloudFormation
|
|
39
|
+
* expects, registering its body under a key derived from `keyHint`.
|
|
40
|
+
*
|
|
41
|
+
* @param who - Names the rule or default action in error messages.
|
|
42
|
+
*/
|
|
43
|
+
register(who: string, keyHint: string, response: CustomResponse): CfnWebACL.CustomResponseProperty;
|
|
44
|
+
/**
|
|
45
|
+
* The Block action for a rule or default action, with `response` as its
|
|
46
|
+
* custom response when there is one.
|
|
47
|
+
*/
|
|
48
|
+
block(who: string, keyHint: string, response?: CustomResponse): CfnWebACL.BlockActionProperty;
|
|
49
|
+
/** The map for `CfnWebACLProps.customResponseBodies`, or `undefined` when empty. */
|
|
50
|
+
toProperty(): Record<string, CfnWebACL.CustomResponseBodyProperty> | undefined;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=custom-response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-response.d.ts","sourceRoot":"","sources":["../../src/custom-response.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAMD;;;;;GAKG;AACH,eAAO,MAAM,sCAAsC,EAAE,SAAS,MAAM,EAGnE,CAAC;AA2DF;;;;;;;GAOG;AACH,qBAAa,oBAAoB;;gBAMnB,KAAK,EAAE,MAAM;IAIzB;;;;;OAKG;IACH,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,GACvB,SAAS,CAAC,sBAAsB;IAgDnC;;;OAGG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC,mBAAmB;IAI7F,oFAAoF;IACpF,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,0BAA0B,CAAC,GAAG,SAAS;CAG/E"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CustomResponseBodies = exports.SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const SOURCE = "https://docs.aws.amazon.com/waf/latest/developerguide/customizing-the-response-status-codes.html";
|
|
6
|
+
const QUOTAS = "https://docs.aws.amazon.com/waf/latest/developerguide/limits.html";
|
|
7
|
+
/**
|
|
8
|
+
* The status codes WAF accepts in a custom response. `410` is not among them,
|
|
9
|
+
* and `402` is reserved for the Monetize action.
|
|
10
|
+
*
|
|
11
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/customizing-the-response-status-codes.html
|
|
12
|
+
*/
|
|
13
|
+
exports.SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES = [
|
|
14
|
+
200, 201, 202, 204, 206, 300, 301, 302, 303, 304, 307, 308, 400, 401, 403, 404, 405, 408, 409,
|
|
15
|
+
411, 412, 413, 414, 415, 416, 421, 429, 500, 501, 502, 503, 504, 505,
|
|
16
|
+
];
|
|
17
|
+
const MAX_BODY_BYTES = 4 * 1024;
|
|
18
|
+
const MAX_BODIES = 50;
|
|
19
|
+
const MAX_TOTAL_BODY_BYTES = 50 * 1024;
|
|
20
|
+
const MAX_HEADERS = 10;
|
|
21
|
+
const HEADER_NAME = /^[a-zA-Z0-9._$-]{1,64}$/;
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
const byteLength = (s) => encoder.encode(s).length;
|
|
24
|
+
function toBodyProperty(body) {
|
|
25
|
+
if ("json" in body) {
|
|
26
|
+
return {
|
|
27
|
+
contentType: "APPLICATION_JSON",
|
|
28
|
+
content: typeof body.json === "string" ? body.json : JSON.stringify(body.json),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if ("text" in body)
|
|
32
|
+
return { contentType: "TEXT_PLAIN", content: body.text };
|
|
33
|
+
return { contentType: "TEXT_HTML", content: body.html };
|
|
34
|
+
}
|
|
35
|
+
function validateStatus(owner, status) {
|
|
36
|
+
if (aws_cdk_lib_1.Token.isUnresolved(status))
|
|
37
|
+
return;
|
|
38
|
+
if (!exports.SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES.includes(status)) {
|
|
39
|
+
throw new Error(`${owner}: AWS WAF does not support the custom response status code ${String(status)}. ` +
|
|
40
|
+
`Supported: ${exports.SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES.join(", ")}. See ${SOURCE}.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function validateHeaders(owner, headers) {
|
|
44
|
+
const names = Object.keys(headers);
|
|
45
|
+
if (names.length > MAX_HEADERS) {
|
|
46
|
+
throw new Error(`${owner}: a custom response can set at most ${String(MAX_HEADERS)} headers, but ${String(names.length)} were given. See ${QUOTAS}.`);
|
|
47
|
+
}
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
for (const name of names) {
|
|
50
|
+
if (!HEADER_NAME.test(name)) {
|
|
51
|
+
throw new Error(`${owner}: custom response header "${name}" is invalid. Names are 1–64 characters of letters, digits and ._$-. See ${SOURCE}.`);
|
|
52
|
+
}
|
|
53
|
+
const lower = name.toLowerCase();
|
|
54
|
+
if (lower === "content-type") {
|
|
55
|
+
throw new Error(`${owner}: a custom response cannot set content-type; WAF sets it from the body's type. Use { json }, { text } or { html } instead.`);
|
|
56
|
+
}
|
|
57
|
+
if (seen.has(lower)) {
|
|
58
|
+
throw new Error(`${owner}: custom response header "${name}" is set twice.`);
|
|
59
|
+
}
|
|
60
|
+
seen.add(lower);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Collects the custom response bodies of a web ACL's default action and rules
|
|
65
|
+
* into the ACL-level `CustomResponseBodies` map CloudFormation requires.
|
|
66
|
+
* Identical bodies share one key; a body's key is derived from the first rule
|
|
67
|
+
* that uses it.
|
|
68
|
+
*
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
class CustomResponseBodies {
|
|
72
|
+
#owner;
|
|
73
|
+
#bodies = {};
|
|
74
|
+
#keysByContent = new Map();
|
|
75
|
+
#totalBytes = 0;
|
|
76
|
+
constructor(owner) {
|
|
77
|
+
this.#owner = owner;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validates `response` and turns it into the `CustomResponse` CloudFormation
|
|
81
|
+
* expects, registering its body under a key derived from `keyHint`.
|
|
82
|
+
*
|
|
83
|
+
* @param who - Names the rule or default action in error messages.
|
|
84
|
+
*/
|
|
85
|
+
register(who, keyHint, response) {
|
|
86
|
+
const owner = `${this.#owner} ${who}`;
|
|
87
|
+
validateStatus(owner, response.status);
|
|
88
|
+
if (response.headers)
|
|
89
|
+
validateHeaders(owner, response.headers);
|
|
90
|
+
const responseHeaders = response.headers
|
|
91
|
+
? Object.entries(response.headers).map(([name, value]) => ({ name, value }))
|
|
92
|
+
: undefined;
|
|
93
|
+
return {
|
|
94
|
+
responseCode: response.status,
|
|
95
|
+
...(response.body && { customResponseBodyKey: this.#keyFor(owner, keyHint, response.body) }),
|
|
96
|
+
...(responseHeaders && { responseHeaders }),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
#keyFor(owner, keyHint, body) {
|
|
100
|
+
const property = toBodyProperty(body);
|
|
101
|
+
const identity = `${property.contentType}\n${property.content}`;
|
|
102
|
+
const existing = this.#keysByContent.get(identity);
|
|
103
|
+
if (existing !== undefined)
|
|
104
|
+
return existing;
|
|
105
|
+
const bytes = byteLength(property.content);
|
|
106
|
+
if (bytes > MAX_BODY_BYTES) {
|
|
107
|
+
throw new Error(`${owner}: the custom response body is ${String(bytes)} bytes; AWS WAF allows at most ${String(MAX_BODY_BYTES)}. See ${QUOTAS}.`);
|
|
108
|
+
}
|
|
109
|
+
if (this.#keysByContent.size >= MAX_BODIES) {
|
|
110
|
+
throw new Error(`${this.#owner}: a web ACL can hold at most ${String(MAX_BODIES)} distinct custom response bodies. See ${QUOTAS}.`);
|
|
111
|
+
}
|
|
112
|
+
this.#totalBytes += bytes;
|
|
113
|
+
if (this.#totalBytes > MAX_TOTAL_BODY_BYTES) {
|
|
114
|
+
throw new Error(`${this.#owner}: the custom response bodies total ${String(this.#totalBytes)} bytes; AWS WAF allows at most ${String(MAX_TOTAL_BODY_BYTES)} per web ACL. See ${QUOTAS}.`);
|
|
115
|
+
}
|
|
116
|
+
let key = keyHint;
|
|
117
|
+
// Keys share the 128-character limit of rule names, so leave room for a suffix.
|
|
118
|
+
for (let n = 2; key in this.#bodies; n++)
|
|
119
|
+
key = `${keyHint.slice(0, 120)}-${String(n)}`;
|
|
120
|
+
this.#bodies[key] = property;
|
|
121
|
+
this.#keysByContent.set(identity, key);
|
|
122
|
+
return key;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The Block action for a rule or default action, with `response` as its
|
|
126
|
+
* custom response when there is one.
|
|
127
|
+
*/
|
|
128
|
+
block(who, keyHint, response) {
|
|
129
|
+
return response ? { customResponse: this.register(who, keyHint, response) } : {};
|
|
130
|
+
}
|
|
131
|
+
/** The map for `CfnWebACLProps.customResponseBodies`, or `undefined` when empty. */
|
|
132
|
+
toProperty() {
|
|
133
|
+
return this.#keysByContent.size > 0 ? this.#bodies : undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.CustomResponseBodies = CustomResponseBodies;
|
|
137
|
+
//# sourceMappingURL=custom-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-response.js","sourceRoot":"","sources":["../../src/custom-response.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defaults for {@link createWebAclBuilder}. Each can be overridden through the
|
|
3
|
+
* builder's fluent API.
|
|
4
|
+
*/
|
|
5
|
+
export declare const WEB_ACL_DEFAULTS: {
|
|
6
|
+
/**
|
|
7
|
+
* Regional, for API Gateway, Application Load Balancers, AppSync, Cognito,
|
|
8
|
+
* App Runner and Verified Access. A web ACL for CloudFront must say
|
|
9
|
+
* `.scope("CLOUDFRONT")` and be deployed in `us-east-1`.
|
|
10
|
+
*
|
|
11
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/how-aws-waf-works-resources.html
|
|
12
|
+
*/
|
|
13
|
+
readonly scope: "REGIONAL";
|
|
14
|
+
/**
|
|
15
|
+
* Off, because a sampled request keeps every header, including the
|
|
16
|
+
* credentials that logging redacts. Turn it on only with a
|
|
17
|
+
* `dataProtectionConfig`, which does apply to samples.
|
|
18
|
+
*
|
|
19
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/waf-data-protection-and-logging.html
|
|
20
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_data_classification_define_protection.html
|
|
21
|
+
*/
|
|
22
|
+
readonly sampledRequests: false;
|
|
23
|
+
/**
|
|
24
|
+
* On, to a created `aws-waf-logs-` log group, keeping the requests WAF does
|
|
25
|
+
* not allow ({@link DEFAULT_LOGGING_FILTER}) and redacting
|
|
26
|
+
* {@link DEFAULT_LOGGING_REDACTED_HEADERS}.
|
|
27
|
+
*
|
|
28
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_detect_investigate_events_app_service_logging.html
|
|
29
|
+
*/
|
|
30
|
+
readonly logging: {};
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Visibility settings that are not configurable. CloudWatch metrics are always
|
|
34
|
+
* on for the web ACL and every rule: they are free, and the recommended alarms
|
|
35
|
+
* and `metrics` helper read them.
|
|
36
|
+
*
|
|
37
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_detect_investigate_events_app_service_logging.html
|
|
38
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/waf-metrics.html
|
|
39
|
+
*/
|
|
40
|
+
export declare const WEB_ACL_VISIBILITY_DEFAULTS: {
|
|
41
|
+
readonly cloudWatchMetricsEnabled: true;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Gap between the priorities of consecutive rules, so a rule can be inserted
|
|
45
|
+
* with an explicit `.priority(n)` without renumbering the others.
|
|
46
|
+
*/
|
|
47
|
+
export declare const DEFAULT_RULE_PRIORITY_STEP = 10;
|
|
48
|
+
/**
|
|
49
|
+
* The prefix AWS WAF requires of a CloudWatch log group, S3 bucket or Firehose
|
|
50
|
+
* stream it logs to.
|
|
51
|
+
*
|
|
52
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/logging-cw-logs.html
|
|
53
|
+
*/
|
|
54
|
+
export declare const WAF_LOG_GROUP_NAME_PREFIX = "aws-waf-logs-";
|
|
55
|
+
/**
|
|
56
|
+
* Headers always redacted from WAF logs. Both carry credentials a log reader
|
|
57
|
+
* could replay, and neither helps tune a rule.
|
|
58
|
+
*
|
|
59
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_data_classification_define_protection.html
|
|
60
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/logging-management.html
|
|
61
|
+
*/
|
|
62
|
+
export declare const DEFAULT_LOGGING_REDACTED_HEADERS: readonly string[];
|
|
63
|
+
/**
|
|
64
|
+
* Logs every request WAF does not simply allow, and drops the rest. Filtering
|
|
65
|
+
* is AWS's main lever on log volume and cost, and the allowed requests are
|
|
66
|
+
* rarely what a rule is tuned against.
|
|
67
|
+
*
|
|
68
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/logging-management.html
|
|
69
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_detect_investigate_events_app_service_logging.html
|
|
70
|
+
*/
|
|
71
|
+
export declare const DEFAULT_LOGGING_FILTER: {
|
|
72
|
+
readonly defaultBehavior: "DROP";
|
|
73
|
+
readonly filters: readonly [{
|
|
74
|
+
readonly behavior: "KEEP";
|
|
75
|
+
readonly requirement: "MEETS_ANY";
|
|
76
|
+
readonly conditions: readonly [{
|
|
77
|
+
readonly action: "BLOCK";
|
|
78
|
+
}, {
|
|
79
|
+
readonly action: "COUNT";
|
|
80
|
+
}, {
|
|
81
|
+
readonly action: "CAPTCHA";
|
|
82
|
+
}, {
|
|
83
|
+
readonly action: "CHALLENGE";
|
|
84
|
+
}, {
|
|
85
|
+
readonly action: "EXCLUDED_AS_COUNT";
|
|
86
|
+
}];
|
|
87
|
+
}];
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/defaults.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;;;;;OAMG;;IAGH;;;;;;;OAOG;;IAGH;;;;;;OAMG;;CAEK,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B;;CAE9B,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,kBAAkB,CAAC;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,EAAE,SAAS,MAAM,EAAgC,CAAC;AAE/F;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;CAeK,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_LOGGING_FILTER = exports.DEFAULT_LOGGING_REDACTED_HEADERS = exports.WAF_LOG_GROUP_NAME_PREFIX = exports.DEFAULT_RULE_PRIORITY_STEP = exports.WEB_ACL_VISIBILITY_DEFAULTS = exports.WEB_ACL_DEFAULTS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Defaults for {@link createWebAclBuilder}. Each can be overridden through the
|
|
6
|
+
* builder's fluent API.
|
|
7
|
+
*/
|
|
8
|
+
exports.WEB_ACL_DEFAULTS = {
|
|
9
|
+
/**
|
|
10
|
+
* Regional, for API Gateway, Application Load Balancers, AppSync, Cognito,
|
|
11
|
+
* App Runner and Verified Access. A web ACL for CloudFront must say
|
|
12
|
+
* `.scope("CLOUDFRONT")` and be deployed in `us-east-1`.
|
|
13
|
+
*
|
|
14
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/how-aws-waf-works-resources.html
|
|
15
|
+
*/
|
|
16
|
+
scope: "REGIONAL",
|
|
17
|
+
/**
|
|
18
|
+
* Off, because a sampled request keeps every header, including the
|
|
19
|
+
* credentials that logging redacts. Turn it on only with a
|
|
20
|
+
* `dataProtectionConfig`, which does apply to samples.
|
|
21
|
+
*
|
|
22
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/waf-data-protection-and-logging.html
|
|
23
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_data_classification_define_protection.html
|
|
24
|
+
*/
|
|
25
|
+
sampledRequests: false,
|
|
26
|
+
/**
|
|
27
|
+
* On, to a created `aws-waf-logs-` log group, keeping the requests WAF does
|
|
28
|
+
* not allow ({@link DEFAULT_LOGGING_FILTER}) and redacting
|
|
29
|
+
* {@link DEFAULT_LOGGING_REDACTED_HEADERS}.
|
|
30
|
+
*
|
|
31
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_detect_investigate_events_app_service_logging.html
|
|
32
|
+
*/
|
|
33
|
+
logging: {},
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Visibility settings that are not configurable. CloudWatch metrics are always
|
|
37
|
+
* on for the web ACL and every rule: they are free, and the recommended alarms
|
|
38
|
+
* and `metrics` helper read them.
|
|
39
|
+
*
|
|
40
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_detect_investigate_events_app_service_logging.html
|
|
41
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/waf-metrics.html
|
|
42
|
+
*/
|
|
43
|
+
exports.WEB_ACL_VISIBILITY_DEFAULTS = {
|
|
44
|
+
cloudWatchMetricsEnabled: true,
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Gap between the priorities of consecutive rules, so a rule can be inserted
|
|
48
|
+
* with an explicit `.priority(n)` without renumbering the others.
|
|
49
|
+
*/
|
|
50
|
+
exports.DEFAULT_RULE_PRIORITY_STEP = 10;
|
|
51
|
+
/**
|
|
52
|
+
* The prefix AWS WAF requires of a CloudWatch log group, S3 bucket or Firehose
|
|
53
|
+
* stream it logs to.
|
|
54
|
+
*
|
|
55
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/logging-cw-logs.html
|
|
56
|
+
*/
|
|
57
|
+
exports.WAF_LOG_GROUP_NAME_PREFIX = "aws-waf-logs-";
|
|
58
|
+
/**
|
|
59
|
+
* Headers always redacted from WAF logs. Both carry credentials a log reader
|
|
60
|
+
* could replay, and neither helps tune a rule.
|
|
61
|
+
*
|
|
62
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_data_classification_define_protection.html
|
|
63
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/logging-management.html
|
|
64
|
+
*/
|
|
65
|
+
exports.DEFAULT_LOGGING_REDACTED_HEADERS = ["authorization", "cookie"];
|
|
66
|
+
/**
|
|
67
|
+
* Logs every request WAF does not simply allow, and drops the rest. Filtering
|
|
68
|
+
* is AWS's main lever on log volume and cost, and the allowed requests are
|
|
69
|
+
* rarely what a rule is tuned against.
|
|
70
|
+
*
|
|
71
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/logging-management.html
|
|
72
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_detect_investigate_events_app_service_logging.html
|
|
73
|
+
*/
|
|
74
|
+
exports.DEFAULT_LOGGING_FILTER = {
|
|
75
|
+
defaultBehavior: "DROP",
|
|
76
|
+
filters: [
|
|
77
|
+
{
|
|
78
|
+
behavior: "KEEP",
|
|
79
|
+
requirement: "MEETS_ANY",
|
|
80
|
+
conditions: [
|
|
81
|
+
{ action: "BLOCK" },
|
|
82
|
+
{ action: "COUNT" },
|
|
83
|
+
{ action: "CAPTCHA" },
|
|
84
|
+
{ action: "CHALLENGE" },
|
|
85
|
+
{ action: "EXCLUDED_AS_COUNT" },
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/defaults.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACU,QAAA,gBAAgB,GAAG;IAC9B;;;;;;OAMG;IACH,KAAK,EAAE,UAAU;IAEjB;;;;;;;OAOG;IACH,eAAe,EAAE,KAAK;IAEtB;;;;;;OAMG;IACH,OAAO,EAAE,EAAE;CACH,CAAC;AAEX;;;;;;;GAOG;AACU,QAAA,2BAA2B,GAAG;IACzC,wBAAwB,EAAE,IAAI;CACtB,CAAC;AAEX;;;GAGG;AACU,QAAA,0BAA0B,GAAG,EAAE,CAAC;AAE7C;;;;;GAKG;AACU,QAAA,yBAAyB,GAAG,eAAe,CAAC;AAEzD;;;;;;GAMG;AACU,QAAA,gCAAgC,GAAsB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;AAE/F;;;;;;;GAOG;AACU,QAAA,sBAAsB,GAAG;IACpC,eAAe,EAAE,MAAM;IACvB,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,MAAM;YAChB,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE;gBACV,EAAE,MAAM,EAAE,OAAO,EAAE;gBACnB,EAAE,MAAM,EAAE,OAAO,EAAE;gBACnB,EAAE,MAAM,EAAE,SAAS,EAAE;gBACrB,EAAE,MAAM,EAAE,WAAW,EAAE;gBACvB,EAAE,MAAM,EAAE,mBAAmB,EAAE;aAChC;SACF;KACF;CACqC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { validateMetricName, validateRuleLabel, validateRuleName, validateWebAclName } from "./names.js";
|
|
2
|
+
export { createWebAclBuilder, type IWebAclBuilder, type WebAclBuilderProps, type WebAclBuilderResult, } from "./web-acl-builder.js";
|
|
3
|
+
export { type IWebAclRuleBuilder, type WebAclRuleAction, type WebAclRuleBuilderProps, } from "./rule-builder.js";
|
|
4
|
+
export { type WebAclAssociationTarget } from "./association.js";
|
|
5
|
+
export { type CustomResponse, type CustomResponseBody, SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES, } from "./custom-response.js";
|
|
6
|
+
export { type WebAclScope } from "./scope.js";
|
|
7
|
+
export { type ManagedRuleGroupVersion, type WebAclMetrics, type WebAclRequestMetrics, } from "./metrics.js";
|
|
8
|
+
export { type WebAclAlarmConfig, type WebAclRuleAlarmConfig } from "./alarm-config.js";
|
|
9
|
+
export { WEB_ACL_RULE_ALARM_DEFAULTS } from "./alarm-defaults.js";
|
|
10
|
+
export { type WebAclLoggingConfig, type WebAclLogRedaction } from "./logging.js";
|
|
11
|
+
export { type WebAclLogAction, type WebAclLogCondition, type WebAclLoggingFilter, } from "./logging-filter.js";
|
|
12
|
+
export { DEFAULT_LOGGING_FILTER, DEFAULT_LOGGING_REDACTED_HEADERS, DEFAULT_RULE_PRIORITY_STEP, WEB_ACL_DEFAULTS, WEB_ACL_VISIBILITY_DEFAULTS, WAF_LOG_GROUP_NAME_PREFIX, } from "./defaults.js";
|
|
13
|
+
/**
|
|
14
|
+
* This package's AWS-property constraints, grouped by application strategy.
|
|
15
|
+
* The `constraints.validate.*` / `constraints.sanitize.*` shape is identical
|
|
16
|
+
* in every builder package, so it is discoverable without importing anything
|
|
17
|
+
* beyond the package you already use. The underlying constraint definitions
|
|
18
|
+
* stay module-private — this namespace is the only public surface for them.
|
|
19
|
+
* See ADR-0010.
|
|
20
|
+
*/
|
|
21
|
+
export declare const constraints: {
|
|
22
|
+
validate: {
|
|
23
|
+
webAclName: typeof validateWebAclName;
|
|
24
|
+
ruleName: typeof validateRuleName;
|
|
25
|
+
metricName: typeof validateMetricName;
|
|
26
|
+
ruleLabel: typeof validateRuleLabel;
|
|
27
|
+
};
|
|
28
|
+
sanitize: {};
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,sCAAsC,GACvC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EAChC,0BAA0B,EAC1B,gBAAgB,EAChB,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAEvB;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;;;;;;;;CAQO,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.constraints = exports.WAF_LOG_GROUP_NAME_PREFIX = exports.WEB_ACL_VISIBILITY_DEFAULTS = exports.WEB_ACL_DEFAULTS = exports.DEFAULT_RULE_PRIORITY_STEP = exports.DEFAULT_LOGGING_REDACTED_HEADERS = exports.DEFAULT_LOGGING_FILTER = exports.WEB_ACL_RULE_ALARM_DEFAULTS = exports.SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES = exports.createWebAclBuilder = void 0;
|
|
4
|
+
const names_js_1 = require("./names.js");
|
|
5
|
+
var web_acl_builder_js_1 = require("./web-acl-builder.js");
|
|
6
|
+
Object.defineProperty(exports, "createWebAclBuilder", { enumerable: true, get: function () { return web_acl_builder_js_1.createWebAclBuilder; } });
|
|
7
|
+
var custom_response_js_1 = require("./custom-response.js");
|
|
8
|
+
Object.defineProperty(exports, "SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES", { enumerable: true, get: function () { return custom_response_js_1.SUPPORTED_CUSTOM_RESPONSE_STATUS_CODES; } });
|
|
9
|
+
var alarm_defaults_js_1 = require("./alarm-defaults.js");
|
|
10
|
+
Object.defineProperty(exports, "WEB_ACL_RULE_ALARM_DEFAULTS", { enumerable: true, get: function () { return alarm_defaults_js_1.WEB_ACL_RULE_ALARM_DEFAULTS; } });
|
|
11
|
+
var defaults_js_1 = require("./defaults.js");
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_LOGGING_FILTER", { enumerable: true, get: function () { return defaults_js_1.DEFAULT_LOGGING_FILTER; } });
|
|
13
|
+
Object.defineProperty(exports, "DEFAULT_LOGGING_REDACTED_HEADERS", { enumerable: true, get: function () { return defaults_js_1.DEFAULT_LOGGING_REDACTED_HEADERS; } });
|
|
14
|
+
Object.defineProperty(exports, "DEFAULT_RULE_PRIORITY_STEP", { enumerable: true, get: function () { return defaults_js_1.DEFAULT_RULE_PRIORITY_STEP; } });
|
|
15
|
+
Object.defineProperty(exports, "WEB_ACL_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.WEB_ACL_DEFAULTS; } });
|
|
16
|
+
Object.defineProperty(exports, "WEB_ACL_VISIBILITY_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.WEB_ACL_VISIBILITY_DEFAULTS; } });
|
|
17
|
+
Object.defineProperty(exports, "WAF_LOG_GROUP_NAME_PREFIX", { enumerable: true, get: function () { return defaults_js_1.WAF_LOG_GROUP_NAME_PREFIX; } });
|
|
18
|
+
/**
|
|
19
|
+
* This package's AWS-property constraints, grouped by application strategy.
|
|
20
|
+
* The `constraints.validate.*` / `constraints.sanitize.*` shape is identical
|
|
21
|
+
* in every builder package, so it is discoverable without importing anything
|
|
22
|
+
* beyond the package you already use. The underlying constraint definitions
|
|
23
|
+
* stay module-private — this namespace is the only public surface for them.
|
|
24
|
+
* See ADR-0010.
|
|
25
|
+
*/
|
|
26
|
+
exports.constraints = {
|
|
27
|
+
validate: {
|
|
28
|
+
webAclName: names_js_1.validateWebAclName,
|
|
29
|
+
ruleName: names_js_1.validateRuleName,
|
|
30
|
+
metricName: names_js_1.validateMetricName,
|
|
31
|
+
ruleLabel: names_js_1.validateRuleLabel,
|
|
32
|
+
},
|
|
33
|
+
sanitize: {},
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AACA,yCAKoB;AAEpB,2DAK8B;AAJ5B,yHAAA,mBAAmB,OAAA;AAWrB,2DAI8B;AAD5B,4IAAA,sCAAsC,OAAA;AASxC,yDAAkE;AAAzD,gIAAA,2BAA2B,OAAA;AAOpC,6CAOuB;AANrB,qHAAA,sBAAsB,OAAA;AACtB,+HAAA,gCAAgC,OAAA;AAChC,yHAAA,0BAA0B,OAAA;AAC1B,+GAAA,gBAAgB,OAAA;AAChB,0HAAA,2BAA2B,OAAA;AAC3B,wHAAA,yBAAyB,OAAA;AAG3B;;;;;;;GAOG;AACU,QAAA,WAAW,GAAG;IACzB,QAAQ,EAAE;QACR,UAAU,EAAE,6BAAkB;QAC9B,QAAQ,EAAE,2BAAgB;QAC1B,UAAU,EAAE,6BAAkB;QAC9B,SAAS,EAAE,4BAAiB;KAC7B;IACD,QAAQ,EAAE,EAAE;CACiB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** An action a logging filter condition can match on. */
|
|
2
|
+
export type WebAclLogAction = "ALLOW" | "BLOCK" | "COUNT" | "CAPTCHA" | "CHALLENGE" | "EXCLUDED_AS_COUNT";
|
|
3
|
+
/** One condition of a {@link WebAclLoggingFilter} filter: an action or a label. */
|
|
4
|
+
export type WebAclLogCondition = {
|
|
5
|
+
action: WebAclLogAction;
|
|
6
|
+
} | {
|
|
7
|
+
label: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Which requests WAF writes to the log, typed. The builder turns it into the
|
|
11
|
+
* PascalCase JSON CloudFormation's `LoggingFilter` expects, which CDK types
|
|
12
|
+
* as `any`.
|
|
13
|
+
*
|
|
14
|
+
* @see https://docs.aws.amazon.com/waf/latest/APIReference/API_LoggingFilter.html
|
|
15
|
+
*/
|
|
16
|
+
export interface WebAclLoggingFilter {
|
|
17
|
+
/** What to do with a request no filter matches. */
|
|
18
|
+
readonly defaultBehavior: "KEEP" | "DROP";
|
|
19
|
+
readonly filters: readonly {
|
|
20
|
+
readonly behavior: "KEEP" | "DROP";
|
|
21
|
+
readonly requirement: "MEETS_ALL" | "MEETS_ANY";
|
|
22
|
+
readonly conditions: readonly WebAclLogCondition[];
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
/** @internal — `LoggingFilter` is `any` in CDK, so this emits CloudFormation's PascalCase. */
|
|
26
|
+
export declare function toFilterProperty(filter: WebAclLoggingFilter): unknown;
|
|
27
|
+
//# sourceMappingURL=logging-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging-filter.d.ts","sourceRoot":"","sources":["../../src/logging-filter.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,MAAM,MAAM,eAAe,GACzB,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,GAAG,mBAAmB,CAAC;AAE9E,mFAAmF;AACnF,MAAM,MAAM,kBAAkB,GAAG;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjF;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS;QACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;QACnC,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,WAAW,CAAC;QAChD,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;KACpD,EAAE,CAAC;CACL;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAarE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toFilterProperty = toFilterProperty;
|
|
4
|
+
/** @internal — `LoggingFilter` is `any` in CDK, so this emits CloudFormation's PascalCase. */
|
|
5
|
+
function toFilterProperty(filter) {
|
|
6
|
+
return {
|
|
7
|
+
DefaultBehavior: filter.defaultBehavior,
|
|
8
|
+
Filters: filter.filters.map((f) => ({
|
|
9
|
+
Behavior: f.behavior,
|
|
10
|
+
Requirement: f.requirement,
|
|
11
|
+
Conditions: f.conditions.map((c) => "action" in c
|
|
12
|
+
? { ActionCondition: { Action: c.action } }
|
|
13
|
+
: { LabelNameCondition: { LabelName: c.label } }),
|
|
14
|
+
})),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=logging-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging-filter.js","sourceRoot":"","sources":["../../src/logging-filter.ts"],"names":[],"mappings":";;AAyBA,4CAaC;AAdD,8FAA8F;AAC9F,SAAgB,gBAAgB,CAAC,MAA2B;IAC1D,OAAO;QACL,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClC,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACjC,QAAQ,IAAI,CAAC;gBACX,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC3C,CAAC,CAAC,EAAE,kBAAkB,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,CACnD;SACF,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
|