From bd306b406c19ffb5295507046c1d9528a0ce5193 Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 29 Jun 2020 13:06:13 -0700 Subject: [PATCH 1/9] allow default IPv6 ingress rule for ALB w/ dualstack + internet facing --- .../lib/alb/application-load-balancer.ts | 7 ++++ .../test/alb/test.listener.ts | 37 ++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts index fe829d83d4a1e..40aec9a2e6f45 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts @@ -56,6 +56,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic } public readonly connections: ec2.Connections; + public readonly ipAddressType?: IpAddressType; private readonly securityGroup: ec2.ISecurityGroup; constructor(scope: Construct, id: string, props: ApplicationLoadBalancerProps) { @@ -65,6 +66,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic ipAddressType: props.ipAddressType, }); + this.ipAddressType = props.ipAddressType || IpAddressType.IPV4; this.securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, description: `Automatically created Security Group for ELB ${this.node.uniqueId}`, @@ -458,6 +460,11 @@ export interface IApplicationLoadBalancer extends ILoadBalancerV2, ec2.IConnecta */ readonly vpc?: ec2.IVpc; + /** + * The IP Address Type for this load balancer + */ + readonly ipAddressType?: IpAddressType; + /** * Add a new listener to this load balancer */ diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts index 825e4472db7cb..aa20ccaf25bcd 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts @@ -48,7 +48,7 @@ export = { test.done(); }, - 'Listener default to open'(test: Test) { + 'Listener default to open - IPv4'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); @@ -76,6 +76,41 @@ export = { test.done(); }, + 'Listener default to open - Dualstack'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const loadBalancer = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc, ipAddressType: elbv2.IpAddressType.DUAL_STACK}); + + // WHEN + loadBalancer.addListener('MyListener', { + port: 80, + defaultTargetGroups: [new elbv2.ApplicationTargetGroup(stack, 'Group', { vpc, port: 80 })], + }); + + // THEN + expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: [ + { + Description: 'Allow from anyone on port 80', + CidrIp: '0.0.0.0/0', + FromPort: 80, + IpProtocol: 'tcp', + ToPort: 80, + }, + { + Description: 'Allow from anyone on port 80', + CidrIpv6: '::/0', + FromPort: 80, + IpProtocol: 'tcp', + ToPort: 80, + }, + ], + })); + + test.done(); + }, + 'HTTPS listener requires certificate'(test: Test) { // GIVEN const stack = new cdk.Stack(); From 7c8f26dccae0b79cc64cb86bd9c33fdf2b713db0 Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 29 Jun 2020 13:06:52 -0700 Subject: [PATCH 2/9] update w/ application-listener changes --- .../lib/alb/application-listener.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index f671e705ec78b..7bbf2b4ddbf93 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -2,7 +2,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import { Construct, Duration, IResource, Lazy, Resource, Token } from '@aws-cdk/core'; import { BaseListener } from '../shared/base-listener'; import { HealthCheck } from '../shared/base-target-group'; -import { ApplicationProtocol, SslPolicy } from '../shared/enums'; +import { ApplicationProtocol, IpAddressType, SslPolicy } from '../shared/enums'; import { IListenerCertificate, ListenerCertificate } from '../shared/listener-certificate'; import { determineProtocolAndPort } from '../shared/util'; import { ListenerAction } from './application-listener-action'; @@ -186,6 +186,10 @@ export class ApplicationListener extends BaseListener implements IApplicationLis if (props.open !== false) { this.connections.allowDefaultPortFrom(ec2.Peer.anyIpv4(), `Allow from anyone on port ${port}`); } + + if (props.open !== false && this.loadBalancer.ipAddressType === IpAddressType.DUAL_STACK) { + this.connections.allowDefaultPortFrom(ec2.Peer.anyIpv6(), `Allow from anyone on port ${port}`); + } } /** @@ -539,6 +543,7 @@ class ImportedApplicationListener extends Resource implements IApplicationListen throw new Error('Either `securityGroup` or `securityGroupId` must be specified to import an application listener.'); } + // TODO: Allow this to accept connections that are IPv6 if dualstack this.connections = new ec2.Connections({ securityGroups: [securityGroup], defaultPort, From c28e54ccd77f03925fe339bdcdf46eac253ad9f8 Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 29 Jun 2020 14:02:22 -0700 Subject: [PATCH 3/9] removed unncessary todo --- .../aws-elasticloadbalancingv2/lib/alb/application-listener.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 7bbf2b4ddbf93..583e71dea92f1 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -543,7 +543,6 @@ class ImportedApplicationListener extends Resource implements IApplicationListen throw new Error('Either `securityGroup` or `securityGroupId` must be specified to import an application listener.'); } - // TODO: Allow this to accept connections that are IPv6 if dualstack this.connections = new ec2.Connections({ securityGroups: [securityGroup], defaultPort, From c0becc878f1e9b5f25846c57ae2019e1161ec0e8 Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 29 Jun 2020 14:30:50 -0700 Subject: [PATCH 4/9] added integration check for ipAddressType: dualstack --- .../test/integ.alb3.expected.json | 671 ++++++++++++++++++ .../test/integ.alb3.ts | 53 ++ 2 files changed, 724 insertions(+) create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json new file mode 100644 index 0000000000000..939cde601998b --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json @@ -0,0 +1,671 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "LB8A12904C": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "LBSecurityGroup8A41EA2B", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ], + "Type": "application" + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ] + }, + "LBSecurityGroup8A41EA2B": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB9950B1E4", + "SecurityGroupEgress": [ + { + "CidrIp": "255.255.255.255/32", + "Description": "Disallow all traffic", + "FromPort": 252, + "IpProtocol": "icmp", + "ToPort": 86 + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + }, + { + "CidrIp": "::/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LBListener49E825B4": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "LBListenerTargetGroupF04FCF6D" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "LB8A12904C" + }, + "Port": 80, + "Protocol": "HTTP" + } + }, + "LBListenerTargetGroupF04FCF6D": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "Targets": [ + { + "Id": "10.0.128.4" + } + ], + "TargetType": "ip", + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LBListenerConditionalTargetGroupA75CCCD9": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "Targets": [ + { + "Id": "10.0.128.5" + } + ], + "TargetType": "ip", + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LBListenerConditionalTargetRule91FA260F": { + "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", + "Properties": { + "Actions": [ + { + "TargetGroupArn": { + "Ref": "LBListenerConditionalTargetGroupA75CCCD9" + }, + "Type": "forward" + } + ], + "Conditions": [ + { + "Field": "host-header", + "Values": [ + "example.com" + ] + } + ], + "ListenerArn": { + "Ref": "LBListener49E825B4" + }, + "Priority": 10 + } + }, + "LBListeneraction1Rule86E405BB": { + "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", + "Properties": { + "Actions": [ + { + "FixedResponseConfig": { + "MessageBody": "success", + "StatusCode": "200" + }, + "Type": "fixed-response" + } + ], + "Conditions": [ + { + "Field": "host-header", + "HostHeaderConfig": { + "Values": [ + "example.com" + ] + } + } + ], + "ListenerArn": { + "Ref": "LBListener49E825B4" + }, + "Priority": 1 + } + }, + "ResponseTimeHigh1D16E109F": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 2, + "Dimensions": [ + { + "Name": "LoadBalancer", + "Value": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "/", + { + "Ref": "LBListener49E825B4" + } + ] + } + ] + }, + "/", + { + "Fn::Select": [ + 2, + { + "Fn::Split": [ + "/", + { + "Ref": "LBListener49E825B4" + } + ] + } + ] + }, + "/", + { + "Fn::Select": [ + 3, + { + "Fn::Split": [ + "/", + { + "Ref": "LBListener49E825B4" + } + ] + } + ] + } + ] + ] + } + }, + { + "Name": "TargetGroup", + "Value": { + "Fn::GetAtt": [ + "LBListenerTargetGroupF04FCF6D", + "TargetGroupFullName" + ] + } + } + ], + "MetricName": "TargetResponseTime", + "Namespace": "AWS/ApplicationELB", + "Period": 300, + "Statistic": "Average", + "Threshold": 5 + } + }, + "ResponseTimeHigh2FFCF1FE1": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 2, + "Dimensions": [ + { + "Name": "LoadBalancer", + "Value": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "/", + { + "Ref": "LBListener49E825B4" + } + ] + } + ] + }, + "/", + { + "Fn::Select": [ + 2, + { + "Fn::Split": [ + "/", + { + "Ref": "LBListener49E825B4" + } + ] + } + ] + }, + "/", + { + "Fn::Select": [ + 3, + { + "Fn::Split": [ + "/", + { + "Ref": "LBListener49E825B4" + } + ] + } + ] + } + ] + ] + } + }, + { + "Name": "TargetGroup", + "Value": { + "Fn::GetAtt": [ + "LBListenerConditionalTargetGroupA75CCCD9", + "TargetGroupFullName" + ] + } + } + ], + "MetricName": "TargetResponseTime", + "Namespace": "AWS/ApplicationELB", + "Period": 300, + "Statistic": "Average", + "Threshold": 5 + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts new file mode 100644 index 0000000000000..1dc485b57c5ee --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts @@ -0,0 +1,53 @@ +#!/usr/bin/env node +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as elbv2 from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-elbv2-integ'); + +const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 2, +}); + +const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { + vpc, + ipAddressType: elbv2.IpAddressType.DUAL_STACK, + internetFacing: true, +}); + +const listener = lb.addListener('Listener', { + port: 80, +}); + +const group1 = listener.addTargets('Target', { + port: 80, + targets: [new elbv2.IpTarget('10.0.128.4')], +}); + +const group2 = listener.addTargets('ConditionalTarget', { + priority: 10, + hostHeader: 'example.com', + port: 80, + targets: [new elbv2.IpTarget('10.0.128.5')], +}); + +listener.addAction('action1', { + priority: 1, + conditions: [ + elbv2.ListenerCondition.hostHeaders(['example.com']), + ], + action: elbv2.ListenerAction.fixedResponse(200, {messageBody: 'success'}), +}); + +group1.metricTargetResponseTime().createAlarm(stack, 'ResponseTimeHigh1', { + threshold: 5, + evaluationPeriods: 2, +}); + +group2.metricTargetResponseTime().createAlarm(stack, 'ResponseTimeHigh2', { + threshold: 5, + evaluationPeriods: 2, +}); + +app.synth(); From dcbe5f555f918c7c22217f862a3cddbe6ff11b98 Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 29 Jun 2020 15:43:52 -0700 Subject: [PATCH 5/9] adjusted for ipv6 workaround --- .../test/integ.alb3.expected.json | 42 ++++++++++++++ .../test/integ.alb3.ts | 55 +++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json index 939cde601998b..12a7c02b4c554 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json @@ -23,6 +23,24 @@ "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1a", + "Ipv6CidrBlock": { + "Fn::Select":[ + 0, { + "Fn::Cidr": [{ + "Fn::Select":[ + "0", { + "Fn::GetAtt": [ + "VPC89E5F0B4", + "Ipv6CidrBlocks" + ] + } + ]}, + 0, + "64" + ] + } + ] + }, "MapPublicIpOnLaunch": true, "Tags": [ { @@ -37,6 +55,9 @@ "Key": "Name", "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" } + ], + "DependsOn": [ + "IPv6Block" ] } }, @@ -120,6 +141,24 @@ "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1b", + "Ipv6CidrBlock": { + "Fn::Select":[ + 0, { + "Fn::Cidr": [{ + "Fn::Select":[ + "0", { + "Fn::GetAtt": [ + "VPC89E5F0B4", + "Ipv6CidrBlocks" + ] + } + ]}, + 0, + "64" + ] + } + ] + }, "MapPublicIpOnLaunch": true, "Tags": [ { @@ -134,6 +173,9 @@ "Key": "Name", "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" } + ], + "DependsOn": [ + "IPv6Block" ] } }, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts index 1dc485b57c5ee..906384087343b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts @@ -3,6 +3,14 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../lib'; +const valueOrDie = ( + value: T | undefined, + err: Error, +): C => { + if (value === undefined) { throw err; } + return value as C; +}; + const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-elbv2-integ'); @@ -10,6 +18,53 @@ const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2, }); +const ipv6Block = new ec2.CfnVPCCidrBlock( + stack, + `IPv6_Block`, + { + vpcId: vpc.vpcId, + amazonProvidedIpv6CidrBlock: true + } +); + +// Get the vpc's internet gateway so we can create default routes for the +// public subnets. +const internetGateway = valueOrDie( + vpc.node.children.find(c => c instanceof ec2.CfnInternetGateway), + new Error("Couldn't find an internet gateway"), +); + +vpc.publicSubnets.forEach((subnet, idx) => { + // Add a default ipv6 route to the subnet's route table. + const unboxedSubnet = subnet as ec2.Subnet; + unboxedSubnet.addRoute("IPv6Default", { + routerId: internetGateway.ref, + routerType: ec2.RouterType.GATEWAY, + destinationIpv6CidrBlock: "::/0", + }); + + // Find a CfnSubnet (raw cloudformation resources) child to the public + // subnet nodes. + const cfnSubnet = valueOrDie( + subnet.node.children.find(c => c instanceof ec2.CfnSubnet), + new Error("Couldn't find a CfnSubnet"), + ); + + // Use the intrinsic Fn::Cidr CloudFormation function on the VPC's + // first IPv6 block to determine ipv6 /64 cidrs for each subnet as + // a function of the public subnet's index. + const vpcCidrBlock = cdk.Fn.select(0, vpc.vpcIpv6CidrBlocks); + const ipv6Cidrs = cdk.Fn.cidr( + vpcCidrBlock, + vpc.publicSubnets.length, + "64", + ); + cfnSubnet.ipv6CidrBlock = cdk.Fn.select(idx, ipv6Cidrs); + + // The subnet depends on the ipv6 cidr being allocated. + cfnSubnet.addDependsOn(ipv6Block); +}); + const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc, ipAddressType: elbv2.IpAddressType.DUAL_STACK, From b7186b2c69b33b2c6146204af6ecd69e6e18d50c Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 29 Jun 2020 15:51:59 -0700 Subject: [PATCH 6/9] eslint makes me sad --- .../test/integ.alb3.ts | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts index 906384087343b..7db1bc73746bc 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts @@ -3,10 +3,8 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../lib'; -const valueOrDie = ( - value: T | undefined, - err: Error, -): C => { +/* Credit to @TrueBrain and @misterjoshua for the IPv6 workaround */ +const valueOrDie = (value: T | undefined, err: Error): C => { if (value === undefined) { throw err; } return value as C; }; @@ -20,34 +18,34 @@ const vpc = new ec2.Vpc(stack, 'VPC', { const ipv6Block = new ec2.CfnVPCCidrBlock( stack, - `IPv6_Block`, + 'IPv6_Block', { vpcId: vpc.vpcId, - amazonProvidedIpv6CidrBlock: true - } + amazonProvidedIpv6CidrBlock: true, + }, ); // Get the vpc's internet gateway so we can create default routes for the // public subnets. const internetGateway = valueOrDie( vpc.node.children.find(c => c instanceof ec2.CfnInternetGateway), - new Error("Couldn't find an internet gateway"), + new Error('Couldnt find an internet gateway'), ); vpc.publicSubnets.forEach((subnet, idx) => { // Add a default ipv6 route to the subnet's route table. const unboxedSubnet = subnet as ec2.Subnet; - unboxedSubnet.addRoute("IPv6Default", { + unboxedSubnet.addRoute('IPv6Default', { routerId: internetGateway.ref, routerType: ec2.RouterType.GATEWAY, - destinationIpv6CidrBlock: "::/0", + destinationIpv6CidrBlock: '::/0', }); // Find a CfnSubnet (raw cloudformation resources) child to the public // subnet nodes. const cfnSubnet = valueOrDie( subnet.node.children.find(c => c instanceof ec2.CfnSubnet), - new Error("Couldn't find a CfnSubnet"), + new Error('Couldnt find a CfnSubnet'), ); // Use the intrinsic Fn::Cidr CloudFormation function on the VPC's @@ -57,7 +55,7 @@ vpc.publicSubnets.forEach((subnet, idx) => { const ipv6Cidrs = cdk.Fn.cidr( vpcCidrBlock, vpc.publicSubnets.length, - "64", + '64', ); cfnSubnet.ipv6CidrBlock = cdk.Fn.select(idx, ipv6Cidrs); From ade9b91f852070abaa654e196aa866c85538e18d Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 29 Jun 2020 16:07:25 -0700 Subject: [PATCH 7/9] adjust integ.alb3 for ipv6 block --- .../test/integ.alb3.expected.json | 108 ++++++++++++------ 1 file changed, 75 insertions(+), 33 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json index 12a7c02b4c554..c98f3faa86290 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json @@ -24,18 +24,22 @@ }, "AvailabilityZone": "test-region-1a", "Ipv6CidrBlock": { - "Fn::Select":[ - 0, { - "Fn::Cidr": [{ - "Fn::Select":[ - "0", { - "Fn::GetAtt": [ - "VPC89E5F0B4", - "Ipv6CidrBlocks" - ] - } - ]}, - 0, + "Fn::Select": [ + 0, + { + "Fn::Cidr": [ + { + "Fn::Select": [ + 0, + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "Ipv6CidrBlocks" + ] + } + ] + }, + 2, "64" ] } @@ -55,11 +59,11 @@ "Key": "Name", "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" } - ], - "DependsOn": [ - "IPv6Block" ] - } + }, + "DependsOn": [ + "IPv6Block" + ] }, "VPCPublicSubnet1RouteTableFEE4B781": { "Type": "AWS::EC2::RouteTable", @@ -133,6 +137,18 @@ ] } }, + "VPCPublicSubnet1IPv6DefaultFD18367E": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationIpv6CidrBlock": "::/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, "VPCPublicSubnet2Subnet74179F39": { "Type": "AWS::EC2::Subnet", "Properties": { @@ -142,18 +158,22 @@ }, "AvailabilityZone": "test-region-1b", "Ipv6CidrBlock": { - "Fn::Select":[ - 0, { - "Fn::Cidr": [{ - "Fn::Select":[ - "0", { - "Fn::GetAtt": [ - "VPC89E5F0B4", - "Ipv6CidrBlocks" - ] - } - ]}, - 0, + "Fn::Select": [ + 1, + { + "Fn::Cidr": [ + { + "Fn::Select": [ + 0, + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "Ipv6CidrBlocks" + ] + } + ] + }, + 2, "64" ] } @@ -173,11 +193,11 @@ "Key": "Name", "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" } - ], - "DependsOn": [ - "IPv6Block" ] - } + }, + "DependsOn": [ + "IPv6Block" + ] }, "VPCPublicSubnet2RouteTable6F1A15F1": { "Type": "AWS::EC2::RouteTable", @@ -251,6 +271,18 @@ ] } }, + "VPCPublicSubnet2IPv6DefaultDD0476C2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationIpv6CidrBlock": "::/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, "VPCPrivateSubnet1Subnet8BCA10E0": { "Type": "AWS::EC2::Subnet", "Properties": { @@ -397,9 +429,19 @@ } } }, + "IPv6Block": { + "Type": "AWS::EC2::VPCCidrBlock", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AmazonProvidedIpv6CidrBlock": true + } + }, "LB8A12904C": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties": { + "IpAddressType": "dualstack", "Scheme": "internet-facing", "SecurityGroups": [ { @@ -446,7 +488,7 @@ "ToPort": 80 }, { - "CidrIp": "::/0", + "CidrIpv6": "::/0", "Description": "Allow from anyone on port 80", "FromPort": 80, "IpProtocol": "tcp", From 586f2557b2202bd480c15dcc01d53c7c0606646a Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Tue, 30 Jun 2020 15:22:42 -0700 Subject: [PATCH 8/9] shiv inspired me to put some documentation in my integ test --- .../aws-elasticloadbalancingv2/test/integ.alb3.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts index 7db1bc73746bc..b202ab0e85f7a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts @@ -9,6 +9,16 @@ const valueOrDie = (value: T | undefined, err: Error): C => return value as C; }; +/** + * Integration test to deployability and use of dualstack ALB. Creates an ALB + * with dualstack ipAddresType and an ipv6Block to add to VPC subnets. Main + * test is for the inclusion of default IPv6 ingress rule. + * + * Stack Verification steps: + * VPC is created with subnets that allow for IPv6 connection and then dualstack + * ALB attaches a listener with dualstack that defaults IPv4/IPv6 ingress rule. + * + */ const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-elbv2-integ'); From 874bddb3763307ad5a88c0ac9f32263de836c5e9 Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Wed, 1 Jul 2020 09:32:04 -0700 Subject: [PATCH 9/9] address readability comments --- .../lib/alb/application-listener.ts | 7 +++---- .../lib/alb/application-load-balancer.ts | 4 +++- .../aws-elasticloadbalancingv2/test/alb/test.listener.ts | 2 +- ...lb3.expected.json => integ.alb.dualstack.expected.json} | 0 .../test/{integ.alb3.ts => integ.alb.dualstack.ts} | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) rename packages/@aws-cdk/aws-elasticloadbalancingv2/test/{integ.alb3.expected.json => integ.alb.dualstack.expected.json} (100%) rename packages/@aws-cdk/aws-elasticloadbalancingv2/test/{integ.alb3.ts => integ.alb.dualstack.ts} (97%) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 583e71dea92f1..6809b777a9343 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -185,10 +185,9 @@ export class ApplicationListener extends BaseListener implements IApplicationLis if (props.open !== false) { this.connections.allowDefaultPortFrom(ec2.Peer.anyIpv4(), `Allow from anyone on port ${port}`); - } - - if (props.open !== false && this.loadBalancer.ipAddressType === IpAddressType.DUAL_STACK) { - this.connections.allowDefaultPortFrom(ec2.Peer.anyIpv6(), `Allow from anyone on port ${port}`); + if (this.loadBalancer.ipAddressType === IpAddressType.DUAL_STACK) { + this.connections.allowDefaultPortFrom(ec2.Peer.anyIpv6(), `Allow from anyone on port ${port}`); + } } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts index 40aec9a2e6f45..bbf91ed8834e4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts @@ -66,7 +66,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic ipAddressType: props.ipAddressType, }); - this.ipAddressType = props.ipAddressType || IpAddressType.IPV4; + this.ipAddressType = props.ipAddressType ?? IpAddressType.IPV4; this.securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, description: `Automatically created Security Group for ELB ${this.node.uniqueId}`, @@ -462,6 +462,8 @@ export interface IApplicationLoadBalancer extends ILoadBalancerV2, ec2.IConnecta /** * The IP Address Type for this load balancer + * + * @default IpAddressType.IPV4 */ readonly ipAddressType?: IpAddressType; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts index aa20ccaf25bcd..188fd80ea4eea 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts @@ -76,7 +76,7 @@ export = { test.done(); }, - 'Listener default to open - Dualstack'(test: Test) { + 'Listener default to open - IPv4 and IPv6 (dualstack)'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.expected.json similarity index 100% rename from packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.expected.json rename to packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.expected.json diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts similarity index 97% rename from packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts rename to packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts index b202ab0e85f7a..5ce09e6f82ef3 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb3.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts @@ -3,7 +3,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import * as elbv2 from '../lib'; -/* Credit to @TrueBrain and @misterjoshua for the IPv6 workaround */ +/* IPv6 workaround found here: https://github.com/aws/aws-cdk/issues/894 */ const valueOrDie = (value: T | undefined, err: Error): C => { if (value === undefined) { throw err; } return value as C;