Skip to content

Commit

Permalink
feat(rds): add support for joining instance to domain
Browse files Browse the repository at this point in the history
Added new properties to be able to join instance to a domain.

closes aws#9869
  • Loading branch information
ctaylor-osv committed Aug 24, 2020
1 parent 1c9b733 commit bfb0c6e
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 1 deletion.
34 changes: 34 additions & 0 deletions packages/@aws-cdk/aws-rds/lib/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,21 @@ export interface DatabaseInstanceNewProps {
* @default - No autoscaling of RDS instance
*/
readonly maxAllocatedStorage?: number;

/**
* The Active Directory directory ID to create the DB instance in.
*
* @default - Do not join domain
*/
readonly domain?: string;

/**
* The IAM role to be used when making API calls to the Directory Service. The role needs the AWS-managed policy
* AmazonRDSDirectoryServiceAccess or equivalent.
*
* @default - The role will be created for you if {@link DatabaseInstanceNewProps#domain} is specified
*/
readonly domainRole?: iam.IRole;
}

/**
Expand All @@ -514,6 +529,9 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
private readonly cloudwatchLogsRetention?: logs.RetentionDays;
private readonly cloudwatchLogsRetentionRole?: iam.IRole;

private readonly domainId?: string;
private readonly domainRole?: iam.IRole;

protected enableIamAuthentication?: boolean;

constructor(scope: Construct, id: string, props: DatabaseInstanceNewProps) {
Expand Down Expand Up @@ -556,6 +574,16 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
this.cloudwatchLogsRetentionRole = props.cloudwatchLogsRetentionRole;
this.enableIamAuthentication = props.iamAuthentication;

if (props.domain) {
this.domainId = props.domain;
this.domainRole = props.domainRole || new iam.Role(this, 'RDSDirectoryServiceRole', {
assumedBy: new iam.ServicePrincipal('rds.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSDirectoryServiceAccess'),
],
});
}

this.newCfnProps = {
autoMinorVersionUpgrade: props.autoMinorVersionUpgrade,
availabilityZone: props.multiAz ? undefined : props.availabilityZone,
Expand Down Expand Up @@ -588,6 +616,8 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData
storageType,
vpcSecurityGroups: securityGroups.map(s => s.securityGroupId),
maxAllocatedStorage: props.maxAllocatedStorage,
domain: this.domainId,
domainIamRoleName: this.domainRole?.roleName,
};
}

Expand Down Expand Up @@ -698,6 +728,10 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa
this.singleUserRotationApplication = props.engine.singleUserRotationApplication;
this.multiUserRotationApplication = props.engine.multiUserRotationApplication;

if (props.domain && !props.engine.engineType.match(/^(mysql|postgres|oracle|sqlserver)/)) {
throw new Error('Cannot specify `domain` unless engine is MySQL, Oracle, PostgreSQL, or SQL Server.');
}

props.engine.bindToInstance(this, props);
this.instanceType = props.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE);

Expand Down
103 changes: 102 additions & 1 deletion packages/@aws-cdk/aws-rds/test/test.instance.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ABSENT, countResources, expect, haveResource, ResourcePart, haveResourceLike } from '@aws-cdk/assert';
import { ABSENT, countResources, expect, haveResource, ResourcePart, haveResourceLike, anything } from '@aws-cdk/assert';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as targets from '@aws-cdk/aws-events-targets';
import { ManagedPolicy, Role, ServicePrincipal, AccountPrincipal } from '@aws-cdk/aws-iam';
Expand Down Expand Up @@ -757,4 +757,105 @@ export = {
test.done();
},

'domain - sets domain property'(test: Test) {
const domain = 'd-90670a8d36';

// WHEN
new rds.DatabaseInstance(stack, 'Instance', {
engine: rds.DatabaseInstanceEngine.sqlServerWeb({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }),
vpc,
masterUsername: 'admin',
domain: domain,
});

// THEN
expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', {
Domain: domain,
}));

test.done();
},

'domain - uses role if provided'(test: Test) {
const domain = 'd-90670a8d36';

// WHEN
const role = new Role(stack, 'DomainRole', { assumedBy: new ServicePrincipal('rds.amazonaws.com') });
new rds.DatabaseInstance(stack, 'Instance', {
engine: rds.DatabaseInstanceEngine.sqlServerWeb({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }),
vpc,
masterUsername: 'admin',
domain: domain,
domainRole: role,
});

// THEN
expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', {
Domain: domain,
DomainIAMRoleName: stack.resolve(role.roleName),
}));

test.done();
},

'domain - creates role if not provided'(test: Test) {
const domain = 'd-90670a8d36';

// WHEN
new rds.DatabaseInstance(stack, 'Instance', {
engine: rds.DatabaseInstanceEngine.sqlServerWeb({ version: rds.SqlServerEngineVersion.VER_14_00_3192_2_V1 }),
vpc,
masterUsername: 'admin',
domain: domain,
});

// THEN
expect(stack).to(haveResourceLike('AWS::RDS::DBInstance', {
Domain: domain,
DomainIAMRoleName: anything(),
}));

expect(stack).to(haveResource('AWS::IAM::Role', {
AssumeRolePolicyDocument: {
Statement: [
{
Action: 'sts:AssumeRole',
Effect: 'Allow',
Principal: {
Service: 'rds.amazonaws.com',
},
},
],
Version: '2012-10-17',
},
ManagedPolicyArns: [
{
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':iam::aws:policy/service-role/AmazonRDSDirectoryServiceAccess',
],
],
},
],
}));

test.done();
},

'domain - throws if incompatible engine type'(test: Test) {
const domain = 'd-90670a8d36';
test.throws(() => new rds.DatabaseInstance(stack, 'Instance', {
engine: rds.DatabaseInstanceEngine.mariaDb({ version: rds.MariaDbEngineVersion.VER_10_4_8 }),
vpc,
masterUsername: 'admin',
domain: domain,
}), 'Cannot specify `domain` unless engine is MySQL, Oracle, PostgreSQL, or SQL Server.');

test.done();
},
};

0 comments on commit bfb0c6e

Please sign in to comment.