Repository: cdklabs/cdk-monitoring-constructs (language: python)

Issue:
[waf] Support for AWS WAF
### Feature scope

AWS WAF

### Describe your suggested feature

AWS Offers Several different firewall tools. Having Web Application Firewall being monitored in this library would be greatly helpful.


Discussion / hints:
https://docs.aws.amazon.com/waf/latest/developerguide/monitoring-cloudwatch.html

Can you describe which metrics would be useful for you to monitor and alarm on?
When creating a [WAF ACL](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_wafv2.CfnWebACL.html) or [RuleGroups](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_wafv2.CfnRuleGroup.html) there is a visibility section where we can enable and name the metrics:

```typescript
  visibilityConfig: {
    cloudWatchMetricsEnabled: false,
    metricName: 'metricName',
    sampledRequestsEnabled: false,
  },
```

If we can create dashboards on the `COUNT` `BLOCK` and `ALLOW` traffic that would be greatly helpful.
Just curious - what does this metricName parameter do? I see the metric names are specified already in the doc. What changes when you modify it?

Best start IMHO would be if we can agree on the API. How would you like to define your monitoring, what parameters to pass? Should we take visibilityConfig, ACL or RuleGroup?
Based on what I've seen `metricName` allows you to specify custom names for the rule or WAF itself.

As far as API to define monitoring, to keep consistent with other APIs it probably would be a good idea to either take the ACL directly (if we can query the `metricNames` assigned for that ACL) its also worth noting that ACLs can be assigned to an AWS resource, so maybe its possible to "automagically" determine the ACL metrics for services that have them tied already if the API supports it (i.e. API Gateway may have an ACL so `.monitorAPIGateway()` can automatically pull ACL metrics in?, or similar with CloudFront?)
We can take it step by step, e.g. start with something simple and keep extending it.

I have been researching some existing solutions and it seems that people are usually just monitoring allowed vs. blocked requests, typically for ALL rules in the given ACL.

So, what is the basic unit we are monitoring here... is it ACL + subset of rules? Or just list of rules and ACL separately?
Probably the latter as it seems from what I've seen that most ACLs will contain very very similar rules, we may also want to include count as well since that will tell the user if a request matched a rule but was not blocked (generally used for testing new rules?)

Fix patch:
diff --git a/API.md b/API.md
index 5724896a..bdda8378 100644
--- a/API.md
+++ b/API.md
@@ -780,6 +780,7 @@ new MonitoringFacade(scope: Construct, id: string, props: MonitoringFacadeProps)
 | <code><a href="#cdk-monitoring-constructs.MonitoringFacade.monitorStepFunctionLambdaIntegration">monitorStepFunctionLambdaIntegration</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.MonitoringFacade.monitorStepFunctionServiceIntegration">monitorStepFunctionServiceIntegration</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.MonitoringFacade.monitorSyntheticsCanary">monitorSyntheticsCanary</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.MonitoringFacade.monitorWebApplicationFirewallAclV2">monitorWebApplicationFirewallAclV2</a></code> | *No description.* |
 
 ---
 
@@ -1613,6 +1614,18 @@ public monitorSyntheticsCanary(props: SyntheticsCanaryMonitoringProps): Monitori
 
 ---
 
+##### `monitorWebApplicationFirewallAclV2` <a name="monitorWebApplicationFirewallAclV2" id="cdk-monitoring-constructs.MonitoringFacade.monitorWebApplicationFirewallAclV2"></a>
+
+```typescript
+public monitorWebApplicationFirewallAclV2(props: WafV2MonitoringProps): MonitoringFacade
+```
+
+###### `props`<sup>Required</sup> <a name="props" id="cdk-monitoring-constructs.MonitoringFacade.monitorWebApplicationFirewallAclV2.parameter.props"></a>
+
+- *Type:* <a href="#cdk-monitoring-constructs.WafV2MonitoringProps">WafV2MonitoringProps</a>
+
+---
+
 #### Static Functions <a name="Static Functions" id="Static Functions"></a>
 
 | **Name** | **Description** |
@@ -23313,6 +23326,7 @@ const monitoringAspectProps: MonitoringAspectProps = { ... }
 | <code><a href="#cdk-monitoring-constructs.MonitoringAspectProps.property.sqs">sqs</a></code> | <code><a href="#cdk-monitoring-constructs.MonitoringAspectType">MonitoringAspectType</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.MonitoringAspectProps.property.stepFunctions">stepFunctions</a></code> | <code><a href="#cdk-monitoring-constructs.MonitoringAspectType">MonitoringAspectType</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.MonitoringAspectProps.property.syntheticsCanaries">syntheticsCanaries</a></code> | <code><a href="#cdk-monitoring-constructs.MonitoringAspectType">MonitoringAspectType</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.MonitoringAspectProps.property.webApplicationFirewallAclV2">webApplicationFirewallAclV2</a></code> | <code><a href="#cdk-monitoring-constructs.MonitoringAspectType">MonitoringAspectType</a></code> | *No description.* |
 
 ---
 
@@ -23566,6 +23580,16 @@ public readonly syntheticsCanaries: MonitoringAspectType;
 
 ---
 
+##### `webApplicationFirewallAclV2`<sup>Optional</sup> <a name="webApplicationFirewallAclV2" id="cdk-monitoring-constructs.MonitoringAspectProps.property.webApplicationFirewallAclV2"></a>
+
+```typescript
+public readonly webApplicationFirewallAclV2: MonitoringAspectType;
+```
+
+- *Type:* <a href="#cdk-monitoring-constructs.MonitoringAspectType">MonitoringAspectType</a>
+
+---
+
 ### MonitoringAspectType <a name="MonitoringAspectType" id="cdk-monitoring-constructs.MonitoringAspectType"></a>
 
 #### Initializer <a name="Initializer" id="cdk-monitoring-constructs.MonitoringAspectType.Initializer"></a>
@@ -33680,6 +33704,311 @@ The length must be 1 - 255 characters and although the validation rules are undo
 
 ---
 
+### WafV2MetricFactoryProps <a name="WafV2MetricFactoryProps" id="cdk-monitoring-constructs.WafV2MetricFactoryProps"></a>
+
+#### Initializer <a name="Initializer" id="cdk-monitoring-constructs.WafV2MetricFactoryProps.Initializer"></a>
+
+```typescript
+import { WafV2MetricFactoryProps } from 'cdk-monitoring-constructs'
+
+const wafV2MetricFactoryProps: WafV2MetricFactoryProps = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#cdk-monitoring-constructs.WafV2MetricFactoryProps.property.acl">acl</a></code> | <code>monocdk.aws_wafv2.CfnWebACL</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.WafV2MetricFactoryProps.property.region">region</a></code> | <code>string</code> | *No description.* |
+
+---
+
+##### `acl`<sup>Required</sup> <a name="acl" id="cdk-monitoring-constructs.WafV2MetricFactoryProps.property.acl"></a>
+
+```typescript
+public readonly acl: CfnWebACL;
+```
+
+- *Type:* monocdk.aws_wafv2.CfnWebACL
+
+---
+
+##### `region`<sup>Optional</sup> <a name="region" id="cdk-monitoring-constructs.WafV2MetricFactoryProps.property.region"></a>
+
+```typescript
+public readonly region: string;
+```
+
+- *Type:* string
+
+---
+
+### WafV2MonitoringOptions <a name="WafV2MonitoringOptions" id="cdk-monitoring-constructs.WafV2MonitoringOptions"></a>
+
+#### Initializer <a name="Initializer" id="cdk-monitoring-constructs.WafV2MonitoringOptions.Initializer"></a>
+
+```typescript
+import { WafV2MonitoringOptions } from 'cdk-monitoring-constructs'
+
+const wafV2MonitoringOptions: WafV2MonitoringOptions = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringOptions.property.alarmFriendlyName">alarmFriendlyName</a></code> | <code>string</code> | Plain name, used in naming alarms. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringOptions.property.humanReadableName">humanReadableName</a></code> | <code>string</code> | Human-readable name is a freeform string, used as a caption or description. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringOptions.property.localAlarmNamePrefixOverride">localAlarmNamePrefixOverride</a></code> | <code>string</code> | If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringOptions.property.addToAlarmDashboard">addToAlarmDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to alarm dashboard. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringOptions.property.addToDetailDashboard">addToDetailDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to detailed dashboard. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringOptions.property.addToSummaryDashboard">addToSummaryDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to summary dashboard. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringOptions.property.useCreatedAlarms">useCreatedAlarms</a></code> | <code><a href="#cdk-monitoring-constructs.IAlarmConsumer">IAlarmConsumer</a></code> | Calls provided function to process all alarms created. |
+
+---
+
+##### `alarmFriendlyName`<sup>Optional</sup> <a name="alarmFriendlyName" id="cdk-monitoring-constructs.WafV2MonitoringOptions.property.alarmFriendlyName"></a>
+
+```typescript
+public readonly alarmFriendlyName: string;
+```
+
+- *Type:* string
+- *Default:* derives name from the construct itself
+
+Plain name, used in naming alarms.
+
+This unique among other resources, and respect the AWS CDK restriction posed on alarm names.
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+---
+
+##### `humanReadableName`<sup>Optional</sup> <a name="humanReadableName" id="cdk-monitoring-constructs.WafV2MonitoringOptions.property.humanReadableName"></a>
+
+```typescript
+public readonly humanReadableName: string;
+```
+
+- *Type:* string
+- *Default:* use alarmFriendlyName
+
+Human-readable name is a freeform string, used as a caption or description.
+
+There are no limitations on what it can be.
+
+---
+
+##### `localAlarmNamePrefixOverride`<sup>Optional</sup> <a name="localAlarmNamePrefixOverride" id="cdk-monitoring-constructs.WafV2MonitoringOptions.property.localAlarmNamePrefixOverride"></a>
+
+```typescript
+public readonly localAlarmNamePrefixOverride: string;
+```
+
+- *Type:* string
+
+If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value.
+
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+> [AlarmNamingStrategy for more details on alarm name prefixes](AlarmNamingStrategy for more details on alarm name prefixes)
+
+---
+
+##### `addToAlarmDashboard`<sup>Optional</sup> <a name="addToAlarmDashboard" id="cdk-monitoring-constructs.WafV2MonitoringOptions.property.addToAlarmDashboard"></a>
+
+```typescript
+public readonly addToAlarmDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to alarm dashboard.
+
+---
+
+##### `addToDetailDashboard`<sup>Optional</sup> <a name="addToDetailDashboard" id="cdk-monitoring-constructs.WafV2MonitoringOptions.property.addToDetailDashboard"></a>
+
+```typescript
+public readonly addToDetailDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to detailed dashboard.
+
+---
+
+##### `addToSummaryDashboard`<sup>Optional</sup> <a name="addToSummaryDashboard" id="cdk-monitoring-constructs.WafV2MonitoringOptions.property.addToSummaryDashboard"></a>
+
+```typescript
+public readonly addToSummaryDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to summary dashboard.
+
+---
+
+##### `useCreatedAlarms`<sup>Optional</sup> <a name="useCreatedAlarms" id="cdk-monitoring-constructs.WafV2MonitoringOptions.property.useCreatedAlarms"></a>
+
+```typescript
+public readonly useCreatedAlarms: IAlarmConsumer;
+```
+
+- *Type:* <a href="#cdk-monitoring-constructs.IAlarmConsumer">IAlarmConsumer</a>
+
+Calls provided function to process all alarms created.
+
+---
+
+### WafV2MonitoringProps <a name="WafV2MonitoringProps" id="cdk-monitoring-constructs.WafV2MonitoringProps"></a>
+
+#### Initializer <a name="Initializer" id="cdk-monitoring-constructs.WafV2MonitoringProps.Initializer"></a>
+
+```typescript
+import { WafV2MonitoringProps } from 'cdk-monitoring-constructs'
+
+const wafV2MonitoringProps: WafV2MonitoringProps = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.acl">acl</a></code> | <code>monocdk.aws_wafv2.CfnWebACL</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.region">region</a></code> | <code>string</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.alarmFriendlyName">alarmFriendlyName</a></code> | <code>string</code> | Plain name, used in naming alarms. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.humanReadableName">humanReadableName</a></code> | <code>string</code> | Human-readable name is a freeform string, used as a caption or description. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.localAlarmNamePrefixOverride">localAlarmNamePrefixOverride</a></code> | <code>string</code> | If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.addToAlarmDashboard">addToAlarmDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to alarm dashboard. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.addToDetailDashboard">addToDetailDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to detailed dashboard. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.addToSummaryDashboard">addToSummaryDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to summary dashboard. |
+| <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps.property.useCreatedAlarms">useCreatedAlarms</a></code> | <code><a href="#cdk-monitoring-constructs.IAlarmConsumer">IAlarmConsumer</a></code> | Calls provided function to process all alarms created. |
+
+---
+
+##### `acl`<sup>Required</sup> <a name="acl" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.acl"></a>
+
+```typescript
+public readonly acl: CfnWebACL;
+```
+
+- *Type:* monocdk.aws_wafv2.CfnWebACL
+
+---
+
+##### `region`<sup>Optional</sup> <a name="region" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.region"></a>
+
+```typescript
+public readonly region: string;
+```
+
+- *Type:* string
+
+---
+
+##### `alarmFriendlyName`<sup>Optional</sup> <a name="alarmFriendlyName" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.alarmFriendlyName"></a>
+
+```typescript
+public readonly alarmFriendlyName: string;
+```
+
+- *Type:* string
+- *Default:* derives name from the construct itself
+
+Plain name, used in naming alarms.
+
+This unique among other resources, and respect the AWS CDK restriction posed on alarm names.
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+---
+
+##### `humanReadableName`<sup>Optional</sup> <a name="humanReadableName" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.humanReadableName"></a>
+
+```typescript
+public readonly humanReadableName: string;
+```
+
+- *Type:* string
+- *Default:* use alarmFriendlyName
+
+Human-readable name is a freeform string, used as a caption or description.
+
+There are no limitations on what it can be.
+
+---
+
+##### `localAlarmNamePrefixOverride`<sup>Optional</sup> <a name="localAlarmNamePrefixOverride" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.localAlarmNamePrefixOverride"></a>
+
+```typescript
+public readonly localAlarmNamePrefixOverride: string;
+```
+
+- *Type:* string
+
+If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value.
+
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+> [AlarmNamingStrategy for more details on alarm name prefixes](AlarmNamingStrategy for more details on alarm name prefixes)
+
+---
+
+##### `addToAlarmDashboard`<sup>Optional</sup> <a name="addToAlarmDashboard" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.addToAlarmDashboard"></a>
+
+```typescript
+public readonly addToAlarmDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to alarm dashboard.
+
+---
+
+##### `addToDetailDashboard`<sup>Optional</sup> <a name="addToDetailDashboard" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.addToDetailDashboard"></a>
+
+```typescript
+public readonly addToDetailDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to detailed dashboard.
+
+---
+
+##### `addToSummaryDashboard`<sup>Optional</sup> <a name="addToSummaryDashboard" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.addToSummaryDashboard"></a>
+
+```typescript
+public readonly addToSummaryDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to summary dashboard.
+
+---
+
+##### `useCreatedAlarms`<sup>Optional</sup> <a name="useCreatedAlarms" id="cdk-monitoring-constructs.WafV2MonitoringProps.property.useCreatedAlarms"></a>
+
+```typescript
+public readonly useCreatedAlarms: IAlarmConsumer;
+```
+
+- *Type:* <a href="#cdk-monitoring-constructs.IAlarmConsumer">IAlarmConsumer</a>
+
+Calls provided function to process all alarms created.
+
+---
+
 ### XaxrMathExpressionProps <a name="XaxrMathExpressionProps" id="cdk-monitoring-constructs.XaxrMathExpressionProps"></a>
 
 Custom wrapper class for MathExpressionProps that supports account and region customization.
@@ -46733,6 +47062,203 @@ public addMemoryUsagePercentAlarm(percentMetric: Metric | MathExpression, props:
 
 
 
+### WafV2MetricFactory <a name="WafV2MetricFactory" id="cdk-monitoring-constructs.WafV2MetricFactory"></a>
+
+https://docs.aws.amazon.com/waf/latest/developerguide/monitoring-cloudwatch.html.
+
+#### Initializers <a name="Initializers" id="cdk-monitoring-constructs.WafV2MetricFactory.Initializer"></a>
+
+```typescript
+import { WafV2MetricFactory } from 'cdk-monitoring-constructs'
+
+new WafV2MetricFactory(metricFactory: MetricFactory, props: WafV2MetricFactoryProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#cdk-monitoring-constructs.WafV2MetricFactory.Initializer.parameter.metricFactory">metricFactory</a></code> | <code><a href="#cdk-monitoring-constructs.MetricFactory">MetricFactory</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.WafV2MetricFactory.Initializer.parameter.props">props</a></code> | <code><a href="#cdk-monitoring-constructs.WafV2MetricFactoryProps">WafV2MetricFactoryProps</a></code> | *No description.* |
+
+---
+
+##### `metricFactory`<sup>Required</sup> <a name="metricFactory" id="cdk-monitoring-constructs.WafV2MetricFactory.Initializer.parameter.metricFactory"></a>
+
+- *Type:* <a href="#cdk-monitoring-constructs.MetricFactory">MetricFactory</a>
+
+---
+
+##### `props`<sup>Required</sup> <a name="props" id="cdk-monitoring-constructs.WafV2MetricFactory.Initializer.parameter.props"></a>
+
+- *Type:* <a href="#cdk-monitoring-constructs.WafV2MetricFactoryProps">WafV2MetricFactoryProps</a>
+
+---
+
+#### Methods <a name="Methods" id="Methods"></a>
+
+| **Name** | **Description** |
+| --- | --- |
+| <code><a href="#cdk-monitoring-constructs.WafV2MetricFactory.metricAllowedRequests">metricAllowedRequests</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.WafV2MetricFactory.metricBlockedRequests">metricBlockedRequests</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.WafV2MetricFactory.metricBlockedRequestsRate">metricBlockedRequestsRate</a></code> | *No description.* |
+
+---
+
+##### `metricAllowedRequests` <a name="metricAllowedRequests" id="cdk-monitoring-constructs.WafV2MetricFactory.metricAllowedRequests"></a>
+
+```typescript
+public metricAllowedRequests(): Metric | MathExpression
+```
+
+##### `metricBlockedRequests` <a name="metricBlockedRequests" id="cdk-monitoring-constructs.WafV2MetricFactory.metricBlockedRequests"></a>
+
+```typescript
+public metricBlockedRequests(): Metric | MathExpression
+```
+
+##### `metricBlockedRequestsRate` <a name="metricBlockedRequestsRate" id="cdk-monitoring-constructs.WafV2MetricFactory.metricBlockedRequestsRate"></a>
+
+```typescript
+public metricBlockedRequestsRate(): Metric | MathExpression
+```
+
+
+
+
+### WafV2Monitoring <a name="WafV2Monitoring" id="cdk-monitoring-constructs.WafV2Monitoring"></a>
+
+Monitoring for AWS Web Application Firewall.
+
+> [https://docs.aws.amazon.com/waf/latest/developerguide/monitoring-cloudwatch.html](https://docs.aws.amazon.com/waf/latest/developerguide/monitoring-cloudwatch.html)
+
+#### Initializers <a name="Initializers" id="cdk-monitoring-constructs.WafV2Monitoring.Initializer"></a>
+
+```typescript
+import { WafV2Monitoring } from 'cdk-monitoring-constructs'
+
+new WafV2Monitoring(scope: MonitoringScope, props: WafV2MonitoringProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.Initializer.parameter.scope">scope</a></code> | <code><a href="#cdk-monitoring-constructs.MonitoringScope">MonitoringScope</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.Initializer.parameter.props">props</a></code> | <code><a href="#cdk-monitoring-constructs.WafV2MonitoringProps">WafV2MonitoringProps</a></code> | *No description.* |
+
+---
+
+##### `scope`<sup>Required</sup> <a name="scope" id="cdk-monitoring-constructs.WafV2Monitoring.Initializer.parameter.scope"></a>
+
+- *Type:* <a href="#cdk-monitoring-constructs.MonitoringScope">MonitoringScope</a>
+
+---
+
+##### `props`<sup>Required</sup> <a name="props" id="cdk-monitoring-constructs.WafV2Monitoring.Initializer.parameter.props"></a>
+
+- *Type:* <a href="#cdk-monitoring-constructs.WafV2MonitoringProps">WafV2MonitoringProps</a>
+
+---
+
+#### Methods <a name="Methods" id="Methods"></a>
+
+| **Name** | **Description** |
+| --- | --- |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.addAlarm">addAlarm</a></code> | Adds an alarm. |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.alarmWidgets">alarmWidgets</a></code> | Returns widgets for all alarms. |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.createAlarmFactory">createAlarmFactory</a></code> | Creates a new alarm factory. |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.createdAlarms">createdAlarms</a></code> | Returns all the alarms created. |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.createMetricFactory">createMetricFactory</a></code> | Creates a new metric factory. |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.createWidgetFactory">createWidgetFactory</a></code> | Creates a new widget factory. |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.summaryWidgets">summaryWidgets</a></code> | Returns widgets to be placed on the summary dashboard. |
+| <code><a href="#cdk-monitoring-constructs.WafV2Monitoring.widgets">widgets</a></code> | Returns widgets to be placed on the main dashboard. |
+
+---
+
+##### `addAlarm` <a name="addAlarm" id="cdk-monitoring-constructs.WafV2Monitoring.addAlarm"></a>
+
+```typescript
+public addAlarm(alarm: AlarmWithAnnotation): void
+```
+
+Adds an alarm.
+
+###### `alarm`<sup>Required</sup> <a name="alarm" id="cdk-monitoring-constructs.WafV2Monitoring.addAlarm.parameter.alarm"></a>
+
+- *Type:* <a href="#cdk-monitoring-constructs.AlarmWithAnnotation">AlarmWithAnnotation</a>
+
+alarm to add.
+
+---
+
+##### `alarmWidgets` <a name="alarmWidgets" id="cdk-monitoring-constructs.WafV2Monitoring.alarmWidgets"></a>
+
+```typescript
+public alarmWidgets(): IWidget[]
+```
+
+Returns widgets for all alarms.
+
+These can go to runbook or to service dashboard.
+
+##### `createAlarmFactory` <a name="createAlarmFactory" id="cdk-monitoring-constructs.WafV2Monitoring.createAlarmFactory"></a>
+
+```typescript
+public createAlarmFactory(alarmNamePrefix: string): AlarmFactory
+```
+
+Creates a new alarm factory.
+
+Alarms created will be named with the given prefix, unless a local name override is present.
+
+###### `alarmNamePrefix`<sup>Required</sup> <a name="alarmNamePrefix" id="cdk-monitoring-constructs.WafV2Monitoring.createAlarmFactory.parameter.alarmNamePrefix"></a>
+
+- *Type:* string
+
+alarm name prefix.
+
+---
+
+##### `createdAlarms` <a name="createdAlarms" id="cdk-monitoring-constructs.WafV2Monitoring.createdAlarms"></a>
+
+```typescript
+public createdAlarms(): AlarmWithAnnotation[]
+```
+
+Returns all the alarms created.
+
+##### `createMetricFactory` <a name="createMetricFactory" id="cdk-monitoring-constructs.WafV2Monitoring.createMetricFactory"></a>
+
+```typescript
+public createMetricFactory(): MetricFactory
+```
+
+Creates a new metric factory.
+
+##### `createWidgetFactory` <a name="createWidgetFactory" id="cdk-monitoring-constructs.WafV2Monitoring.createWidgetFactory"></a>
+
+```typescript
+public createWidgetFactory(): IWidgetFactory
+```
+
+Creates a new widget factory.
+
+##### `summaryWidgets` <a name="summaryWidgets" id="cdk-monitoring-constructs.WafV2Monitoring.summaryWidgets"></a>
+
+```typescript
+public summaryWidgets(): IWidget[]
+```
+
+Returns widgets to be placed on the summary dashboard.
+
+##### `widgets` <a name="widgets" id="cdk-monitoring-constructs.WafV2Monitoring.widgets"></a>
+
+```typescript
+public widgets(): IWidget[]
+```
+
+Returns widgets to be placed on the main dashboard.
+
+
+
+
 ### XaxrMathExpression <a name="XaxrMathExpression" id="cdk-monitoring-constructs.XaxrMathExpression"></a>
 
 - *Implements:* monocdk.aws_cloudwatch.IMetric
@@ -47027,7 +47553,7 @@ Dashboard placement override props.
 
 ### IDashboardSegment <a name="IDashboardSegment" id="cdk-monitoring-constructs.IDashboardSegment"></a>
 
-- *Implemented By:* <a href="#cdk-monitoring-constructs.ApiGatewayMonitoring">ApiGatewayMonitoring</a>, <a href="#cdk-monitoring-constructs.ApiGatewayV2HttpApiMonitoring">ApiGatewayV2HttpApiMonitoring</a>, <a href="#cdk-monitoring-constructs.AppSyncMonitoring">AppSyncMonitoring</a>, <a href="#cdk-monitoring-constructs.AutoScalingGroupMonitoring">AutoScalingGroupMonitoring</a>, <a href="#cdk-monitoring-constructs.BillingMonitoring">BillingMonitoring</a>, <a href="#cdk-monitoring-constructs.CertificateManagerMonitoring">CertificateManagerMonitoring</a>, <a href="#cdk-monitoring-constructs.CloudFrontDistributionMonitoring">CloudFrontDistributionMonitoring</a>, <a href="#cdk-monitoring-constructs.CodeBuildProjectMonitoring">CodeBuildProjectMonitoring</a>, <a href="#cdk-monitoring-constructs.CustomMonitoring">CustomMonitoring</a>, <a href="#cdk-monitoring-constructs.DynamoTableGlobalSecondaryIndexMonitoring">DynamoTableGlobalSecondaryIndexMonitoring</a>, <a href="#cdk-monitoring-constructs.DynamoTableMonitoring">DynamoTableMonitoring</a>, <a href="#cdk-monitoring-constructs.EC2Monitoring">EC2Monitoring</a>, <a href="#cdk-monitoring-constructs.Ec2ServiceMonitoring">Ec2ServiceMonitoring</a>, <a href="#cdk-monitoring-constructs.ElastiCacheClusterMonitoring">ElastiCacheClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.FargateServiceMonitoring">FargateServiceMonitoring</a>, <a href="#cdk-monitoring-constructs.GlueJobMonitoring">GlueJobMonitoring</a>, <a href="#cdk-monitoring-constructs.KinesisDataAnalyticsMonitoring">KinesisDataAnalyticsMonitoring</a>, <a href="#cdk-monitoring-constructs.KinesisDataStreamMonitoring">KinesisDataStreamMonitoring</a>, <a href="#cdk-monitoring-constructs.KinesisFirehoseMonitoring">KinesisFirehoseMonitoring</a>, <a href="#cdk-monitoring-constructs.LambdaFunctionMonitoring">LambdaFunctionMonitoring</a>, <a href="#cdk-monitoring-constructs.LogMonitoring">LogMonitoring</a>, <a href="#cdk-monitoring-constructs.Monitoring">Monitoring</a>, <a href="#cdk-monitoring-constructs.NetworkLoadBalancerMonitoring">NetworkLoadBalancerMonitoring</a>, <a href="#cdk-monitoring-constructs.OpenSearchClusterMonitoring">OpenSearchClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.RdsClusterMonitoring">RdsClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.RedshiftClusterMonitoring">RedshiftClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.S3BucketMonitoring">S3BucketMonitoring</a>, <a href="#cdk-monitoring-constructs.SecretsManagerSecretMonitoring">SecretsManagerSecretMonitoring</a>, <a href="#cdk-monitoring-constructs.SingleWidgetDashboardSegment">SingleWidgetDashboardSegment</a>, <a href="#cdk-monitoring-constructs.SnsTopicMonitoring">SnsTopicMonitoring</a>, <a href="#cdk-monitoring-constructs.SqsQueueMonitoring">SqsQueueMonitoring</a>, <a href="#cdk-monitoring-constructs.SqsQueueMonitoringWithDlq">SqsQueueMonitoringWithDlq</a>, <a href="#cdk-monitoring-constructs.StepFunctionActivityMonitoring">StepFunctionActivityMonitoring</a>, <a href="#cdk-monitoring-constructs.StepFunctionLambdaIntegrationMonitoring">StepFunctionLambdaIntegrationMonitoring</a>, <a href="#cdk-monitoring-constructs.StepFunctionMonitoring">StepFunctionMonitoring</a>, <a href="#cdk-monitoring-constructs.StepFunctionServiceIntegrationMonitoring">StepFunctionServiceIntegrationMonitoring</a>, <a href="#cdk-monitoring-constructs.SyntheticsCanaryMonitoring">SyntheticsCanaryMonitoring</a>, <a href="#cdk-monitoring-constructs.IDashboardSegment">IDashboardSegment</a>
+- *Implemented By:* <a href="#cdk-monitoring-constructs.ApiGatewayMonitoring">ApiGatewayMonitoring</a>, <a href="#cdk-monitoring-constructs.ApiGatewayV2HttpApiMonitoring">ApiGatewayV2HttpApiMonitoring</a>, <a href="#cdk-monitoring-constructs.AppSyncMonitoring">AppSyncMonitoring</a>, <a href="#cdk-monitoring-constructs.AutoScalingGroupMonitoring">AutoScalingGroupMonitoring</a>, <a href="#cdk-monitoring-constructs.BillingMonitoring">BillingMonitoring</a>, <a href="#cdk-monitoring-constructs.CertificateManagerMonitoring">CertificateManagerMonitoring</a>, <a href="#cdk-monitoring-constructs.CloudFrontDistributionMonitoring">CloudFrontDistributionMonitoring</a>, <a href="#cdk-monitoring-constructs.CodeBuildProjectMonitoring">CodeBuildProjectMonitoring</a>, <a href="#cdk-monitoring-constructs.CustomMonitoring">CustomMonitoring</a>, <a href="#cdk-monitoring-constructs.DynamoTableGlobalSecondaryIndexMonitoring">DynamoTableGlobalSecondaryIndexMonitoring</a>, <a href="#cdk-monitoring-constructs.DynamoTableMonitoring">DynamoTableMonitoring</a>, <a href="#cdk-monitoring-constructs.EC2Monitoring">EC2Monitoring</a>, <a href="#cdk-monitoring-constructs.Ec2ServiceMonitoring">Ec2ServiceMonitoring</a>, <a href="#cdk-monitoring-constructs.ElastiCacheClusterMonitoring">ElastiCacheClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.FargateServiceMonitoring">FargateServiceMonitoring</a>, <a href="#cdk-monitoring-constructs.GlueJobMonitoring">GlueJobMonitoring</a>, <a href="#cdk-monitoring-constructs.KinesisDataAnalyticsMonitoring">KinesisDataAnalyticsMonitoring</a>, <a href="#cdk-monitoring-constructs.KinesisDataStreamMonitoring">KinesisDataStreamMonitoring</a>, <a href="#cdk-monitoring-constructs.KinesisFirehoseMonitoring">KinesisFirehoseMonitoring</a>, <a href="#cdk-monitoring-constructs.LambdaFunctionMonitoring">LambdaFunctionMonitoring</a>, <a href="#cdk-monitoring-constructs.LogMonitoring">LogMonitoring</a>, <a href="#cdk-monitoring-constructs.Monitoring">Monitoring</a>, <a href="#cdk-monitoring-constructs.NetworkLoadBalancerMonitoring">NetworkLoadBalancerMonitoring</a>, <a href="#cdk-monitoring-constructs.OpenSearchClusterMonitoring">OpenSearchClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.RdsClusterMonitoring">RdsClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.RedshiftClusterMonitoring">RedshiftClusterMonitoring</a>, <a href="#cdk-monitoring-constructs.S3BucketMonitoring">S3BucketMonitoring</a>, <a href="#cdk-monitoring-constructs.SecretsManagerSecretMonitoring">SecretsManagerSecretMonitoring</a>, <a href="#cdk-monitoring-constructs.SingleWidgetDashboardSegment">SingleWidgetDashboardSegment</a>, <a href="#cdk-monitoring-constructs.SnsTopicMonitoring">SnsTopicMonitoring</a>, <a href="#cdk-monitoring-constructs.SqsQueueMonitoring">SqsQueueMonitoring</a>, <a href="#cdk-monitoring-constructs.SqsQueueMonitoringWithDlq">SqsQueueMonitoringWithDlq</a>, <a href="#cdk-monitoring-constructs.StepFunctionActivityMonitoring">StepFunctionActivityMonitoring</a>, <a href="#cdk-monitoring-constructs.StepFunctionLambdaIntegrationMonitoring">StepFunctionLambdaIntegrationMonitoring</a>, <a href="#cdk-monitoring-constructs.StepFunctionMonitoring">StepFunctionMonitoring</a>, <a href="#cdk-monitoring-constructs.StepFunctionServiceIntegrationMonitoring">StepFunctionServiceIntegrationMonitoring</a>, <a href="#cdk-monitoring-constructs.SyntheticsCanaryMonitoring">SyntheticsCanaryMonitoring</a>, <a href="#cdk-monitoring-constructs.WafV2Monitoring">WafV2Monitoring</a>, <a href="#cdk-monitoring-constructs.IDashboardSegment">IDashboardSegment</a>
 
 #### Methods <a name="Methods" id="Methods"></a>
 
diff --git a/README.md b/README.md
index 74463f77..24655546 100644
--- a/README.md
+++ b/README.md
@@ -90,6 +90,7 @@ You can also browse the documentation at https://constructs.dev/packages/cdk-mon
 | AWS SNS Topic (`.monitorSnsTopic()`) | Message count, size, failed notifications | Failed notifications | |
 | AWS SQS Queue (`.monitorSqsQueue()`, `.monitorSqsQueueWithDlq()`) | Message count, age, size | Message count, age, DLQ incoming messages | |
 | AWS Step Functions (`.monitorStepFunction()`, `.monitorStepFunctionActivity()`, `monitorStepFunctionLambdaIntegration()`, `.monitorStepFunctionServiceIntegration()`) | Execution count and breakdown per state | Duration, failed, failed rate, aborted, throttled, timed out executions | |
+| AWS Web Application Firewall (`.monitorWebApplicationFirewallAcl()`) | Allowed/blocked requests | | |
 | CloudWatch Logs (`.monitorLog()`) | Patterns present in the log group | | |
 | Custom metrics (`.monitorCustom()`) | Addition of custom metrics into the dashboard (each group is a widget) | | Supports anomaly detection |
 
diff --git a/lib/facade/MonitoringAspect.ts b/lib/facade/MonitoringAspect.ts
index 9411da48..05591650 100644
--- a/lib/facade/MonitoringAspect.ts
+++ b/lib/facade/MonitoringAspect.ts
@@ -22,6 +22,7 @@ import * as sns from "monocdk/aws-sns";
 import * as sqs from "monocdk/aws-sqs";
 import * as stepfunctions from "monocdk/aws-stepfunctions";
 import * as synthetics from "monocdk/aws-synthetics";
+import * as wafv2 from "monocdk/aws-wafv2";
 
 import { ElastiCacheClusterType } from "../monitoring";
 import { MonitoringAspectProps, MonitoringAspectType } from "./aspect-types";
@@ -64,6 +65,7 @@ export class MonitoringAspect implements IAspect {
     this.monitorSqs(node);
     this.monitorStepFunctions(node);
     this.monitorSyntheticsCanaries(node);
+    this.monitorWebApplicationFirewallV2Acls(node);
 
     if (!this.addedNodeIndependentMonitoringToScope) {
       this.addedNodeIndependentMonitoringToScope = true;
@@ -365,6 +367,18 @@ export class MonitoringAspect implements IAspect {
       });
     }
   }
+
+  private monitorWebApplicationFirewallV2Acls(node: IConstruct) {
+    const [isEnabled, props] = this.getMonitoringDetails(
+      this.props.webApplicationFirewallAclV2
+    );
+    if (isEnabled && node instanceof wafv2.CfnWebACL) {
+      this.monitoringFacade.monitorWebApplicationFirewallAclV2({
+        acl: node,
+        ...props,
+      });
+    }
+  }
 }
 
 export * from "./aspect-types";
diff --git a/lib/facade/MonitoringFacade.ts b/lib/facade/MonitoringFacade.ts
index 0145889a..5c7802a1 100644
--- a/lib/facade/MonitoringFacade.ts
+++ b/lib/facade/MonitoringFacade.ts
@@ -103,6 +103,8 @@ import {
   getQueueProcessingFargateServiceMonitoring,
   SyntheticsCanaryMonitoringProps,
   SyntheticsCanaryMonitoring,
+  WafV2MonitoringProps,
+  WafV2Monitoring,
 } from "../monitoring";
 import { MonitoringAspect, MonitoringAspectProps } from "./MonitoringAspect";
 
@@ -613,6 +615,12 @@ export class MonitoringFacade extends MonitoringScope {
     return this;
   }
 
+  monitorWebApplicationFirewallAclV2(props: WafV2MonitoringProps) {
+    const segment = new WafV2Monitoring(this, props);
+    this.addSegment(segment, props);
+    return this;
+  }
+
   monitorBilling(props?: BillingMonitoringProps) {
     const segment = new BillingMonitoring(this, props ?? {});
     this.addSegment(segment, props);
diff --git a/lib/facade/aspect-types.ts b/lib/facade/aspect-types.ts
index 8b02b7d5..1c7b733f 100644
--- a/lib/facade/aspect-types.ts
+++ b/lib/facade/aspect-types.ts
@@ -24,6 +24,7 @@ import {
   SqsQueueMonitoringOptions,
   StepFunctionMonitoringOptions,
   SyntheticsCanaryMonitoringOptions,
+  WafV2MonitoringOptions,
 } from "../monitoring";
 
 export interface MonitoringAspectType<T> {
@@ -66,4 +67,5 @@ export interface MonitoringAspectProps {
   readonly sqs?: MonitoringAspectType<SqsQueueMonitoringOptions>;
   readonly stepFunctions?: MonitoringAspectType<StepFunctionMonitoringOptions>;
   readonly syntheticsCanaries?: MonitoringAspectType<SyntheticsCanaryMonitoringOptions>;
+  readonly webApplicationFirewallAclV2?: MonitoringAspectType<WafV2MonitoringOptions>;
 }
diff --git a/lib/monitoring/aws-wafv2/WafV2MetricFactory.ts b/lib/monitoring/aws-wafv2/WafV2MetricFactory.ts
new file mode 100644
index 00000000..dd91492d
--- /dev/null
+++ b/lib/monitoring/aws-wafv2/WafV2MetricFactory.ts
@@ -0,0 +1,60 @@
+import { DimensionHash } from "monocdk/aws-cloudwatch";
+import { CfnWebACL } from "monocdk/aws-wafv2";
+import { MetricFactory, MetricStatistic } from "../../common";
+
+const MetricNamespace = "AWS/WAFV2";
+const AllRulesDimensionValue = "ALL";
+
+export interface WafV2MetricFactoryProps {
+  readonly region?: string;
+  readonly acl: CfnWebACL;
+}
+
+/**
+ * https://docs.aws.amazon.com/waf/latest/developerguide/monitoring-cloudwatch.html
+ */
+export class WafV2MetricFactory {
+  protected readonly metricFactory: MetricFactory;
+  protected readonly dimensions: DimensionHash;
+
+  constructor(metricFactory: MetricFactory, props: WafV2MetricFactoryProps) {
+    this.metricFactory = metricFactory;
+    this.dimensions = {
+      Rule: AllRulesDimensionValue,
+      WebACL: props.acl.name,
+    };
+  }
+
+  metricAllowedRequests() {
+    return this.metricFactory.createMetric(
+      "AllowedRequests",
+      MetricStatistic.SUM,
+      "Allowed",
+      this.dimensions,
+      undefined,
+      MetricNamespace
+    );
+  }
+
+  metricBlockedRequests() {
+    return this.metricFactory.createMetric(
+      "BlockedRequests",
+      MetricStatistic.SUM,
+      "Blocked",
+      this.dimensions,
+      undefined,
+      MetricNamespace
+    );
+  }
+
+  metricBlockedRequestsRate() {
+    return this.metricFactory.createMetricMath(
+      "100 * (blocked / (allowed + blocked))",
+      {
+        allowed: this.metricAllowedRequests(),
+        blocked: this.metricBlockedRequests(),
+      },
+      "Blocked (rate)"
+    );
+  }
+}
diff --git a/lib/monitoring/aws-wafv2/WafV2Monitoring.ts b/lib/monitoring/aws-wafv2/WafV2Monitoring.ts
new file mode 100644
index 00000000..680fafef
--- /dev/null
+++ b/lib/monitoring/aws-wafv2/WafV2Monitoring.ts
@@ -0,0 +1,119 @@
+import { GraphWidget, IWidget } from "monocdk/aws-cloudwatch";
+import {
+  BaseMonitoringProps,
+  CountAxisFromZero,
+  DefaultGraphWidgetHeight,
+  DefaultSummaryWidgetHeight,
+  MetricWithAlarmSupport,
+  Monitoring,
+  MonitoringScope,
+  RateAxisFromZero,
+  ThirdWidth,
+} from "../../common";
+import {
+  MonitoringHeaderWidget,
+  MonitoringNamingStrategy,
+} from "../../dashboard";
+import {
+  WafV2MetricFactory,
+  WafV2MetricFactoryProps,
+} from "./WafV2MetricFactory";
+
+export interface WafV2MonitoringOptions extends BaseMonitoringProps {}
+
+export interface WafV2MonitoringProps
+  extends WafV2MetricFactoryProps,
+    WafV2MonitoringOptions {}
+
+/**
+ * Monitoring for AWS Web Application Firewall.
+ *
+ * @see https://docs.aws.amazon.com/waf/latest/developerguide/monitoring-cloudwatch.html
+ */
+export class WafV2Monitoring extends Monitoring {
+  protected readonly humanReadableName: string;
+
+  protected readonly allowedRequestsMetric: MetricWithAlarmSupport;
+  protected readonly blockedRequestsMetric: MetricWithAlarmSupport;
+  protected readonly blockedRequestsRateMetric: MetricWithAlarmSupport;
+
+  constructor(scope: MonitoringScope, props: WafV2MonitoringProps) {
+    super(scope, props);
+
+    const namingStrategy = new MonitoringNamingStrategy({
+      ...props,
+      namedConstruct: props.acl,
+    });
+    this.humanReadableName = namingStrategy.resolveHumanReadableName();
+
+    const metricFactory = new WafV2MetricFactory(
+      scope.createMetricFactory(),
+      props
+    );
+
+    this.allowedRequestsMetric = metricFactory.metricAllowedRequests();
+    this.blockedRequestsMetric = metricFactory.metricBlockedRequests();
+    this.blockedRequestsRateMetric = metricFactory.metricBlockedRequestsRate();
+  }
+
+  summaryWidgets(): IWidget[] {
+    return [
+      this.createTitleWidget(),
+      this.createAllowedRequestsWidget(ThirdWidth, DefaultSummaryWidgetHeight),
+      this.createBlockedRequestsWidget(ThirdWidth, DefaultSummaryWidgetHeight),
+      this.createBlockedRequestsRateWidget(
+        ThirdWidth,
+        DefaultSummaryWidgetHeight
+      ),
+    ];
+  }
+
+  widgets(): IWidget[] {
+    return [
+      this.createTitleWidget(),
+      this.createAllowedRequestsWidget(ThirdWidth, DefaultGraphWidgetHeight),
+      this.createBlockedRequestsWidget(ThirdWidth, DefaultSummaryWidgetHeight),
+      this.createBlockedRequestsRateWidget(
+        ThirdWidth,
+        DefaultSummaryWidgetHeight
+      ),
+    ];
+  }
+
+  protected createTitleWidget() {
+    return new MonitoringHeaderWidget({
+      family: "Web Application Firewall",
+      title: this.humanReadableName,
+    });
+  }
+
+  protected createAllowedRequestsWidget(width: number, height: number) {
+    return new GraphWidget({
+      width,
+      height,
+      title: "Allowed Requests",
+      left: [this.allowedRequestsMetric],
+      leftYAxis: CountAxisFromZero,
+    });
+  }
+
+  protected createBlockedRequestsWidget(width: number, height: number) {
+    return new GraphWidget({
+      width,
+      height,
+      title: "Blocked Requests",
+      left: [this.blockedRequestsMetric],
+      leftYAxis: CountAxisFromZero,
+    });
+  }
+
+  protected createBlockedRequestsRateWidget(width: number, height: number) {
+    return new GraphWidget({
+      width,
+      height,
+      title: "Blocked Requests (rate)",
+      left: [this.blockedRequestsRateMetric],
+      leftYAxis: RateAxisFromZero,
+    });
+  }
+}
diff --git a/lib/monitoring/aws-wafv2/index.ts b/lib/monitoring/aws-wafv2/index.ts
new file mode 100644
index 00000000..03c1fdd8
--- /dev/null
+++ b/lib/monitoring/aws-wafv2/index.ts
@@ -0,0 +1,2 @@
+export * from "./WafV2MetricFactory";
+export * from "./WafV2Monitoring";
diff --git a/lib/monitoring/index.ts b/lib/monitoring/index.ts
index e68414f2..a7468576 100644
--- a/lib/monitoring/index.ts
+++ b/lib/monitoring/index.ts
@@ -24,4 +24,5 @@ export * from "./aws-sns";
 export * from "./aws-sqs";
 export * from "./aws-step-functions";
 export * from "./aws-synthetics";
+export * from "./aws-wafv2";
 export * from "./custom";


Test patch:
diff --git a/test/facade/MonitoringAspect.test.ts b/test/facade/MonitoringAspect.test.ts
index 1a07b419..51e9582b 100644
--- a/test/facade/MonitoringAspect.test.ts
+++ b/test/facade/MonitoringAspect.test.ts
@@ -26,6 +26,7 @@ import * as sns from "monocdk/aws-sns";
 import * as sqs from "monocdk/aws-sqs";
 import * as stepfunctions from "monocdk/aws-stepfunctions";
 import * as synthetics from "monocdk/aws-synthetics";
+import { CfnWebACL } from "monocdk/aws-wafv2";
 
 import {
   DefaultDashboardFactory,
@@ -535,4 +536,26 @@ describe("MonitoringAspect", () => {
     // THEN
     expect(Template.fromStack(stack)).toMatchSnapshot();
   });
+
+  test("WAF v2", () => {
+    // GIVEN
+    const stack = new Stack();
+    const facade = createDummyMonitoringFacade(stack);
+
+    new CfnWebACL(stack, "DummyAcl", {
+      defaultAction: { allow: {} },
+      scope: "REGIONAL",
+      visibilityConfig: {
+        sampledRequestsEnabled: true,
+        cloudWatchMetricsEnabled: true,
+        metricName: "DummyMetricName",
+      },
+    });
+
+    // WHEN
+    facade.monitorScope(stack, defaultAspectProps);
+
+    // THEN
+    expect(Template.fromStack(stack)).toMatchSnapshot();
+  });
 });
diff --git a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap
index ecf031c2..0baf5f42 100644
--- a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap
+++ b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap
@@ -7283,3 +7283,83 @@ Object {
   },
 }
 `;
+
+exports[`MonitoringAspect WAF v2 1`] = `
+Object {
+  "Resources": Object {
+    "DashboardFactoryAlarmDashboard6286FAD3": Object {
+      "Properties": Object {
+        "DashboardBody": "{\\"start\\":\\"-PT8H\\",\\"widgets\\":[]}",
+        "DashboardName": "DummyDashboard-Alarms",
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "DashboardFactoryDashboard3E20AD6E": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"start\\":\\"-PT8H\\",\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### Web Application Firewall **DummyAcl**\\"}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Allowed Requests\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"AWS/WAFV2\\",\\"AllowedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Allowed\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":8,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"AWS/WAFV2\\",\\"BlockedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests (rate)\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[{\\"label\\":\\"Blocked (rate)\\",\\"expression\\":\\"100 * (blocked / (allowed + blocked))\\"}],[\\"AWS/WAFV2\\",\\"AllowedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Allowed\\",\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"allowed\\"}],[\\"AWS/WAFV2\\",\\"BlockedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"blocked\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}",
+            ],
+          ],
+        },
+        "DashboardName": "DummyDashboard",
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "DashboardFactorySummaryDashboard5F4BC8C5": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"start\\":\\"-P14D\\",\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### Web Application Firewall **DummyAcl**\\"}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Allowed Requests\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"AWS/WAFV2\\",\\"AllowedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Allowed\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":8,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"AWS/WAFV2\\",\\"BlockedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests (rate)\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[{\\"label\\":\\"Blocked (rate)\\",\\"expression\\":\\"100 * (blocked / (allowed + blocked))\\"}],[\\"AWS/WAFV2\\",\\"AllowedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Allowed\\",\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"allowed\\"}],[\\"AWS/WAFV2\\",\\"BlockedRequests\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"blocked\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}",
+            ],
+          ],
+        },
+        "DashboardName": "DummyDashboard-Summary",
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "DummyAcl": Object {
+      "Properties": Object {
+        "DefaultAction": Object {
+          "Allow": Object {},
+        },
+        "Scope": "REGIONAL",
+        "VisibilityConfig": Object {
+          "CloudWatchMetricsEnabled": true,
+          "MetricName": "DummyMetricName",
+          "SampledRequestsEnabled": true,
+        },
+      },
+      "Type": "AWS::WAFv2::WebACL",
+    },
+  },
+}
+`;
diff --git a/test/monitoring/aws-wafv2/WafV2Monitoring.test.ts b/test/monitoring/aws-wafv2/WafV2Monitoring.test.ts
new file mode 100644
index 00000000..9f9da4c6
--- /dev/null
+++ b/test/monitoring/aws-wafv2/WafV2Monitoring.test.ts
@@ -0,0 +1,25 @@
+import { Stack } from "monocdk";
+import { Template } from "monocdk/assertions";
+import { CfnWebACL } from "monocdk/aws-wafv2";
+
+import { WafV2Monitoring } from "../../../lib";
+import { TestMonitoringScope } from "../TestMonitoringScope";
+
+test("snapshot test: no alarms", () => {
+  const stack = new Stack();
+  const acl = new CfnWebACL(stack, "DummyAcl", {
+    defaultAction: { allow: {} },
+    scope: "REGIONAL",
+    visibilityConfig: {
+      sampledRequestsEnabled: true,
+      cloudWatchMetricsEnabled: true,
+      metricName: "DummyMetricName",
+    },
+  });
+
+  const scope = new TestMonitoringScope(stack, "Scope");
+
+  new WafV2Monitoring(scope, { acl });
+
+  expect(Template.fromStack(stack)).toMatchSnapshot();
+});
diff --git a/test/monitoring/aws-wafv2/__snapshots__/WafV2Monitoring.test.ts.snap b/test/monitoring/aws-wafv2/__snapshots__/WafV2Monitoring.test.ts.snap
new file mode 100644
index 00000000..482fbb25
--- /dev/null
+++ b/test/monitoring/aws-wafv2/__snapshots__/WafV2Monitoring.test.ts.snap
@@ -0,0 +1,22 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`snapshot test: no alarms 1`] = `
+Object {
+  "Resources": Object {
+    "DummyAcl": Object {
+      "Properties": Object {
+        "DefaultAction": Object {
+          "Allow": Object {},
+        },
+        "Scope": "REGIONAL",
+        "VisibilityConfig": Object {
+          "CloudWatchMetricsEnabled": true,
+          "MetricName": "DummyMetricName",
+          "SampledRequestsEnabled": true,
+        },
+      },
+      "Type": "AWS::WAFv2::WebACL",
+    },
+  },
+}
+`;