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(elbv2): Implement IConnectable to NLB #28494

Merged
merged 28 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8c2d773
feat(elbv2): Implement IConnectable to NLB
WinterYukky Dec 26, 2023
c2fc279
test(elbv2): remove unnecessary test
WinterYukky Dec 26, 2023
0b67abd
docs(elbv2): add description of NLB using SecurityGroup
WinterYukky Dec 26, 2023
a9d15d2
test(elbv2): update to using security group and assertions by http api
WinterYukky Dec 27, 2023
91f9e1f
feat(elbv2): supported imported security groups
WinterYukky Dec 27, 2023
643584a
test(elbv2): fix dummy value
WinterYukky Dec 28, 2023
a4b5324
test(elbv2): add fromNetworkLoadBalancerAttributes integ test
WinterYukky Dec 28, 2023
745f931
test(elbv2): use nlb connections
WinterYukky Dec 29, 2023
6a19bbc
revert: THIRD_PARTY_LICENSES
WinterYukky Jan 4, 2024
953a282
chore: mark securityGroups as deprecated
WinterYukky Jan 4, 2024
20ce6db
Update packages/aws-cdk-lib/aws-elasticloadbalancingv2/lib/nlb/networ…
WinterYukky Jan 4, 2024
cb68e88
Update packages/aws-cdk-lib/aws-elasticloadbalancingv2/test/nlb/load-…
WinterYukky Jan 4, 2024
ab8d0a4
Update packages/aws-cdk-lib/aws-elasticloadbalancingv2/test/nlb/load-…
WinterYukky Jan 4, 2024
fe33c04
Update packages/aws-cdk-lib/aws-elasticloadbalancingv2/lib/nlb/networ…
WinterYukky Jan 4, 2024
bea84c0
Merge branch 'main' into feat/elbv2/implement-IConnectable-NLB
WinterYukky Jan 4, 2024
0aa750c
chore(elbv2): backwards compatible on securityGroups
WinterYukky Jan 4, 2024
da632ef
Revert "chore(elbv2): backwards compatible on securityGroups"
WinterYukky Jan 5, 2024
2f68a0a
fix: keep original security groups
WinterYukky Jan 5, 2024
6c6f905
test: update integ
WinterYukky Jan 5, 2024
6e0d64e
Update packages/aws-cdk-lib/aws-elasticloadbalancingv2/lib/nlb/networ…
WinterYukky Jan 5, 2024
297b2a6
Update packages/aws-cdk-lib/aws-elasticloadbalancingv2/lib/nlb/networ…
WinterYukky Jan 5, 2024
602a1b2
Update packages/aws-cdk-lib/aws-elasticloadbalancingv2/lib/nlb/networ…
WinterYukky Jan 5, 2024
70a88e5
chore: originalSecurityGroups to boolean
WinterYukky Jan 5, 2024
0aff8cb
chore: simplify securityGroups
WinterYukky Jan 5, 2024
500ecce
fix: security groups are undefined even if security groups are added …
WinterYukky Jan 5, 2024
569910f
Merge branch 'main' into feat/elbv2/implement-IConnectable-NLB
paulhcsun Jan 15, 2024
0db974c
Merge branch 'main' into feat/elbv2/implement-IConnectable-NLB
paulhcsun Jan 15, 2024
2a13aa1
Merge branch 'main' into feat/elbv2/implement-IConnectable-NLB
paulhcsun Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BaseNetworkListenerProps, NetworkListener } from './network-listener';
import * as cloudwatch from '../../../aws-cloudwatch';
import * as ec2 from '../../../aws-ec2';
import * as cxschema from '../../../cloud-assembly-schema';
import { Resource } from '../../../core';
import { Lazy, Resource } from '../../../core';
import * as cxapi from '../../../cx-api';
import { NetworkELBMetrics } from '../elasticloadbalancingv2-canned-metrics.generated';
import { BaseLoadBalancer, BaseLoadBalancerLookupOptions, BaseLoadBalancerProps, ILoadBalancerV2 } from '../shared/base-load-balancer';
Expand Down Expand Up @@ -165,6 +165,11 @@ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoa

public static fromNetworkLoadBalancerAttributes(scope: Construct, id: string, attrs: NetworkLoadBalancerAttributes): INetworkLoadBalancer {
class Import extends Resource implements INetworkLoadBalancer {
public readonly connections: ec2.Connections = new ec2.Connections({
securityGroups: attrs.loadBalancerSecurityGroups?.map(
securityGroupId => ec2.SecurityGroup.fromSecurityGroupId(this, securityGroupId, securityGroupId),
),
});
public readonly loadBalancerArn = attrs.loadBalancerArn;
public readonly vpc?: ec2.IVpc = attrs.vpc;
public readonly metrics: INetworkLoadBalancerMetrics = new NetworkLoadBalancerMetrics(this, parseLoadBalancerFullName(attrs.loadBalancerArn));
Expand Down Expand Up @@ -196,16 +201,19 @@ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoa
public readonly metrics: INetworkLoadBalancerMetrics;
public readonly securityGroups?: string[];
WinterYukky marked this conversation as resolved.
Show resolved Hide resolved
public readonly ipAddressType?: IpAddressType;
public readonly connections: ec2.Connections;

constructor(scope: Construct, id: string, props: NetworkLoadBalancerProps) {
super(scope, id, props, {
type: 'network',
securityGroups: props.securityGroups?.map(sg => sg.securityGroupId),
securityGroups: Lazy.list({
produce: () => this.connections.securityGroups.length >= 1 ? this.connections.securityGroups.map(sg => sg.securityGroupId) : undefined,
WinterYukky marked this conversation as resolved.
Show resolved Hide resolved
}),
Copy link
Contributor Author

@WinterYukky WinterYukky Dec 26, 2023

Choose a reason for hiding this comment

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

If securityGroups becomes an empty array from undefined, an update will be applied and deployment will not be possible, so in the case of an empty array, it is undefined for backwards compatibility.
ref: https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-security-groups.html#security-group-considerations

ipAddressType: props.ipAddressType,
});

this.metrics = new NetworkLoadBalancerMetrics(this, this.loadBalancerFullName);
this.securityGroups = props.securityGroups?.map(sg => sg.securityGroupId);
this.connections = new ec2.Connections({ securityGroups: props.securityGroups });
WinterYukky marked this conversation as resolved.
Show resolved Hide resolved
this.ipAddressType = props.ipAddressType ?? IpAddressType.IPV4;
if (props.crossZoneEnabled) { this.setAttribute('load_balancing.cross_zone.enabled', 'true'); }
}
Expand All @@ -222,6 +230,13 @@ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoa
});
}

/**
* Add a security group to this load balancer
*/
public addSecurityGroup(securityGroup: ec2.ISecurityGroup) {
this.connections.addSecurityGroup(securityGroup);
WinterYukky marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Return the given named metric for this Network Load Balancer
*
Expand Down Expand Up @@ -415,7 +430,7 @@ export interface INetworkLoadBalancerMetrics {
/**
* A network load balancer
*/
export interface INetworkLoadBalancer extends ILoadBalancerV2, ec2.IVpcEndpointServiceLoadBalancer {
export interface INetworkLoadBalancer extends ILoadBalancerV2, ec2.IVpcEndpointServiceLoadBalancer, ec2.IConnectable {

/**
* The VPC this load balancer has been created in (if available)
Expand Down Expand Up @@ -455,6 +470,7 @@ class LookedUpNetworkLoadBalancer extends Resource implements INetworkLoadBalanc
public readonly metrics: INetworkLoadBalancerMetrics;
public readonly securityGroups?: string[];
public readonly ipAddressType?: IpAddressType;
public readonly connections: ec2.Connections;

constructor(scope: Construct, id: string, props: cxapi.LoadBalancerContextResponse) {
super(scope, id, { environmentFromArn: props.loadBalancerArn });
Expand All @@ -464,6 +480,9 @@ class LookedUpNetworkLoadBalancer extends Resource implements INetworkLoadBalanc
this.loadBalancerDnsName = props.loadBalancerDnsName;
this.metrics = new NetworkLoadBalancerMetrics(this, parseLoadBalancerFullName(props.loadBalancerArn));
this.securityGroups = props.securityGroupIds;
this.connections = new ec2.Connections({
securityGroups: props.securityGroupIds.map(securityGroupId => ec2.SecurityGroup.fromSecurityGroupId(this, securityGroupId, securityGroupId)),
});

if (props.ipAddressType === cxapi.LoadBalancerIpAddressType.IPV4) {
this.ipAddressType = IpAddressType.IPV4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -661,14 +661,17 @@ describe('tests', () => {
const sg2 = new ec2.SecurityGroup(stack, 'SG2', { vpc });

// WHEN
new elbv2.NetworkLoadBalancer(stack, 'LB', {
const nlb = new elbv2.NetworkLoadBalancer(stack, 'LB', {
vpc,
internetFacing: true,
securityGroups: [sg1, sg2],
securityGroups: [sg1],
});
nlb.connections.allowFromAnyIpv4(ec2.Port.tcp(80));
nlb.addSecurityGroup(sg2);

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', {
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', {
Scheme: 'internet-facing',
Subnets: [
{ Ref: 'StackPublicSubnet1Subnet0AD81D22' },
Expand All @@ -690,6 +693,17 @@ describe('tests', () => {
],
Type: 'network',
});
template.resourcePropertiesCountIs('AWS::EC2::SecurityGroup', {
SecurityGroupIngress: [
{
CidrIp: '0.0.0.0/0',
Description: 'from 0.0.0.0/0:80',
FromPort: 80,
IpProtocol: 'tcp',
ToPort: 80,
},
],
}, 2);
});

test('Trivial construction: no security groups', () => {
Expand All @@ -698,20 +712,33 @@ describe('tests', () => {
const vpc = new ec2.Vpc(stack, 'Stack');

// WHEN
new elbv2.NetworkLoadBalancer(stack, 'LB', {
const nlb = new elbv2.NetworkLoadBalancer(stack, 'LB', {
vpc,
internetFacing: true,
});
nlb.connections.allowFromAnyIpv4(ec2.Port.tcp(80));

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', {
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::ElasticLoadBalancingV2::LoadBalancer', {
Scheme: 'internet-facing',
Subnets: [
{ Ref: 'StackPublicSubnet1Subnet0AD81D22' },
{ Ref: 'StackPublicSubnet2Subnet3C7D2288' },
],
SecurityGroups: Match.absent(),
});
template.resourcePropertiesCountIs('AWS::EC2::SecurityGroup', {
SecurityGroupIngress: [
{
CidrIp: '0.0.0.0/0',
Description: 'from 0.0.0.0/0:80',
FromPort: 80,
IpProtocol: 'tcp',
ToPort: 80,
},
],
}, 0);
WinterYukky marked this conversation as resolved.
Show resolved Hide resolved
});

describe('lookup', () => {
Expand Down Expand Up @@ -800,34 +827,32 @@ describe('tests', () => {

test('can look up security groups', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'Stack');
const sg = new ec2.SecurityGroup(stack, 'SG', { vpc });

// WHEN
const nlb = new elbv2.NetworkLoadBalancer(stack, 'LB', {
vpc,
internetFacing: true,
securityGroups: [sg],
const app = new cdk.App();
const stack = new cdk.Stack(app, 'Stack', {
env: {
account: '123456789012',
region: 'us-west-2',
},
});

// THEN
expect(nlb.securityGroups).toEqual([`${sg.securityGroupId}`]);
});

test('can look up with no security groups', () => {
WinterYukky marked this conversation as resolved.
Show resolved Hide resolved
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'Stack');

// WHEN
const nlb = new elbv2.NetworkLoadBalancer(stack, 'LB', {
vpc,
internetFacing: true,
const nlb = elbv2.NetworkLoadBalancer.fromLookup(stack, 'LB', {
loadBalancerTags: {
some: 'tag',
},
});
nlb.connections.allowFromAnyIpv4(ec2.Port.tcp(80));

// THEN
expect(nlb.securityGroups).toBeUndefined();
Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroupIngress', {
CidrIp: '0.0.0.0/0',
Description: 'from 0.0.0.0/0:80',
FromPort: 80,
GroupId: 'sg-1234',
IpProtocol: 'tcp',
ToPort: 80,
});
expect(nlb.securityGroups).toEqual(['sg-1234']);
});
});

Expand Down
Loading