Skip to content

Commit

Permalink
feat(rds): allow using existing security groups for new instance (aws…
Browse files Browse the repository at this point in the history
…#4495)

* feat(rds): allow using existing security group for instance

Closes aws#2949

* securityGroups

* s

* avoid duplication

* remove useless protected securityGroups
  • Loading branch information
jogold authored and mergify[bot] committed Oct 24, 2019
1 parent 8484114 commit ef1ce5e
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 36 deletions.
53 changes: 19 additions & 34 deletions packages/@aws-cdk/aws-rds/lib/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import kms = require('@aws-cdk/aws-kms');
import lambda = require('@aws-cdk/aws-lambda');
import logs = require('@aws-cdk/aws-logs');
import secretsmanager = require('@aws-cdk/aws-secretsmanager');
import { Construct, Duration, IResource, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core';
import { Construct, Duration, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core';
import { DatabaseSecret } from './database-secret';
import { Endpoint } from './endpoint';
import { IOptionGroup } from './option-group';
Expand Down Expand Up @@ -44,11 +44,6 @@ export interface IDatabaseInstance extends IResource, ec2.IConnectable, secretsm
*/
readonly instanceEndpoint: Endpoint;

/**
* The security group identifier of the instance.
*/
readonly securityGroupId: string;

/**
* Defines a CloudWatch event rule which triggers for instance events. Use
* `rule.addEventPattern(pattern)` to specify a filter.
Expand Down Expand Up @@ -76,9 +71,9 @@ export interface DatabaseInstanceAttributes {
readonly port: number;

/**
* The security group of the instance.
* The security groups of the instance.
*/
readonly securityGroup: ec2.ISecurityGroup;
readonly securityGroups: ec2.ISecurityGroup[];
}

/**
Expand All @@ -92,14 +87,13 @@ export abstract class DatabaseInstanceBase extends Resource implements IDatabase
class Import extends DatabaseInstanceBase implements IDatabaseInstance {
public readonly defaultPort = ec2.Port.tcp(attrs.port);
public readonly connections = new ec2.Connections({
securityGroups: [attrs.securityGroup],
securityGroups: attrs.securityGroups,
defaultPort: this.defaultPort
});
public readonly instanceIdentifier = attrs.instanceIdentifier;
public readonly dbInstanceEndpointAddress = attrs.instanceEndpointAddress;
public readonly dbInstanceEndpointPort = attrs.port.toString();
public readonly instanceEndpoint = new Endpoint(attrs.instanceEndpointAddress, attrs.port);
public readonly securityGroupId = attrs.securityGroup.securityGroupId;
}

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

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

/**
* The security groups to assign to the DB instance.
*
* @default - a new security group is created
*/
readonly securityGroups?: ec2.ISecurityGroup[];

/**
* The port for the instance.
*
Expand Down Expand Up @@ -469,12 +469,11 @@ export interface DatabaseInstanceNewProps {
* A new database instance.
*/
abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IDatabaseInstance {
public readonly securityGroupId: string;
public readonly vpc: ec2.IVpc;
public readonly connections: ec2.Connections;

protected readonly vpcPlacement?: ec2.SubnetSelection;
protected readonly newCfnProps: CfnDBInstanceProps;
protected readonly securityGroup: ec2.SecurityGroup;

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

this.securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', {
const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', {
description: `Security group for ${this.node.id} database`,
vpc: props.vpc
})];

this.connections = new ec2.Connections({
securityGroups,
defaultPort: ec2.Port.tcp(Lazy.numberValue({ produce: () => this.instanceEndpoint.port }))
});
this.securityGroupId = this.securityGroup.securityGroupId;

let monitoringRole;
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
Expand Down Expand Up @@ -545,7 +548,7 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
processorFeatures: props.processorFeatures && renderProcessorFeatures(props.processorFeatures),
publiclyAccessible: props.vpcPlacement && props.vpcPlacement.subnetType === ec2.SubnetType.PUBLIC,
storageType,
vpcSecurityGroups: [this.securityGroupId]
vpcSecurityGroups: securityGroups.map(s => s.securityGroupId)
};
}

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

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

this.connections = new ec2.Connections({
securityGroups: [this.securityGroup],
defaultPort: ec2.Port.tcp(this.instanceEndpoint.port)
});

this.setLogRetention();
}
}
Expand Down Expand Up @@ -816,7 +813,6 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme
public readonly dbInstanceEndpointAddress: string;
public readonly dbInstanceEndpointPort: string;
public readonly instanceEndpoint: Endpoint;
public readonly connections: ec2.Connections;
public readonly secret?: secretsmanager.ISecret;

constructor(scope: Construct, id: string, props: DatabaseInstanceFromSnapshotProps) {
Expand Down Expand Up @@ -863,11 +859,6 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme
});
}

this.connections = new ec2.Connections({
securityGroups: [this.securityGroup],
defaultPort: ec2.Port.tcp(this.instanceEndpoint.port)
});

this.setLogRetention();
}
}
Expand Down Expand Up @@ -910,7 +901,6 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements
public readonly dbInstanceEndpointAddress: string;
public readonly dbInstanceEndpointPort: string;
public readonly instanceEndpoint: Endpoint;
public readonly connections: ec2.Connections;

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

this.connections = new ec2.Connections({
securityGroups: [this.securityGroup],
defaultPort: ec2.Port.tcp(this.instanceEndpoint.port)
});

this.setLogRetention();
}
}
Expand Down
46 changes: 44 additions & 2 deletions packages/@aws-cdk/aws-rds/test/test.instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,9 +499,9 @@ export = {
instanceEndpointAddress: 'address',
instanceIdentifier: 'identifier',
port: 3306,
securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', {
securityGroups: [ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', {
allowAllOutbound: false
}),
})],
});

// WHEN
Expand Down Expand Up @@ -547,4 +547,46 @@ export = {

test.done();
},

'create an instance with an existing security group'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'VPC');
const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', {
allowAllOutbound: false
});

// WHEN
const instance = new rds.DatabaseInstance(stack, 'Instance', {
engine: rds.DatabaseInstanceEngine.MYSQL,
instanceClass: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
masterUsername: 'admin',
vpc,
securityGroups: [securityGroup],
});
instance.connections.allowDefaultPortFromAnyIpv4();

// THEN
expect(stack).to(haveResource('AWS::RDS::DBInstance', {
VPCSecurityGroups: ['sg-123456789']
}));

expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', {
FromPort: {
'Fn::GetAtt': [
'InstanceC1063A87',
'Endpoint.Port'
]
},
GroupId: 'sg-123456789',
ToPort: {
'Fn::GetAtt': [
'InstanceC1063A87',
'Endpoint.Port'
]
}
}));

test.done();
}
};

0 comments on commit ef1ce5e

Please sign in to comment.