Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(deadline): add security group configuration for Repository and RenderQueue #319

Merged
merged 3 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
ddneilson marked this conversation as resolved.
Show resolved Hide resolved
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) {
ddneilson marked this conversation as resolved.
Show resolved Hide resolved
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(' '),
);
}
kozlove-aws marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* 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;
}
kozlove-aws marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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