Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wafv2): add L2 IPSet #6230

Closed
wants to merge 13 commits into from
17 changes: 17 additions & 0 deletions packages/@aws-cdk/aws-wafv2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,20 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw
```ts
import wafv2 = require('@aws-cdk/aws-wafv2');
```

### IPSet

Use an AWS::WAFv2::IPSet to identify web requests that originate from specific IP addresses or ranges of IP addresses. For example, if you're receiving a lot of requests from a ranges of IP addresses, you can configure AWS WAF to block them using an IP set that lists those IP addresses.
wulfmann marked this conversation as resolved.
Show resolved Hide resolved

Example:

```ts
import waf = require('@aws-cdk/aws-wafv2');

new waf.IPSet(this, 'MyIPSet', {
addresses: [
'192.168.1.1/32
wulfmann marked this conversation as resolved.
Show resolved Hide resolved
],
name: 'MyIPSet'
})
```
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-wafv2/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// AWS::WAFv2 CloudFormation Resources:
export * from './wafv2.generated';
export * from './ipset';
111 changes: 111 additions & 0 deletions packages/@aws-cdk/aws-wafv2/lib/ipset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import * as cdk from '@aws-cdk/core';
import * as waf from './index';

export enum IPAddressVersion {
wulfmann marked this conversation as resolved.
Show resolved Hide resolved
IPV4 = 'IPV4',
IPV6 = 'IPV6'
}

export enum IPSetScope {
wulfmann marked this conversation as resolved.
Show resolved Hide resolved
CLOUDFRONT = 'CLOUDFRONT',
REGIONAL = 'REGIONAL'
}

export interface IIPSet {
/**
* A friendly name of the IP set. You cannot change the name of an IPSet
* after you create it.
*/
readonly ipSetName: string;
}

export abstract class IPSetBase extends cdk.Resource implements IIPSet {
/**
* A friendly name of the IP set. You cannot change the name of an IPSet
* after you create it.
*/
public abstract readonly ipSetName: string;
}

export interface IPSetProps {
wulfmann marked this conversation as resolved.
Show resolved Hide resolved
/**
* A friendly name of the IP set. You cannot change the name of an IPSet
* after you create it.
*/
readonly name?: string;

/**
* A friendly description of the IP set. You cannot change the description
* of an IP set after you create it.
*/
readonly description?: string;
wulfmann marked this conversation as resolved.
Show resolved Hide resolved

/**
* Contains an array of strings that specify one or more IP addresses or
* blocks of IP addresses in Classless Inter-Domain Routing (CIDR) notation.
* AWS WAF supports all address ranges for IP versions IPv4 and IPv6.
*/
readonly addresses?: string[];

/**
* Specify IPV4 or IPV6.
*
* @efault IPV4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

D efault

*/
readonly ipAddressVersion: IPAddressVersion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is not optional. Probably should be?


/**
* Specifies whether this is for an AWS CloudFront distribution or for a
* regional application. A regional application can be an Application
* Load Balancer (ALB) or an API Gateway stage.
*
* @default CLOUDFRONT
*/
readonly scope: IPSetScope;
wulfmann marked this conversation as resolved.
Show resolved Hide resolved
}

export class IPSet extends IPSetBase {
/**
* A friendly name of the IP set. You cannot change the name of an IPSet
* after you create it.
*/
public readonly ipSetName: string;
wulfmann marked this conversation as resolved.
Show resolved Hide resolved

/**
* Contains an array of strings that specify one or more IP addresses or
* blocks of IP addresses in Classless Inter-Domain Routing (CIDR) notation.
* AWS WAF supports all address ranges for IP versions IPv4 and IPv6.
*/
private addresses: string[] = [];

constructor(scope: cdk.Construct, id: string, props: IPSetProps) {
super(scope, id, {
physicalName: props.name || cdk.PhysicalName.GENERATE_IF_NEEDED
});

this.ipSetName = this.physicalName;
wulfmann marked this conversation as resolved.
Show resolved Hide resolved

this.addAddresses(...props.addresses || []);

const resource: waf.CfnIPSet = new waf.CfnIPSet(this, 'Resource', {
addresses: {
ipAddresses: cdk.Lazy.listValue({ produce: () => this.addresses }, { omitEmpty: true })
},
ipAddressVersion: props.ipAddressVersion || IPAddressVersion.IPV4,
name: props.name,
scope: props.scope || IPSetScope.CLOUDFRONT,
description: props.description
});

this.node.defaultChild = resource;
wulfmann marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Adds an ip address to the the addresses list
*/
public addAddresses(...addresses: string[]): void {
for (const address of addresses) {
this.addresses.push(address);
}
}
}
89 changes: 89 additions & 0 deletions packages/@aws-cdk/aws-wafv2/test/ipset.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { expect } from '@aws-cdk/assert';
import * as cdk from '@aws-cdk/core';
import * as waf from '../lib';

test('IPV4 IP Set', () => {
const stack = new cdk.Stack();
new waf.IPSet(stack, 'IPSet', {
addresses: [
'192.168.1.1'
],
scope: waf.IPSetScope.CLOUDFRONT,
ipAddressVersion: waf.IPAddressVersion.IPV4
});

expect(stack).toMatch({
Resources: {
IPSetEBDDFDAE: {
Type: "AWS::WAFv2::IPSet",
Properties: {
Addresses: {
IPAddresses: ["192.168.1.1"]
},
IPAddressVersion: "IPV4",
Scope: "CLOUDFRONT"
}
}
}
});
});

test('IPV6 IP Set', () => {
const stack = new cdk.Stack();
new waf.IPSet(stack, 'IPSet', {
addresses: [
'2001:0db8:85a3:0000:0000:8a2e:0370:7334'
],
scope: waf.IPSetScope.CLOUDFRONT,
ipAddressVersion: waf.IPAddressVersion.IPV6
});

expect(stack).toMatch({
Resources: {
IPSetEBDDFDAE: {
Type: "AWS::WAFv2::IPSet",
Properties: {
Addresses: {
IPAddresses: [
"2001:0db8:85a3:0000:0000:8a2e:0370:7334"
]
},
IPAddressVersion: "IPV6",
Scope: "CLOUDFRONT"
}
}
}
});
});

test('addAddresses method with name and description', () => {
const stack = new cdk.Stack();

const ipSet = new waf.IPSet(stack, 'IPSet', {
scope: waf.IPSetScope.CLOUDFRONT,
ipAddressVersion: waf.IPAddressVersion.IPV6,
name: 'MyIPSet',
description: 'MyIPSet Description'
});

ipSet.addAddresses('2001:0db8:85a3:0000:0000:8a2e:0370:7334');

expect(stack).toMatch({
Resources: {
IPSetEBDDFDAE: {
Type: "AWS::WAFv2::IPSet",
Properties: {
Addresses: {
IPAddresses: [
"2001:0db8:85a3:0000:0000:8a2e:0370:7334"
]
},
IPAddressVersion: "IPV6",
Scope: "CLOUDFRONT",
Name: "MyIPSet",
Description: "MyIPSet Description"
}
}
}
});
});