Skip to content

Commit 5ef34a1

Browse files
jogoldmergify[bot]
authored andcommitted
feat(ecs,lambda,rds): specify allowAllOutbound when importing security groups (#3833)
* fix(lambda/rds): expose allowAllOutbound prop when importing * fix and test ecs * test lambda * test elbv2 * test rds * deprecate in rds * deprecate in lambda * deprecate in elbv2 * JSDoc * JSDoc * remove securityGroupId in rds BREAKING CHANGE: `securityGroupId: string` replaced by `securityGroup: ISecurityGroup` when importing a cluster/instance in `@aws-cdk/aws-rds`
1 parent b7d00ec commit 5ef34a1

File tree

12 files changed

+178
-26
lines changed

12 files changed

+178
-26
lines changed

packages/@aws-cdk/aws-ecs/lib/cluster.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,9 @@ class ImportedCluster extends Resource implements ICluster {
581581
resourceName: props.clusterName
582582
});
583583

584-
let i = 1;
585-
for (const sgProps of props.securityGroups) {
586-
this.connections.addSecurityGroup(ec2.SecurityGroup.fromSecurityGroupId(this, `SecurityGroup${i}`, sgProps.securityGroupId));
587-
i++;
588-
}
584+
this.connections = new ec2.Connections({
585+
securityGroups: props.securityGroups
586+
});
589587
}
590588

591589
public get defaultCloudMapNamespace(): cloudmap.INamespace | undefined {

packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { expect, haveResource } from '@aws-cdk/assert';
1+
import { countResources, expect, haveResource } from '@aws-cdk/assert';
22
import ec2 = require('@aws-cdk/aws-ec2');
33
import { InstanceType } from '@aws-cdk/aws-ec2';
44
import cloudmap = require('@aws-cdk/aws-servicediscovery');
@@ -1099,6 +1099,33 @@ export = {
10991099
test.done();
11001100
},
11011101

1102+
'imported cluster with imported security groups honors allowAllOutbound'(test: Test) {
1103+
// GIVEN
1104+
const stack = new cdk.Stack();
1105+
const vpc = new ec2.Vpc(stack, 'Vpc');
1106+
1107+
const importedSg1 = ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG1', 'sg-1', { allowAllOutbound: false });
1108+
const importedSg2 = ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG2', 'sg-2');
1109+
1110+
const cluster = ecs.Cluster.fromClusterAttributes(stack, 'Cluster', {
1111+
clusterName: 'cluster-name',
1112+
securityGroups: [importedSg1, importedSg2],
1113+
vpc,
1114+
});
1115+
1116+
// WHEN
1117+
cluster.connections.allowToAnyIpv4(ec2.Port.tcp(443));
1118+
1119+
// THEN
1120+
expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', {
1121+
GroupId: 'sg-1'
1122+
}));
1123+
1124+
expect(stack).to(countResources('AWS::EC2::SecurityGroupEgress', 1));
1125+
1126+
test.done();
1127+
},
1128+
11021129
"Metric"(test: Test) {
11031130
// GIVEN
11041131
const stack = new cdk.Stack();

packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,20 +327,30 @@ export interface ApplicationListenerAttributes {
327327

328328
/**
329329
* Security group ID of the load balancer this listener is associated with
330+
*
331+
* @deprecated use `securityGroup` instead
332+
*/
333+
readonly securityGroupId?: string;
334+
335+
/**
336+
* Security group of the load balancer this listener is associated with
330337
*/
331-
readonly securityGroupId: string;
338+
readonly securityGroup?: ec2.ISecurityGroup;
332339

333340
/**
334341
* The default port on which this listener is listening
335342
*/
336343
readonly defaultPort?: number;
337344

338345
/**
339-
* Whether the security group allows all outbound traffic or not
346+
* Whether the imported security group allows all outbound traffic or not when
347+
* imported using `securityGroupId`
340348
*
341349
* Unless set to `false`, no egress rules will be added to the security group.
342350
*
343351
* @default true
352+
*
353+
* @deprecated use `securityGroup` instead
344354
*/
345355
readonly securityGroupAllowsAllOutbound?: boolean;
346356
}
@@ -360,10 +370,19 @@ class ImportedApplicationListener extends Resource implements IApplicationListen
360370

361371
const defaultPort = props.defaultPort !== undefined ? ec2.Port.tcp(props.defaultPort) : undefined;
362372

363-
this.connections = new ec2.Connections({
364-
securityGroups: [ec2.SecurityGroup.fromSecurityGroupId(this, 'SecurityGroup', props.securityGroupId, {
373+
let securityGroup: ec2.ISecurityGroup;
374+
if (props.securityGroup) {
375+
securityGroup = props.securityGroup;
376+
} else if (props.securityGroupId) {
377+
securityGroup = ec2.SecurityGroup.fromSecurityGroupId(scope, 'SecurityGroup', props.securityGroupId, {
365378
allowAllOutbound: props.securityGroupAllowsAllOutbound
366-
})],
379+
});
380+
} else {
381+
throw new Error('Either `securityGroup` or `securityGroupId` must be specified to import an application listener.');
382+
}
383+
384+
this.connections = new ec2.Connections({
385+
securityGroups: [securityGroup],
367386
defaultPort,
368387
});
369388
}

packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,29 @@ export = {
624624
}), /`targetGroups`.*`fixedResponse`/);
625625

626626
test.done();
627-
}
627+
},
628+
629+
'Imported listener with imported security group and allowAllOutbound set to false'(test: Test) {
630+
// GIVEN
631+
const stack = new cdk.Stack();
632+
const listener = elbv2.ApplicationListener.fromApplicationListenerAttributes(stack, 'Listener', {
633+
listenerArn: 'listener-arn',
634+
defaultPort: 443,
635+
securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'security-group-id', {
636+
allowAllOutbound: false,
637+
}),
638+
});
639+
640+
// WHEN
641+
listener.connections.allowToAnyIpv4(ec2.Port.tcp(443));
642+
643+
// THEN
644+
expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', {
645+
GroupId: 'security-group-id'
646+
}));
647+
648+
test.done();
649+
},
628650
};
629651

630652
class ResourceWithLBDependency extends cdk.CfnResource {

packages/@aws-cdk/aws-lambda/lib/function-base.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,22 @@ export interface FunctionAttributes {
114114
readonly role?: iam.IRole;
115115

116116
/**
117-
* Id of the securityGroup for this Lambda, if in a VPC.
117+
* Id of the security group of this Lambda, if in a VPC.
118118
*
119119
* This needs to be given in order to support allowing connections
120120
* to this Lambda.
121+
*
122+
* @deprecated use `securityGroup` instead
121123
*/
122124
readonly securityGroupId?: string;
125+
126+
/**
127+
* The security group of this Lambda, if in a VPC.
128+
*
129+
* This needs to be given in order to support allowing connections
130+
* to this Lambda.
131+
*/
132+
readonly securityGroup?: ec2.ISecurityGroup;
123133
}
124134

125135
export abstract class FunctionBase extends Resource implements IFunction {

packages/@aws-cdk/aws-lambda/lib/function.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,13 @@ export class Function extends FunctionBase {
275275

276276
this.grantPrincipal = role || new iam.UnknownPrincipal({ resource: this } );
277277

278-
if (attrs.securityGroupId) {
278+
if (attrs.securityGroup) {
279279
this._connections = new ec2.Connections({
280-
securityGroups: [
281-
ec2.SecurityGroup.fromSecurityGroupId(this, 'SecurityGroup', attrs.securityGroupId)
282-
]
280+
securityGroups: [attrs.securityGroup]
281+
});
282+
} else if (attrs.securityGroupId) {
283+
this._connections = new ec2.Connections({
284+
securityGroups: [ec2.SecurityGroup.fromSecurityGroupId(scope, 'SecurityGroup', attrs.securityGroupId)]
283285
});
284286
}
285287
}

packages/@aws-cdk/aws-lambda/test/test.lambda.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { expect, haveResource, MatchStyle, ResourcePart } from '@aws-cdk/assert';
2+
import ec2 = require('@aws-cdk/aws-ec2');
23
import iam = require('@aws-cdk/aws-iam');
34
import logs = require('@aws-cdk/aws-logs');
45
import sqs = require('@aws-cdk/aws-sqs');
@@ -1372,7 +1373,29 @@ export = {
13721373
}));
13731374

13741375
test.done();
1375-
}
1376+
},
1377+
1378+
'imported lambda with imported security group and allowAllOutbound set to false'(test: Test) {
1379+
// GIVEN
1380+
const stack = new cdk.Stack();
1381+
1382+
const fn = lambda.Function.fromFunctionAttributes(stack, 'fn', {
1383+
functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:my-function',
1384+
securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', {
1385+
allowAllOutbound: false,
1386+
}),
1387+
});
1388+
1389+
// WHEN
1390+
fn.connections.allowToAnyIpv4(ec2.Port.tcp(443));
1391+
1392+
// THEN
1393+
expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', {
1394+
GroupId: 'sg-123456789',
1395+
}));
1396+
1397+
test.done();
1398+
}
13761399
};
13771400

13781401
function newTestLambda(scope: cdk.Construct) {

packages/@aws-cdk/aws-rds/lib/cluster-ref.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ export interface DatabaseClusterAttributes {
5050
readonly port: number;
5151

5252
/**
53-
* The security group for this database cluster
53+
* The security group of the database cluster
5454
*/
55-
readonly securityGroupId: string;
55+
readonly securityGroup: ec2.ISecurityGroup;
5656

5757
/**
5858
* Identifier for the cluster

packages/@aws-cdk/aws-rds/lib/cluster.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ export class DatabaseCluster extends DatabaseClusterBase {
192192
class Import extends DatabaseClusterBase implements IDatabaseCluster {
193193
public readonly defaultPort = ec2.Port.tcp(attrs.port);
194194
public readonly connections = new ec2.Connections({
195-
securityGroups: [ec2.SecurityGroup.fromSecurityGroupId(this, 'SecurityGroup', attrs.securityGroupId)],
195+
securityGroups: [attrs.securityGroup],
196196
defaultPort: this.defaultPort
197197
});
198198
public readonly clusterIdentifier = attrs.clusterIdentifier;
199199
public readonly instanceIdentifiers: string[] = [];
200200
public readonly clusterEndpoint = new Endpoint(attrs.clusterEndpointAddress, attrs.port);
201201
public readonly clusterReadEndpoint = new Endpoint(attrs.readerEndpointAddress, attrs.port);
202202
public readonly instanceEndpoints = attrs.instanceEndpointAddresses.map(a => new Endpoint(a, attrs.port));
203-
public readonly securityGroupId = attrs.securityGroupId;
203+
public readonly securityGroupId = attrs.securityGroup.securityGroupId;
204204
}
205205

206206
return new Import(scope, id);

packages/@aws-cdk/aws-rds/lib/instance.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ export interface DatabaseInstanceAttributes {
7676
readonly port: number;
7777

7878
/**
79-
* The security group identifier of the instance.
79+
* The security group of the instance.
8080
*/
81-
readonly securityGroupId: string;
81+
readonly securityGroup: ec2.ISecurityGroup;
8282
}
8383

8484
/**
@@ -92,14 +92,14 @@ export abstract class DatabaseInstanceBase extends Resource implements IDatabase
9292
class Import extends DatabaseInstanceBase implements IDatabaseInstance {
9393
public readonly defaultPort = ec2.Port.tcp(attrs.port);
9494
public readonly connections = new ec2.Connections({
95-
securityGroups: [ec2.SecurityGroup.fromSecurityGroupId(this, 'SecurityGroup', attrs.securityGroupId)],
95+
securityGroups: [attrs.securityGroup],
9696
defaultPort: this.defaultPort
9797
});
9898
public readonly instanceIdentifier = attrs.instanceIdentifier;
9999
public readonly dbInstanceEndpointAddress = attrs.instanceEndpointAddress;
100100
public readonly dbInstanceEndpointPort = attrs.port.toString();
101101
public readonly instanceEndpoint = new Endpoint(attrs.instanceEndpointAddress, attrs.port);
102-
public readonly securityGroupId = attrs.securityGroupId;
102+
public readonly securityGroupId = attrs.securityGroup.securityGroupId;
103103
}
104104

105105
return new Import(scope, id);

0 commit comments

Comments
 (0)