Skip to content

Commit

Permalink
feat(deadline): add security group configuration for Repository and R…
Browse files Browse the repository at this point in the history
…enderQueue
  • Loading branch information
jericht committed Feb 25, 2021
1 parent e6bb60d commit 4fd6663
Show file tree
Hide file tree
Showing 9 changed files with 452 additions and 6 deletions.
13 changes: 13 additions & 0 deletions packages/aws-rfdk/lib/core/lib/mongodb-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ export interface IMongoDb extends IConnectable, IConstruct {
* The version of MongoDB that is running on this instance.
*/
readonly version: MongoDbVersion;

/**
* Adds security groups to the database.
* @param securityGroups The security groups to add.
*/
addSecurityGroup(...securityGroups: ISecurityGroup[]): void;
}

/**
Expand Down Expand Up @@ -487,6 +493,13 @@ export class MongoDbInstance extends Construct implements IMongoDb, IGrantable {
tagConstruct(this);
}

/**
* @inheritdoc
*/
public addSecurityGroup(...securityGroups: ISecurityGroup[]): void {
securityGroups?.forEach(securityGroup => this.server.autoscalingGroup.addSecurityGroup(securityGroup));
}

/**
* Adds UserData commands to install & configure the CloudWatch Agent onto the instance.
*
Expand Down
25 changes: 25 additions & 0 deletions packages/aws-rfdk/lib/core/test/mongodb-instance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,31 @@ describe('Test MongoDbInstance', () => {
}));
});

test('adds security group', () => {
// GIVEN
const securityGroup = new SecurityGroup(stack, 'NewSecurityGroup', {
vpc,
});
const instance = new MongoDbInstance(stack, 'MongoDbInstance', {
mongoDb: {
version,
dnsZone,
hostname,
serverCertificate: serverCert,
userSsplAcceptance,
},
vpc,
});

// WHEN
instance.addSecurityGroup(securityGroup);

// THEN
cdkExpect(stack).to(haveResourceLike('AWS::AutoScaling::LaunchConfiguration', {
SecurityGroups: arrayWith(stack.resolve(securityGroup.securityGroupId)),
}));
});

testConstructTags({
constructName: 'MongoDbInstance',
createConstruct: () => {
Expand Down
52 changes: 52 additions & 0 deletions packages/aws-rfdk/lib/deadline/lib/database-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import * as path from 'path';
import {
CfnDBCluster,
CfnDBInstance,
DatabaseCluster,
IDatabaseCluster,
} from '@aws-cdk/aws-docdb';
import {
IConnectable,
ISecurityGroup,
OperatingSystemType,
Port,
} from '@aws-cdk/aws-ec2';
Expand Down Expand Up @@ -155,6 +157,13 @@ export abstract class DatabaseConnection {
* @param child The child to make dependent upon this database.
*/
public abstract addChildDependency(child: IConstruct): void;

/**
* Adds a security group to the database.
*
* @param securityGroups The security group to add.
*/
public abstract addSecurityGroup(...securityGroups: ISecurityGroup[]): void;
}

/**
Expand Down Expand Up @@ -267,6 +276,42 @@ class DocDBDatabaseConnection extends DatabaseConnection {
}
}

/**
* @inheritdoc
*/
public addSecurityGroup(...securityGroups: ISecurityGroup[]): void {
let added = false;
const errorReasons: string[] = [];
if (this.props.database instanceof DatabaseCluster) {
const resource = (this.props.database as DatabaseCluster).node.tryFindChild('Resource');

// TODO: Replace this code with the addSecurityGroup method of DatabaseCluster once this PR is merged:
// https://github.com/aws/aws-cdk/pull/13290
if (resource instanceof CfnDBCluster) {
const cfnCluster = resource as CfnDBCluster;
const securityGroupIds = securityGroups.map(sg => sg.securityGroupId);

if (cfnCluster.vpcSecurityGroupIds === undefined) {
cfnCluster.vpcSecurityGroupIds = securityGroupIds;
} else {
cfnCluster.vpcSecurityGroupIds.push(...securityGroupIds);
}
added = true;
} else {
errorReasons.push('The internal implementation of AWS CDK\'s DocumentDB cluster construct has changed.');
}
} else {
errorReasons.push('The "database" property passed to this class is not an instance of AWS CDK\'s DocumentDB cluster construct.');
}

if (!added) {
Annotations.of(this.props.database).addWarning(
`Failed to add the following security groups to ${this.props.database.node.id}: ${securityGroups.map(sg => sg.node.id).join(', ')}. ` +
errorReasons.join(' '),
);
}
}

/**
* Deadline is only compatible with MongoDB 3.6. This function attempts to determine whether
* the given DocDB version is compatible.
Expand Down Expand Up @@ -375,6 +420,13 @@ class MongoDbInstanceDatabaseConnection extends DatabaseConnection {
}
}

/**
* @inheritdoc
*/
public addSecurityGroup(...securityGroups: ISecurityGroup[]): void {
this.props.database.addSecurityGroup(...securityGroups);
}

/**
* Download the client PKCS#12 certificate for authenticating to the MongoDB, and place it into
* the path defined by: DB_CERT_LOCATION
Expand Down
20 changes: 20 additions & 0 deletions packages/aws-rfdk/lib/deadline/lib/render-queue-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '@aws-cdk/aws-certificatemanager';
import {
InstanceType,
ISecurityGroup,
IVpc,
SubnetSelection,
} from '@aws-cdk/aws-ec2';
Expand Down Expand Up @@ -211,6 +212,20 @@ export interface RenderQueueAccessLogProps {
readonly prefix?: string;
}

/**
* Options for security groups of the Render Queue.
*/
export interface RenderQueueSecurityGroupsOptions {
/**
* The security group for the backend components of the Render Queue, which consists of the AutoScalingGroup for the Deadline RCS.
*/
readonly backend?: ISecurityGroup;
/**
* The security group for the frontend of the Render Queue, which is its load balancer.
*/
readonly frontend?: ISecurityGroup;
}

/**
* Properties for the Render Queue
*/
Expand Down Expand Up @@ -312,6 +327,11 @@ export interface RenderQueueProps {
* @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection
*/
readonly deletionProtection?: boolean;

/**
* Options to add additional security groups to the Render Queue.
*/
readonly securityGroupsOptions?: RenderQueueSecurityGroupsOptions;
}

/**
Expand Down
20 changes: 20 additions & 0 deletions packages/aws-rfdk/lib/deadline/lib/render-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Connections,
IConnectable,
InstanceType,
ISecurityGroup,
Port,
SubnetType,
} from '@aws-cdk/aws-ec2';
Expand Down Expand Up @@ -304,6 +305,8 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
volume: BlockDeviceVolume.ebs(30, { encrypted: true }),
}],
updateType: UpdateType.ROLLING_UPDATE,
// @ts-ignore
securityGroup: props.securityGroupsOptions?.backend,
});

/**
Expand Down Expand Up @@ -347,6 +350,7 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
vpcSubnets: props.vpcSubnetsAlb ?? { subnetType: SubnetType.PRIVATE, onePerAz: true },
internetFacing: false,
deletionProtection: props.deletionProtection ?? true,
securityGroup: props.securityGroupsOptions?.frontend,
});

this.pattern = new ApplicationLoadBalancedEc2Service(this, 'AlbEc2ServicePattern', {
Expand Down Expand Up @@ -519,6 +523,22 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
child.node.addDependency(this.taskDefinition);
}

/**
* Adds security groups to the frontend of the Render Queue, which is its load balancer.
* @param securityGroups The security groups to add.
*/
public addFrontendSecurityGroups(...securityGroups: ISecurityGroup[]): void {
securityGroups.forEach(securityGroup => this.loadBalancer.addSecurityGroup(securityGroup));
}

/**
* Adds security groups to the backend components of the Render Queue, which consists of the AutoScalingGroup for the Deadline RCS.
* @param securityGroups The security groups to add.
*/
public addBackendSecurityGroups(...securityGroups: ISecurityGroup[]): void {
securityGroups.forEach(securityGroup => this.asg.addSecurityGroup(securityGroup));
}

private createTaskDefinition(props: {
image: ContainerImage,
portNumber: number,
Expand Down
51 changes: 46 additions & 5 deletions packages/aws-rfdk/lib/deadline/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
InstanceClass,
InstanceSize,
InstanceType,
ISecurityGroup,
IVpc,
OperatingSystemType,
SubnetSelection,
Expand Down Expand Up @@ -242,6 +243,26 @@ export interface RepositoryRemovalPolicies {
readonly filesystem?: RemovalPolicy;
}

/**
* Options for the security groups of the Repository.
*/
export interface RepositorySecurityGroupsOptions {
/**
* The security group for the filesystem of the Repository. This is ignored if the Repository is not creating
* its own Amazon Elastic File System (EFS) because one was given.
*/
readonly fileSystem?: ISecurityGroup;
/**
* The security group for the database of the Repository. This is ignored if the Repository is not creating
* its own DocumentDB database because one was given.
*/
readonly database?: ISecurityGroup;
/**
* The security group for the AutoScalingGroup of the instance that runs the Deadline Repository installer.
*/
readonly installer?: ISecurityGroup;
}

/**
* Properties for the Deadline repository
*/
Expand Down Expand Up @@ -339,6 +360,11 @@ export interface RepositoryProps {
* @default Duration.days(15) for the database
*/
readonly backupOptions?: RepositoryBackupOptions;

/**
* Options to add additional security groups to the Repository.
*/
readonly securityGroupsOptions?: RepositorySecurityGroupsOptions;
}

/**
Expand Down Expand Up @@ -436,6 +462,12 @@ export class Repository extends Construct implements IRepository {
*/
public readonly fileSystem: IMountableLinuxFilesystem;

/**
* The underlying Amazon Elastic File System (EFS) used by the Repository.
* This is only defined if this Repository created its own filesystem, otherwise it will be `undefined`.
*/
public readonly efs?: EfsFileSystem;

/**
* The autoscaling group for this repository's installer-running instance.
*/
Expand All @@ -456,17 +488,24 @@ export class Repository extends Construct implements IRepository {

this.version = props.version;

// Set up the Filesystem and Database components of the repository
this.fileSystem = props.fileSystem ?? new MountableEfs(this, {
filesystem: new EfsFileSystem(this, 'FileSystem', {
// Set up the Filesystem of the repository
if (props.fileSystem !== undefined) {
this.fileSystem = props.fileSystem;
} else {
this.efs = new EfsFileSystem(this, 'FileSystem', {
vpc: props.vpc,
vpcSubnets: props.vpcSubnets ?? { subnetType: SubnetType.PRIVATE },
encrypted: true,
lifecyclePolicy: EfsLifecyclePolicy.AFTER_14_DAYS,
removalPolicy: props.removalPolicy?.filesystem ?? RemovalPolicy.RETAIN,
}),
});
securityGroup: props.securityGroupsOptions?.fileSystem,
});
this.fileSystem = new MountableEfs(this, {
filesystem: this.efs,
});
}

// Set up the Database of the repository
if (props.database) {
this.databaseConnection = props.database;
if (props.databaseAuditLogging !== undefined){
Expand Down Expand Up @@ -498,6 +537,7 @@ export class Repository extends Construct implements IRepository {
instanceType: InstanceType.of(InstanceClass.R5, InstanceSize.LARGE),
vpc: props.vpc,
vpcSubnets: props.vpcSubnets ?? { subnetType: SubnetType.PRIVATE, onePerAz: true },
securityGroup: props.securityGroupsOptions?.database,
},
instances,
backup: {
Expand Down Expand Up @@ -550,6 +590,7 @@ export class Repository extends Construct implements IRepository {
resourceSignalTimeout: (props.repositoryInstallationTimeout || Duration.minutes(15)),
updateType: UpdateType.REPLACING_UPDATE,
replacingUpdateMinSuccessfulInstancesPercent: 100,
securityGroup: props.securityGroupsOptions?.installer,
});
this.node.defaultChild = this.installerGroup;
// Ensure the DB is serving before we try to connect to it.
Expand Down
Loading

0 comments on commit 4fd6663

Please sign in to comment.