@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,59 @@
|
|
|
1
|
+
import { type CfnLoggingConfigurationProps, type CfnWebACL } from "aws-cdk-lib/aws-wafv2";
|
|
2
|
+
import type { IConstruct } from "constructs";
|
|
3
|
+
import { type Resolvable } from "@composurecdk/core";
|
|
4
|
+
import { type ILogGroupBuilder } from "@composurecdk/logs";
|
|
5
|
+
import { type WebAclLoggingFilter } from "./logging-filter.js";
|
|
6
|
+
import type { WebAclBuilderResult } from "./web-acl-builder.js";
|
|
7
|
+
/** Request fields to redact from the log. */
|
|
8
|
+
export interface WebAclLogRedaction {
|
|
9
|
+
/**
|
|
10
|
+
* Header names to redact, **in addition to** `authorization` and `cookie`,
|
|
11
|
+
* which are always redacted.
|
|
12
|
+
*/
|
|
13
|
+
readonly headers?: readonly string[];
|
|
14
|
+
/** Redact the query string. */
|
|
15
|
+
readonly queryString?: boolean;
|
|
16
|
+
/** Redact the URI path. */
|
|
17
|
+
readonly uriPath?: boolean;
|
|
18
|
+
/** Redact the HTTP method. */
|
|
19
|
+
readonly method?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configures the web ACL's logging. On by default: WAF writes the requests it
|
|
23
|
+
* does not allow to a created `aws-waf-logs-` CloudWatch log group, with the
|
|
24
|
+
* `authorization` and `cookie` headers redacted. `false` turns it off.
|
|
25
|
+
*/
|
|
26
|
+
export interface WebAclLoggingConfig {
|
|
27
|
+
/**
|
|
28
|
+
* Customize the created log group. It starts with an `aws-waf-logs-` name,
|
|
29
|
+
* which WAF requires, and the `@composurecdk/logs` retention and removal
|
|
30
|
+
* defaults. The callback's builder resolves `ref`s against the build
|
|
31
|
+
* context. Cannot be combined with {@link destination}.
|
|
32
|
+
*/
|
|
33
|
+
readonly configure?: (b: ILogGroupBuilder) => ILogGroupBuilder;
|
|
34
|
+
/**
|
|
35
|
+
* Log to an existing destination instead of a created log group: a
|
|
36
|
+
* CloudWatch log group, S3 bucket or Firehose stream ARN, or a reference
|
|
37
|
+
* CDK's `CfnLoggingConfiguration` accepts. Its name must start with
|
|
38
|
+
* `aws-waf-logs-`, a log group ARN must not end in `:*`, an S3 bucket must
|
|
39
|
+
* use SSE-S3 or a customer managed key, and a Firehose stream must be
|
|
40
|
+
* DirectPut. Cannot be combined with {@link configure}.
|
|
41
|
+
*/
|
|
42
|
+
readonly destination?: Resolvable<NonNullable<CfnLoggingConfigurationProps["logDestinationConfigs"]>[number]>;
|
|
43
|
+
/**
|
|
44
|
+
* Which requests to log. `"non-allow"`, the default, keeps every request
|
|
45
|
+
* WAF blocks, counts, or answers with a CAPTCHA or challenge, and drops the
|
|
46
|
+
* rest. `"all"` keeps everything.
|
|
47
|
+
*/
|
|
48
|
+
readonly filter?: "non-allow" | "all" | WebAclLoggingFilter;
|
|
49
|
+
/** Fields to redact, merged with the defaults. */
|
|
50
|
+
readonly redact?: WebAclLogRedaction;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Creates the web ACL's logging configuration and, unless a destination was
|
|
54
|
+
* given, its log group.
|
|
55
|
+
*
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export declare function configureLogging(scope: IConstruct, id: string, owner: string, webAcl: CfnWebACL, config: WebAclLoggingConfig | false, context: Record<string, object>): Pick<WebAclBuilderResult, "logGroup" | "logging">;
|
|
59
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/logging.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAMlF,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,+BAA+B;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;IAE/D;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,UAAU,CAC/B,WAAW,CAAC,4BAA4B,CAAC,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,CAC3E,CAAC;IAEF;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,GAAG,mBAAmB,CAAC;IAE5D,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;CACtC;AAwED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,mBAAmB,GAAG,KAAK,EACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,IAAI,CAAC,mBAAmB,EAAE,UAAU,GAAG,SAAS,CAAC,CAwBnD"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configureLogging = configureLogging;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const aws_wafv2_1 = require("aws-cdk-lib/aws-wafv2");
|
|
6
|
+
const core_1 = require("@composurecdk/core");
|
|
7
|
+
const logs_1 = require("@composurecdk/logs");
|
|
8
|
+
const defaults_js_1 = require("./defaults.js");
|
|
9
|
+
const logging_filter_js_1 = require("./logging-filter.js");
|
|
10
|
+
const names_js_1 = require("./names.js");
|
|
11
|
+
const MAX_REDACTED_FIELDS = 100;
|
|
12
|
+
const LOGGING_SOURCE = "https://docs.aws.amazon.com/waf/latest/developerguide/logging.html";
|
|
13
|
+
function loggingFilter(filter) {
|
|
14
|
+
if (filter === "all")
|
|
15
|
+
return undefined;
|
|
16
|
+
return (0, logging_filter_js_1.toFilterProperty)(typeof filter === "object" ? filter : defaults_js_1.DEFAULT_LOGGING_FILTER);
|
|
17
|
+
}
|
|
18
|
+
function redactedFields(owner, redact) {
|
|
19
|
+
const headers = new Map();
|
|
20
|
+
for (const name of [...defaults_js_1.DEFAULT_LOGGING_REDACTED_HEADERS, ...(redact?.headers ?? [])]) {
|
|
21
|
+
headers.set(name.toLowerCase(), name);
|
|
22
|
+
}
|
|
23
|
+
// `FieldToMatch`'s members are `any` in CDK, so `SingleHeader` needs CloudFormation's `Name`.
|
|
24
|
+
const fields = [...headers.values()].map((Name) => ({ singleHeader: { Name } }));
|
|
25
|
+
if (redact?.queryString)
|
|
26
|
+
fields.push({ queryString: {} });
|
|
27
|
+
if (redact?.uriPath)
|
|
28
|
+
fields.push({ uriPath: {} });
|
|
29
|
+
if (redact?.method)
|
|
30
|
+
fields.push({ method: {} });
|
|
31
|
+
if (fields.length > MAX_REDACTED_FIELDS) {
|
|
32
|
+
throw new Error(`${owner}: logging redacts ${String(fields.length)} fields; AWS WAF allows at most ${String(MAX_REDACTED_FIELDS)}. See ${LOGGING_SOURCE}.`);
|
|
33
|
+
}
|
|
34
|
+
return fields;
|
|
35
|
+
}
|
|
36
|
+
function checkLogGroupName(owner, name) {
|
|
37
|
+
// The builder always seeds a name, but `configure` can replace it with a token.
|
|
38
|
+
if (name === undefined || aws_cdk_lib_1.Token.isUnresolved(name))
|
|
39
|
+
return;
|
|
40
|
+
if (!name.startsWith(defaults_js_1.WAF_LOG_GROUP_NAME_PREFIX)) {
|
|
41
|
+
throw new Error(`${owner}: the WAF log group is named "${name}", but AWS WAF only logs to log groups ` +
|
|
42
|
+
`whose names start with "${defaults_js_1.WAF_LOG_GROUP_NAME_PREFIX}". Rename it, or leave the ` +
|
|
43
|
+
`name to the builder. See ${LOGGING_SOURCE}.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates the WAF log group and returns it with the ARN WAF accepts for it.
|
|
48
|
+
*/
|
|
49
|
+
function createLogGroup(scope, id, owner, webAcl, configure, context) {
|
|
50
|
+
let builder = (0, logs_1.createLogGroupBuilder)().logGroupName(`${defaults_js_1.WAF_LOG_GROUP_NAME_PREFIX}${(0, names_js_1.webAclBaseName)(webAcl)}`);
|
|
51
|
+
if (configure)
|
|
52
|
+
builder = configure(builder);
|
|
53
|
+
checkLogGroupName(owner, builder.logGroupName());
|
|
54
|
+
const logGroup = builder.build(scope, `${id}Logs`, context).logGroup;
|
|
55
|
+
// WAF rejects the `:*` that `logGroupArn` ends in.
|
|
56
|
+
const arn = logGroup.stack.formatArn({
|
|
57
|
+
service: "logs",
|
|
58
|
+
resource: "log-group",
|
|
59
|
+
resourceName: logGroup.logGroupName,
|
|
60
|
+
arnFormat: aws_cdk_lib_1.ArnFormat.COLON_RESOURCE_NAME,
|
|
61
|
+
});
|
|
62
|
+
return { logGroup, arn };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates the web ACL's logging configuration and, unless a destination was
|
|
66
|
+
* given, its log group.
|
|
67
|
+
*
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
70
|
+
function configureLogging(scope, id, owner, webAcl, config, context) {
|
|
71
|
+
if (config === false)
|
|
72
|
+
return {};
|
|
73
|
+
const { configure, destination, filter, redact } = config;
|
|
74
|
+
if (configure !== undefined && destination !== undefined) {
|
|
75
|
+
throw new Error(`${owner}: logging 'configure' cannot be combined with 'destination' — the ` +
|
|
76
|
+
`destination is user-managed and not built by this builder.`);
|
|
77
|
+
}
|
|
78
|
+
const { logGroup, arn } = destination === undefined
|
|
79
|
+
? createLogGroup(scope, id, owner, webAcl, configure, context)
|
|
80
|
+
: { logGroup: undefined, arn: (0, core_1.resolve)(destination, context) };
|
|
81
|
+
const logging = new aws_wafv2_1.CfnLoggingConfiguration(scope, `${id}Logging`, {
|
|
82
|
+
resourceArn: webAcl.attrArn,
|
|
83
|
+
logDestinationConfigs: [arn],
|
|
84
|
+
loggingFilter: loggingFilter(filter),
|
|
85
|
+
redactedFields: redactedFields(owner, redact),
|
|
86
|
+
});
|
|
87
|
+
if (logGroup)
|
|
88
|
+
logging.node.addDependency(logGroup);
|
|
89
|
+
return { logGroup, logging };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../../src/logging.ts"],"names":[],"mappings":";;AAmJA,4CA+BC;AAlLD,6CAA+C;AAE/C,qDAI+B;AAE/B,6CAA8D;AAC9D,6CAAkF;AAClF,+CAIuB;AACvB,2DAAiF;AACjF,yCAA4C;AAuD5C,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,cAAc,GAAG,oEAAoE,CAAC;AAE5F,SAAS,aAAa,CAAC,MAAqC;IAC1D,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IACvC,OAAO,IAAA,oCAAgB,EAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oCAAsB,CAAC,CAAC;AACxF,CAAC;AAED,SAAS,cAAc,CACrB,KAAa,EACb,MAAsC;IAEtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,8CAAgC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,8FAA8F;IAC9F,MAAM,MAAM,GAAmD,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CACtF,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CACvC,CAAC;IACF,IAAI,MAAM,EAAE,WAAW;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAClD,IAAI,MAAM,EAAE,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,qBAAqB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,mCAAmC,MAAM,CAAC,mBAAmB,CAAC,SAAS,cAAc,GAAG,CAC3I,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa,EAAE,IAAwB;IAChE,gFAAgF;IAChF,IAAI,IAAI,KAAK,SAAS,IAAI,mBAAK,CAAC,YAAY,CAAC,IAAI,CAAC;QAAE,OAAO;IAC3D,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,uCAAyB,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,iCAAiC,IAAI,yCAAyC;YACpF,2BAA2B,uCAAyB,6BAA6B;YACjF,4BAA4B,cAAc,GAAG,CAChD,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CACrB,KAAiB,EACjB,EAAU,EACV,KAAa,EACb,MAAiB,EACjB,SAA2C,EAC3C,OAA+B;IAE/B,IAAI,OAAO,GAAG,IAAA,4BAAqB,GAAE,CAAC,YAAY,CAChD,GAAG,uCAAyB,GAAG,IAAA,yBAAc,EAAC,MAAM,CAAC,EAAE,CACxD,CAAC;IACF,IAAI,SAAS;QAAE,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5C,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;IACrE,mDAAmD;IACnD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC;QACnC,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,WAAW;QACrB,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,SAAS,EAAE,uBAAS,CAAC,mBAAmB;KACzC,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAC9B,KAAiB,EACjB,EAAU,EACV,KAAa,EACb,MAAiB,EACjB,MAAmC,EACnC,OAA+B;IAE/B,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1D,IAAI,SAAS,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,oEAAoE;YAC1E,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GACrB,WAAW,KAAK,SAAS;QACvB,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;QAC9D,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,IAAA,cAAO,EAAC,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC;IAElE,MAAM,OAAO,GAAG,IAAI,mCAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE;QACjE,WAAW,EAAE,MAAM,CAAC,OAAO;QAC3B,qBAAqB,EAAE,CAAC,GAAG,CAAC;QAC5B,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC;QACpC,cAAc,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC;KAC9C,CAAC,CAAC;IACH,IAAI,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAEnD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Duration } from "aws-cdk-lib";
|
|
2
|
+
import { Metric, type MetricOptions } from "aws-cdk-lib/aws-cloudwatch";
|
|
3
|
+
import type { CfnWebACL } from "aws-cdk-lib/aws-wafv2";
|
|
4
|
+
/**
|
|
5
|
+
* The request-count metrics WAF publishes for a web ACL, a rule, or the
|
|
6
|
+
* default action. Each is a Sum over 5 minutes unless `options` say
|
|
7
|
+
* otherwise. WAF publishes a datapoint only when the count is non-zero.
|
|
8
|
+
*
|
|
9
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/waf-metrics.html
|
|
10
|
+
*/
|
|
11
|
+
export interface WebAclRequestMetrics {
|
|
12
|
+
allowedRequests(options?: MetricOptions): Metric;
|
|
13
|
+
blockedRequests(options?: MetricOptions): Metric;
|
|
14
|
+
countedRequests(options?: MetricOptions): Metric;
|
|
15
|
+
captchaRequests(options?: MetricOptions): Metric;
|
|
16
|
+
challengeRequests(options?: MetricOptions): Metric;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The metrics of a web ACL, with dimensions built from the names the builder
|
|
20
|
+
* gave it and its rules, so they match what WAF publishes. The top-level
|
|
21
|
+
* metrics cover every rule (`Rule=ALL`).
|
|
22
|
+
*/
|
|
23
|
+
export interface WebAclMetrics extends WebAclRequestMetrics {
|
|
24
|
+
/** Requests no rule terminated, which the default action decided. */
|
|
25
|
+
readonly defaultAction: WebAclRequestMetrics;
|
|
26
|
+
/**
|
|
27
|
+
* The metrics of one rule, by the name given to `addRule`.
|
|
28
|
+
*
|
|
29
|
+
* @throws when the web ACL has no rule of that name.
|
|
30
|
+
*/
|
|
31
|
+
rule(name: string): WebAclRequestMetrics;
|
|
32
|
+
/**
|
|
33
|
+
* Days until a pinned managed rule group version expires. Published only
|
|
34
|
+
* for a group the web ACL uses at that version.
|
|
35
|
+
*
|
|
36
|
+
* @see https://docs.aws.amazon.com/waf/latest/developerguide/waf-using-managed-rule-groups-expiration.html
|
|
37
|
+
*/
|
|
38
|
+
daysToExpiry(group: ManagedRuleGroupVersion, options?: MetricOptions): Metric;
|
|
39
|
+
}
|
|
40
|
+
/** A managed rule group at a pinned version. */
|
|
41
|
+
export interface ManagedRuleGroupVersion {
|
|
42
|
+
readonly vendorName: string;
|
|
43
|
+
readonly name: string;
|
|
44
|
+
readonly version: string;
|
|
45
|
+
}
|
|
46
|
+
/** @internal — the period of every request metric unless overridden. */
|
|
47
|
+
export declare const REQUEST_METRIC_PERIOD: Duration;
|
|
48
|
+
/**
|
|
49
|
+
* Builds a web ACL's {@link WebAclMetrics}.
|
|
50
|
+
*
|
|
51
|
+
* @param metricName - The web ACL's own metric name, which WAF publishes the
|
|
52
|
+
* default action's metrics under as the `Rule` dimension.
|
|
53
|
+
* @param ruleMetricNames - Each rule's metric name, by rule name.
|
|
54
|
+
*
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
export declare function webAclMetrics(webAcl: CfnWebACL, metricName: string, ruleMetricNames: ReadonlyMap<string, string>): WebAclMetrics;
|
|
58
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAoB,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAS,MAAM,4BAA4B,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,eAAe,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IACjD,eAAe,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IACjD,eAAe,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IACjD,eAAe,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IACjD,iBAAiB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;CACpD;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,oBAAoB;IACzD,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAE7C;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAAC;IAEzC;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;CAC/E;AAED,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAGD,wEAAwE;AACxE,eAAO,MAAM,qBAAqB,UAAsB,CAAC;AAezD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3C,aAAa,CA8Cf"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REQUEST_METRIC_PERIOD = void 0;
|
|
4
|
+
exports.webAclMetrics = webAclMetrics;
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
const aws_cloudwatch_1 = require("aws-cdk-lib/aws-cloudwatch");
|
|
7
|
+
const NAMESPACE = "AWS/WAFV2";
|
|
8
|
+
/** @internal — the period of every request metric unless overridden. */
|
|
9
|
+
exports.REQUEST_METRIC_PERIOD = aws_cdk_lib_1.Duration.minutes(5);
|
|
10
|
+
const ALL_RULES = "ALL";
|
|
11
|
+
/**
|
|
12
|
+
* The value of a web ACL's `WebACL` dimension: its name. WAF publishes the
|
|
13
|
+
* name here, not the `VisibilityConfig` metric name the documentation
|
|
14
|
+
* describes. A web ACL without a literal name reads it from `Ref`, which is
|
|
15
|
+
* `name|id|scope`.
|
|
16
|
+
*/
|
|
17
|
+
function webAclDimension(webAcl) {
|
|
18
|
+
const { name } = webAcl;
|
|
19
|
+
if (name !== undefined && !aws_cdk_lib_1.Token.isUnresolved(name))
|
|
20
|
+
return name;
|
|
21
|
+
return aws_cdk_lib_1.Fn.select(0, aws_cdk_lib_1.Fn.split("|", webAcl.ref));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Builds a web ACL's {@link WebAclMetrics}.
|
|
25
|
+
*
|
|
26
|
+
* @param metricName - The web ACL's own metric name, which WAF publishes the
|
|
27
|
+
* default action's metrics under as the `Rule` dimension.
|
|
28
|
+
* @param ruleMetricNames - Each rule's metric name, by rule name.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
function webAclMetrics(webAcl, metricName, ruleMetricNames) {
|
|
33
|
+
// CloudFront metrics have no `Region` dimension.
|
|
34
|
+
const regionDimension = webAcl.scope === "CLOUDFRONT" ? {} : { Region: aws_cdk_lib_1.Stack.of(webAcl).region };
|
|
35
|
+
const webAclName = webAclDimension(webAcl);
|
|
36
|
+
const metric = (name, dimensionsMap, options) => new aws_cloudwatch_1.Metric({
|
|
37
|
+
namespace: NAMESPACE,
|
|
38
|
+
metricName: name,
|
|
39
|
+
statistic: aws_cloudwatch_1.Stats.SUM,
|
|
40
|
+
period: exports.REQUEST_METRIC_PERIOD,
|
|
41
|
+
...options,
|
|
42
|
+
dimensionsMap: { ...dimensionsMap, ...regionDimension, ...options?.dimensionsMap },
|
|
43
|
+
});
|
|
44
|
+
const requests = (rule) => {
|
|
45
|
+
const dimensions = { WebACL: webAclName, Rule: rule };
|
|
46
|
+
return {
|
|
47
|
+
allowedRequests: (o) => metric("AllowedRequests", dimensions, o),
|
|
48
|
+
blockedRequests: (o) => metric("BlockedRequests", dimensions, o),
|
|
49
|
+
countedRequests: (o) => metric("CountedRequests", dimensions, o),
|
|
50
|
+
captchaRequests: (o) => metric("CaptchaRequests", dimensions, o),
|
|
51
|
+
challengeRequests: (o) => metric("ChallengeRequests", dimensions, o),
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
...requests(ALL_RULES),
|
|
56
|
+
defaultAction: requests(metricName),
|
|
57
|
+
rule: (name) => {
|
|
58
|
+
const ruleMetricName = ruleMetricNames.get(name);
|
|
59
|
+
if (ruleMetricName === undefined) {
|
|
60
|
+
throw new Error(`The web ACL has no rule named "${name}". Rules: ${[...ruleMetricNames.keys()].join(", ") || "none"}.`);
|
|
61
|
+
}
|
|
62
|
+
return requests(ruleMetricName);
|
|
63
|
+
},
|
|
64
|
+
daysToExpiry: (group, options) => metric("DaysToExpiry", { Vendor: group.vendorName, ManagedRuleGroup: group.name, Version: group.version }, { statistic: aws_cloudwatch_1.Stats.MINIMUM, period: aws_cdk_lib_1.Duration.hours(1), ...options }),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CfnWebACL } from "aws-cdk-lib/aws-wafv2";
|
|
2
|
+
/**
|
|
3
|
+
* Validates a web ACL name.
|
|
4
|
+
*
|
|
5
|
+
* @throws on invalid input.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateWebAclName(raw: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Validates the name of a rule in a web ACL.
|
|
10
|
+
*
|
|
11
|
+
* @throws on invalid input.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateRuleName(raw: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Validates a CloudWatch metric name for a web ACL or rule. `All` and
|
|
16
|
+
* `Default_Action` are rejected: WAF uses them for its own metrics.
|
|
17
|
+
*
|
|
18
|
+
* @throws on invalid input.
|
|
19
|
+
*/
|
|
20
|
+
export declare function validateMetricName(raw: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* The web ACL's name when it is a literal, and otherwise a name derived from
|
|
23
|
+
* its construct path, unique in the app. The base of its default metric and
|
|
24
|
+
* log group names.
|
|
25
|
+
*
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export declare function webAclBaseName(webAcl: CfnWebACL): string;
|
|
29
|
+
/**
|
|
30
|
+
* Turns a construct path or other derived string into a legal metric name, for
|
|
31
|
+
* when the user has not chosen one.
|
|
32
|
+
*
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function sanitizeMetricName(raw: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Validates a label a rule adds to matching requests: up to five
|
|
38
|
+
* colon-separated namespaces and a name, each 1–128 characters of
|
|
39
|
+
* `[A-Za-z0-9_-]`, none of them one of WAF's reserved words. WAF adds the
|
|
40
|
+
* `awswaf:<account>:webacl:<name>:` prefix itself, so it is not part of the
|
|
41
|
+
* label.
|
|
42
|
+
*
|
|
43
|
+
* @throws on invalid input.
|
|
44
|
+
*/
|
|
45
|
+
export declare function validateRuleLabel(raw: string): void;
|
|
46
|
+
//# sourceMappingURL=names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../src/names.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AA6CvD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAOpD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAIxD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAuBD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAgBnD"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateWebAclName = validateWebAclName;
|
|
4
|
+
exports.validateRuleName = validateRuleName;
|
|
5
|
+
exports.validateMetricName = validateMetricName;
|
|
6
|
+
exports.webAclBaseName = webAclBaseName;
|
|
7
|
+
exports.sanitizeMetricName = sanitizeMetricName;
|
|
8
|
+
exports.validateRuleLabel = validateRuleLabel;
|
|
9
|
+
const cloudformation_1 = require("@composurecdk/cloudformation");
|
|
10
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
11
|
+
/**
|
|
12
|
+
* The name rule WAF applies to web ACLs and to the rules in them: 1–128
|
|
13
|
+
* characters from `[\w-]`.
|
|
14
|
+
*/
|
|
15
|
+
const WAF_NAME_RULE = {
|
|
16
|
+
charClass: `${cloudformation_1.charSets.ALNUM}_\\-`,
|
|
17
|
+
minLength: 1,
|
|
18
|
+
maxLength: 128,
|
|
19
|
+
allowed: "ASCII letters, digits, _ and -",
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* AWS-property constraint for a web ACL's name. Module-private; the package
|
|
23
|
+
* exposes {@link validateWebAclName} through the `constraints` namespace. See
|
|
24
|
+
* ADR-0010.
|
|
25
|
+
*/
|
|
26
|
+
const WEB_ACL_NAME = (0, cloudformation_1.stringConstraint)({
|
|
27
|
+
name: "WAFv2 WebACL Name",
|
|
28
|
+
...WAF_NAME_RULE,
|
|
29
|
+
source: "https://docs.aws.amazon.com/waf/latest/APIReference/API_CreateWebACL.html",
|
|
30
|
+
});
|
|
31
|
+
/** AWS-property constraint for a rule's name within a web ACL. */
|
|
32
|
+
const RULE_NAME = (0, cloudformation_1.stringConstraint)({
|
|
33
|
+
name: "WAFv2 WebACL Rule Name",
|
|
34
|
+
...WAF_NAME_RULE,
|
|
35
|
+
source: "https://docs.aws.amazon.com/waf/latest/APIReference/API_Rule.html",
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* AWS-property constraint for a `VisibilityConfig` metric name. The API
|
|
39
|
+
* accepts a looser set, but the Developer Guide restricts metric names to
|
|
40
|
+
* these characters, and CloudWatch is where they end up.
|
|
41
|
+
*/
|
|
42
|
+
const METRIC_NAME = (0, cloudformation_1.stringConstraint)({
|
|
43
|
+
name: "WAFv2 VisibilityConfig MetricName",
|
|
44
|
+
...WAF_NAME_RULE,
|
|
45
|
+
source: "https://docs.aws.amazon.com/waf/latest/APIReference/API_VisibilityConfig.html",
|
|
46
|
+
});
|
|
47
|
+
/** Metric names WAF reserves for its own aggregate metrics. */
|
|
48
|
+
const RESERVED_METRIC_NAMES = ["All", "Default_Action"];
|
|
49
|
+
/**
|
|
50
|
+
* Validates a web ACL name.
|
|
51
|
+
*
|
|
52
|
+
* @throws on invalid input.
|
|
53
|
+
*/
|
|
54
|
+
function validateWebAclName(raw) {
|
|
55
|
+
(0, cloudformation_1.validateString)(raw, WEB_ACL_NAME);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validates the name of a rule in a web ACL.
|
|
59
|
+
*
|
|
60
|
+
* @throws on invalid input.
|
|
61
|
+
*/
|
|
62
|
+
function validateRuleName(raw) {
|
|
63
|
+
(0, cloudformation_1.validateString)(raw, RULE_NAME);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validates a CloudWatch metric name for a web ACL or rule. `All` and
|
|
67
|
+
* `Default_Action` are rejected: WAF uses them for its own metrics.
|
|
68
|
+
*
|
|
69
|
+
* @throws on invalid input.
|
|
70
|
+
*/
|
|
71
|
+
function validateMetricName(raw) {
|
|
72
|
+
(0, cloudformation_1.validateString)(raw, METRIC_NAME);
|
|
73
|
+
if (!aws_cdk_lib_1.Token.isUnresolved(raw) && RESERVED_METRIC_NAMES.includes(raw)) {
|
|
74
|
+
throw new Error(`${METRIC_NAME.name} "${raw}" is reserved by AWS WAF. Reserved: ${RESERVED_METRIC_NAMES.join(", ")}. See ${METRIC_NAME.source}.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The web ACL's name when it is a literal, and otherwise a name derived from
|
|
79
|
+
* its construct path, unique in the app. The base of its default metric and
|
|
80
|
+
* log group names.
|
|
81
|
+
*
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
function webAclBaseName(webAcl) {
|
|
85
|
+
const { name } = webAcl;
|
|
86
|
+
if (name !== undefined && !aws_cdk_lib_1.Token.isUnresolved(name))
|
|
87
|
+
return name;
|
|
88
|
+
return aws_cdk_lib_1.Names.uniqueResourceName(webAcl, { maxLength: 128 });
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Turns a construct path or other derived string into a legal metric name, for
|
|
92
|
+
* when the user has not chosen one.
|
|
93
|
+
*
|
|
94
|
+
* @internal
|
|
95
|
+
*/
|
|
96
|
+
function sanitizeMetricName(raw) {
|
|
97
|
+
return (0, cloudformation_1.sanitizeString)(raw, METRIC_NAME, "");
|
|
98
|
+
}
|
|
99
|
+
const LABEL_SOURCE = "https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-label-requirements.html";
|
|
100
|
+
/** Each colon-separated part of a rule label: a namespace or the name. */
|
|
101
|
+
const LABEL_PART = (0, cloudformation_1.stringConstraint)({
|
|
102
|
+
name: "WAFv2 rule label part",
|
|
103
|
+
...WAF_NAME_RULE,
|
|
104
|
+
source: LABEL_SOURCE,
|
|
105
|
+
});
|
|
106
|
+
const RESERVED_LABEL_WORDS = [
|
|
107
|
+
"awswaf",
|
|
108
|
+
"aws",
|
|
109
|
+
"waf",
|
|
110
|
+
"rulegroup",
|
|
111
|
+
"webacl",
|
|
112
|
+
"regexpatternset",
|
|
113
|
+
"ipset",
|
|
114
|
+
"managed",
|
|
115
|
+
];
|
|
116
|
+
const MAX_LABEL_NAMESPACES = 5;
|
|
117
|
+
/**
|
|
118
|
+
* Validates a label a rule adds to matching requests: up to five
|
|
119
|
+
* colon-separated namespaces and a name, each 1–128 characters of
|
|
120
|
+
* `[A-Za-z0-9_-]`, none of them one of WAF's reserved words. WAF adds the
|
|
121
|
+
* `awswaf:<account>:webacl:<name>:` prefix itself, so it is not part of the
|
|
122
|
+
* label.
|
|
123
|
+
*
|
|
124
|
+
* @throws on invalid input.
|
|
125
|
+
*/
|
|
126
|
+
function validateRuleLabel(raw) {
|
|
127
|
+
if (aws_cdk_lib_1.Token.isUnresolved(raw))
|
|
128
|
+
return;
|
|
129
|
+
const components = raw.split(":");
|
|
130
|
+
if (components.length > MAX_LABEL_NAMESPACES + 1) {
|
|
131
|
+
throw new Error(`WAFv2 rule label "${raw}" has ${String(components.length - 1)} namespaces; at most ${String(MAX_LABEL_NAMESPACES)} are allowed. See ${LABEL_SOURCE}.`);
|
|
132
|
+
}
|
|
133
|
+
for (const component of components) {
|
|
134
|
+
(0, cloudformation_1.validateString)(component, LABEL_PART);
|
|
135
|
+
if (RESERVED_LABEL_WORDS.includes(component)) {
|
|
136
|
+
throw new Error(`WAFv2 rule label "${raw}" uses "${component}", which AWS WAF reserves. Reserved: ${RESERVED_LABEL_WORDS.join(", ")}. See ${LABEL_SOURCE}.`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.js","sourceRoot":"","sources":["../../src/names.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { CfnWebACL } from "aws-cdk-lib/aws-wafv2";
|
|
2
|
+
import { COPY_STATE, type IBuilder } from "@composurecdk/core";
|
|
3
|
+
import type { CustomResponseBody, CustomResponseBodies } from "./custom-response.js";
|
|
4
|
+
import type { WebAclRuleAlarmConfig } from "./alarm-config.js";
|
|
5
|
+
/** The action a rule takes on a request that matches its statement. */
|
|
6
|
+
export type WebAclRuleAction = "block" | "allow" | "count" | "captcha" | "challenge";
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for one rule in a web ACL. The statement, action, custom
|
|
9
|
+
* response and labels are set with the builder's methods; these are the rest.
|
|
10
|
+
*/
|
|
11
|
+
export interface WebAclRuleBuilderProps {
|
|
12
|
+
/**
|
|
13
|
+
* The rule's priority. WAF evaluates rules from the lowest priority up.
|
|
14
|
+
* Defaults to ten times the rule's position in `addRule` order, so rules
|
|
15
|
+
* run in the order they are declared. Must be unique within the web ACL.
|
|
16
|
+
*/
|
|
17
|
+
priority?: number;
|
|
18
|
+
/**
|
|
19
|
+
* The name of the rule's CloudWatch metrics. Defaults to the rule's name.
|
|
20
|
+
*/
|
|
21
|
+
metricName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether WAF keeps a sample of the requests this rule matches. Defaults to
|
|
24
|
+
* the web ACL's `sampledRequests`, which is off.
|
|
25
|
+
*/
|
|
26
|
+
sampledRequests?: boolean;
|
|
27
|
+
/** CAPTCHA immunity for this rule, overriding the web ACL's. */
|
|
28
|
+
captchaConfig?: CfnWebACL.RuleProperty["captchaConfig"];
|
|
29
|
+
/** Challenge immunity for this rule, overriding the web ACL's. */
|
|
30
|
+
challengeConfig?: CfnWebACL.RuleProperty["challengeConfig"];
|
|
31
|
+
/**
|
|
32
|
+
* This rule's recommended alarms: a `BlockedRequests` alarm, on by default
|
|
33
|
+
* for a rule you wrote that blocks and opt-in for a rule-group rule, and a
|
|
34
|
+
* `DaysToExpiry` alarm for a pinned managed rule group version. `false`
|
|
35
|
+
* disables both.
|
|
36
|
+
*/
|
|
37
|
+
alarms?: WebAclRuleAlarmConfig | false;
|
|
38
|
+
}
|
|
39
|
+
/** What the web ACL builder knows when it turns a rule into CloudFormation. */
|
|
40
|
+
export interface RuleBuildContext {
|
|
41
|
+
/** The rule's name, as given to `addRule`. */
|
|
42
|
+
readonly name: string;
|
|
43
|
+
/** Names the web ACL in error messages. */
|
|
44
|
+
readonly owner: string;
|
|
45
|
+
/** The priority to use unless the rule sets its own. */
|
|
46
|
+
readonly defaultPriority: number;
|
|
47
|
+
/** The web ACL's sampling setting, which the rule inherits. */
|
|
48
|
+
readonly sampledRequests: boolean;
|
|
49
|
+
/** Where custom response bodies are collected. */
|
|
50
|
+
readonly bodies: CustomResponseBodies;
|
|
51
|
+
}
|
|
52
|
+
/** A rule turned into CloudFormation, with what the web ACL needs to know about it. */
|
|
53
|
+
export interface BuiltRule {
|
|
54
|
+
readonly property: CfnWebACL.RuleProperty & {
|
|
55
|
+
readonly priority: number;
|
|
56
|
+
};
|
|
57
|
+
/** The rule's CloudWatch metric name: the `Rule` dimension of its metrics. */
|
|
58
|
+
readonly metricName: string;
|
|
59
|
+
readonly sampled: boolean;
|
|
60
|
+
readonly rateBased: boolean;
|
|
61
|
+
/** Whether the rule evaluates a rule group, so takes `overrideAction`. */
|
|
62
|
+
readonly ruleGroup: boolean;
|
|
63
|
+
/** Whether matching requests are blocked: by the rule, or by a rule group's own rules. */
|
|
64
|
+
readonly blocks: boolean;
|
|
65
|
+
/** The rule's recommended alarm configuration. */
|
|
66
|
+
readonly alarms: WebAclRuleAlarmConfig | false | undefined;
|
|
67
|
+
}
|
|
68
|
+
declare class WebAclRuleBuilder {
|
|
69
|
+
#private;
|
|
70
|
+
props: Partial<WebAclRuleBuilderProps>;
|
|
71
|
+
/**
|
|
72
|
+
* Sets the rule's statement as raw CloudFormation, for a statement this
|
|
73
|
+
* builder has no helper for. Fields CDK types as `any` — `singleHeader`,
|
|
74
|
+
* `queryString`, `uriPath`, `method` and the like — pass through verbatim,
|
|
75
|
+
* so they must use CloudFormation's PascalCase (`{ Name: "x-api-key" }`).
|
|
76
|
+
*
|
|
77
|
+
* A rule has exactly one statement; setting a second throws.
|
|
78
|
+
*/
|
|
79
|
+
statement(statement: CfnWebACL.StatementProperty): this;
|
|
80
|
+
/** Blocks matching requests. This is the default action. */
|
|
81
|
+
block(): this;
|
|
82
|
+
/** Allows matching requests, ending evaluation of the web ACL. */
|
|
83
|
+
allow(): this;
|
|
84
|
+
/**
|
|
85
|
+
* Counts matching requests and carries on evaluating. On a rule-group rule
|
|
86
|
+
* this counts every rule in the group instead of applying its actions.
|
|
87
|
+
*/
|
|
88
|
+
count(): this;
|
|
89
|
+
/** Answers matching requests with a CAPTCHA puzzle. */
|
|
90
|
+
captcha(): this;
|
|
91
|
+
/** Answers matching requests with a silent browser challenge. */
|
|
92
|
+
challenge(): this;
|
|
93
|
+
/**
|
|
94
|
+
* Blocks matching requests with a custom response instead of WAF's `403`.
|
|
95
|
+
* The body is collected into the web ACL's `customResponseBodies`, so
|
|
96
|
+
* nothing has to be declared there by hand.
|
|
97
|
+
*
|
|
98
|
+
* @param status - One of the status codes WAF supports; `410` is not.
|
|
99
|
+
* @param body - `{ json }`, `{ text }` or `{ html }`; at most 4 KB.
|
|
100
|
+
* @param headers - At most 10, and not `content-type`.
|
|
101
|
+
*/
|
|
102
|
+
respond(status: number, body?: CustomResponseBody, headers?: Record<string, string>): this;
|
|
103
|
+
/**
|
|
104
|
+
* Adds labels to matching requests, for later rules to match on with a
|
|
105
|
+
* label match statement. Give the namespaces and name only, such as
|
|
106
|
+
* `"auth:missing-token"`; WAF adds the web ACL prefix.
|
|
107
|
+
*/
|
|
108
|
+
labels(...labels: string[]): this;
|
|
109
|
+
/** @internal — see ADR-0005. */
|
|
110
|
+
[COPY_STATE](target: WebAclRuleBuilder): void;
|
|
111
|
+
/** @internal — the web ACL builder turns each rule into CloudFormation. */
|
|
112
|
+
toRule(ctx: RuleBuildContext): BuiltRule;
|
|
113
|
+
}
|
|
114
|
+
type FullWebAclRuleBuilder = IBuilder<WebAclRuleBuilderProps, WebAclRuleBuilder>;
|
|
115
|
+
/**
|
|
116
|
+
* Fluent configuration for one rule in a web ACL, passed to the callback of
|
|
117
|
+
* {@link IWebAclBuilder.addRule}.
|
|
118
|
+
*/
|
|
119
|
+
export type IWebAclRuleBuilder = Omit<FullWebAclRuleBuilder, "toRule">;
|
|
120
|
+
/** @internal — the web ACL builder makes one of these per rule. */
|
|
121
|
+
export declare function createWebAclRuleBuilder(): FullWebAclRuleBuilder;
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=rule-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-builder.d.ts","sourceRoot":"","sources":["../../src/rule-builder.ts"],"names":[],"mappings":"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"}
|