Skip to content

Commit ef1ce5e

Browse files
jogoldmergify[bot]
authored andcommitted
feat(rds): allow using existing security groups for new instance (#4495)
* feat(rds): allow using existing security group for instance Closes #2949 * securityGroups * s * avoid duplication * remove useless protected securityGroups
1 parent 8484114 commit ef1ce5e

File tree

2 files changed

+63
-36
lines changed

2 files changed

+63
-36
lines changed

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

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import kms = require('@aws-cdk/aws-kms');
55
import lambda = require('@aws-cdk/aws-lambda');
66
import logs = require('@aws-cdk/aws-logs');
77
import secretsmanager = require('@aws-cdk/aws-secretsmanager');
8-
import { Construct, Duration, IResource, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core';
8+
import { Construct, Duration, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core';
99
import { DatabaseSecret } from './database-secret';
1010
import { Endpoint } from './endpoint';
1111
import { IOptionGroup } from './option-group';
@@ -44,11 +44,6 @@ export interface IDatabaseInstance extends IResource, ec2.IConnectable, secretsm
4444
*/
4545
readonly instanceEndpoint: Endpoint;
4646

47-
/**
48-
* The security group identifier of the instance.
49-
*/
50-
readonly securityGroupId: string;
51-
5247
/**
5348
* Defines a CloudWatch event rule which triggers for instance events. Use
5449
* `rule.addEventPattern(pattern)` to specify a filter.
@@ -76,9 +71,9 @@ export interface DatabaseInstanceAttributes {
7671
readonly port: number;
7772

7873
/**
79-
* The security group of the instance.
74+
* The security groups of the instance.
8075
*/
81-
readonly securityGroup: ec2.ISecurityGroup;
76+
readonly securityGroups: ec2.ISecurityGroup[];
8277
}
8378

8479
/**
@@ -92,14 +87,13 @@ export abstract class DatabaseInstanceBase extends Resource implements IDatabase
9287
class Import extends DatabaseInstanceBase implements IDatabaseInstance {
9388
public readonly defaultPort = ec2.Port.tcp(attrs.port);
9489
public readonly connections = new ec2.Connections({
95-
securityGroups: [attrs.securityGroup],
90+
securityGroups: attrs.securityGroups,
9691
defaultPort: this.defaultPort
9792
});
9893
public readonly instanceIdentifier = attrs.instanceIdentifier;
9994
public readonly dbInstanceEndpointAddress = attrs.instanceEndpointAddress;
10095
public readonly dbInstanceEndpointPort = attrs.port.toString();
10196
public readonly instanceEndpoint = new Endpoint(attrs.instanceEndpointAddress, attrs.port);
102-
public readonly securityGroupId = attrs.securityGroup.securityGroupId;
10397
}
10498

10599
return new Import(scope, id);
@@ -110,7 +104,6 @@ export abstract class DatabaseInstanceBase extends Resource implements IDatabase
110104
public abstract readonly dbInstanceEndpointPort: string;
111105
public abstract readonly instanceEndpoint: Endpoint;
112106
public abstract readonly connections: ec2.Connections;
113-
public abstract readonly securityGroupId: string;
114107

115108
/**
116109
* Defines a CloudWatch event rule which triggers for instance events. Use
@@ -305,6 +298,13 @@ export interface DatabaseInstanceNewProps {
305298
*/
306299
readonly vpcPlacement?: ec2.SubnetSelection;
307300

301+
/**
302+
* The security groups to assign to the DB instance.
303+
*
304+
* @default - a new security group is created
305+
*/
306+
readonly securityGroups?: ec2.ISecurityGroup[];
307+
308308
/**
309309
* The port for the instance.
310310
*
@@ -469,12 +469,11 @@ export interface DatabaseInstanceNewProps {
469469
* A new database instance.
470470
*/
471471
abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IDatabaseInstance {
472-
public readonly securityGroupId: string;
473472
public readonly vpc: ec2.IVpc;
473+
public readonly connections: ec2.Connections;
474474

475475
protected readonly vpcPlacement?: ec2.SubnetSelection;
476476
protected readonly newCfnProps: CfnDBInstanceProps;
477-
protected readonly securityGroup: ec2.SecurityGroup;
478477

479478
private readonly cloudwatchLogsExports?: string[];
480479
private readonly cloudwatchLogsRetention?: logs.RetentionDays;
@@ -493,11 +492,15 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
493492
subnetIds
494493
});
495494

496-
this.securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', {
495+
const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', {
497496
description: `Security group for ${this.node.id} database`,
498497
vpc: props.vpc
498+
})];
499+
500+
this.connections = new ec2.Connections({
501+
securityGroups,
502+
defaultPort: ec2.Port.tcp(Lazy.numberValue({ produce: () => this.instanceEndpoint.port }))
499503
});
500-
this.securityGroupId = this.securityGroup.securityGroupId;
501504

502505
let monitoringRole;
503506
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
@@ -545,7 +548,7 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
545548
processorFeatures: props.processorFeatures && renderProcessorFeatures(props.processorFeatures),
546549
publiclyAccessible: props.vpcPlacement && props.vpcPlacement.subnetType === ec2.SubnetType.PUBLIC,
547550
storageType,
548-
vpcSecurityGroups: [this.securityGroupId]
551+
vpcSecurityGroups: securityGroups.map(s => s.securityGroupId)
549552
};
550553
}
551554

@@ -724,7 +727,6 @@ export class DatabaseInstance extends DatabaseInstanceSource implements IDatabas
724727
public readonly dbInstanceEndpointAddress: string;
725728
public readonly dbInstanceEndpointPort: string;
726729
public readonly instanceEndpoint: Endpoint;
727-
public readonly connections: ec2.Connections;
728730
public readonly secret?: secretsmanager.ISecret;
729731

730732
constructor(scope: Construct, id: string, props: DatabaseInstanceProps) {
@@ -769,11 +771,6 @@ export class DatabaseInstance extends DatabaseInstanceSource implements IDatabas
769771
});
770772
}
771773

772-
this.connections = new ec2.Connections({
773-
securityGroups: [this.securityGroup],
774-
defaultPort: ec2.Port.tcp(this.instanceEndpoint.port)
775-
});
776-
777774
this.setLogRetention();
778775
}
779776
}
@@ -816,7 +813,6 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme
816813
public readonly dbInstanceEndpointAddress: string;
817814
public readonly dbInstanceEndpointPort: string;
818815
public readonly instanceEndpoint: Endpoint;
819-
public readonly connections: ec2.Connections;
820816
public readonly secret?: secretsmanager.ISecret;
821817

822818
constructor(scope: Construct, id: string, props: DatabaseInstanceFromSnapshotProps) {
@@ -863,11 +859,6 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme
863859
});
864860
}
865861

866-
this.connections = new ec2.Connections({
867-
securityGroups: [this.securityGroup],
868-
defaultPort: ec2.Port.tcp(this.instanceEndpoint.port)
869-
});
870-
871862
this.setLogRetention();
872863
}
873864
}
@@ -910,7 +901,6 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements
910901
public readonly dbInstanceEndpointAddress: string;
911902
public readonly dbInstanceEndpointPort: string;
912903
public readonly instanceEndpoint: Endpoint;
913-
public readonly connections: ec2.Connections;
914904

915905
constructor(scope: Construct, id: string, props: DatabaseInstanceReadReplicaProps) {
916906
super(scope, id, props);
@@ -934,11 +924,6 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements
934924
applyToUpdateReplacePolicy: true
935925
});
936926

937-
this.connections = new ec2.Connections({
938-
securityGroups: [this.securityGroup],
939-
defaultPort: ec2.Port.tcp(this.instanceEndpoint.port)
940-
});
941-
942927
this.setLogRetention();
943928
}
944929
}

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,9 @@ export = {
499499
instanceEndpointAddress: 'address',
500500
instanceIdentifier: 'identifier',
501501
port: 3306,
502-
securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', {
502+
securityGroups: [ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', {
503503
allowAllOutbound: false
504-
}),
504+
})],
505505
});
506506

507507
// WHEN
@@ -547,4 +547,46 @@ export = {
547547

548548
test.done();
549549
},
550+
551+
'create an instance with an existing security group'(test: Test) {
552+
// GIVEN
553+
const stack = new cdk.Stack();
554+
const vpc = new ec2.Vpc(stack, 'VPC');
555+
const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', {
556+
allowAllOutbound: false
557+
});
558+
559+
// WHEN
560+
const instance = new rds.DatabaseInstance(stack, 'Instance', {
561+
engine: rds.DatabaseInstanceEngine.MYSQL,
562+
instanceClass: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
563+
masterUsername: 'admin',
564+
vpc,
565+
securityGroups: [securityGroup],
566+
});
567+
instance.connections.allowDefaultPortFromAnyIpv4();
568+
569+
// THEN
570+
expect(stack).to(haveResource('AWS::RDS::DBInstance', {
571+
VPCSecurityGroups: ['sg-123456789']
572+
}));
573+
574+
expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', {
575+
FromPort: {
576+
'Fn::GetAtt': [
577+
'InstanceC1063A87',
578+
'Endpoint.Port'
579+
]
580+
},
581+
GroupId: 'sg-123456789',
582+
ToPort: {
583+
'Fn::GetAtt': [
584+
'InstanceC1063A87',
585+
'Endpoint.Port'
586+
]
587+
}
588+
}));
589+
590+
test.done();
591+
}
550592
};

0 commit comments

Comments
 (0)