Skip to content

Commit

Permalink
feat: add ability to use EFS access points (#339)
Browse files Browse the repository at this point in the history
- Allows instances to access EFS with a specified UID/GID

BREAKING CHANGE: Repository constructs supplied with an EFS file-system must also pass an EFS Access Point
- If your application provides an EFS file-system to a Repository construct, it must now also pass an
  EFS Access Point to work properly with the Deadline container images.
- Consult https://github.com/aws/aws-rfdk/blob/v0.27.0/packages/aws-rfdk/docs/upgrade/upgrading-0.27.md
  for detailed instructions on how to upgrade
  • Loading branch information
jusiskin committed Mar 12, 2021
1 parent ac052ea commit 544496c
Show file tree
Hide file tree
Showing 21 changed files with 796 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def main():
# ------------------------------
service_props = service_tier.ServiceTierProps(
database=storage.database,
file_system=storage.file_system,
mountable_file_system=storage.mountable_file_system,
vpc=network.vpc,
ubl_certs_secret_arn=config.ubl_certificate_secret_arn,
ubl_licenses=config.ubl_licenses,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def __init__(self):
self.deadline_version: Optional[str] = None

# A map of regions to Deadline Client Linux AMIs. As an example, the Linux Deadline 10.1.13.2 AMI ID
# from us-west-2 is filled in. It can be used as-is, added to, or replaced. Ideally the version here
# should match the one used for fetching the render queue and usage based licensing images.
# from us-west-2 is filled in. It can be used as-is, added to, or replaced. Ideally the version here should match the version of
# Deadline used in any connected Deadline constructs.
self.deadline_client_linux_ami_map: Mapping[str, str] = {'us-west-2': 'ami-0237f13ce87af168e'}

# A secret (in binary form) in SecretsManager that stores the UBL certificates in a .zip file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

from aws_rfdk import (
DistinguishedName,
IMountableLinuxFilesystem,
MountableEfs,
SessionManagerHelper,
X509CertificatePem
)
Expand Down Expand Up @@ -58,8 +58,8 @@ class ServiceTierProps(StackProps):
vpc: IVpc
# The database to connect to.
database: DatabaseConnection
# The file system to install Deadline Repository to.
file_system: IMountableLinuxFilesystem
# The file-system to install Deadline Repository to.
mountable_file_system: MountableEfs
# The ARN of the secret containing the UBL certificates .zip file (in binary form).
ubl_certs_secret_arn: typing.Optional[str]
# The UBL licenses to configure
Expand Down Expand Up @@ -109,9 +109,9 @@ def __init__(self, scope: Construct, stack_id: str, *, props: ServiceTierProps,
]
)

# Granting the bastion access to the file system mount for convenience.
# This can also safely be removed.
props.file_system.mount_to_linux_instance(
# Mounting the root of the EFS file-system to the bastion access for convenience.
# This can safely be removed.
MountableEfs(self, filesystem=props.mountable_file_system.file_system).mount_to_linux_instance(
self.bastion.instance,
location='/mnt/efs'
)
Expand All @@ -127,8 +127,9 @@ def __init__(self, scope: Construct, stack_id: str, *, props: ServiceTierProps,
'Repository',
vpc=props.vpc,
database=props.database,
file_system=props.file_system,
file_system=props.mountable_file_system,
repository_installation_timeout=Duration.minutes(20),
repository_installation_prefix='/',
version=self.version
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
SubnetType
)
from aws_cdk.aws_efs import (
AccessPoint,
Acl,
FileSystem,
PosixUser
)
from aws_cdk.aws_route53 import (
IPrivateHostedZone
Expand Down Expand Up @@ -75,20 +78,54 @@ def __init__(self, scope: Construct, stack_id: str, *, props: StorageTierProps,
:param kwargs: Any kwargs that need to be passed on to the parent class.
"""
super().__init__(scope, stack_id, **kwargs)
# The file system to use (e.g. to install Deadline Repository onto).
self.file_system = MountableEfs(

# The file-system to use (e.g. to install Deadline Repository onto).
file_system = FileSystem(
self,
'EfsFileSystem',
vpc=props.vpc,
encrypted=True,
# TODO - Evaluate this removal policy for your own needs. This is set to DESTROY to
# cleanly remove everything when this stack is destroyed. If you would like to ensure
# that your data is not accidentally deleted, you should modify this value.
removal_policy=RemovalPolicy.DESTROY
)

# Create an EFS access point that is used to grant the Repository and RenderQueue with write access to the
# Deadline Repository directory in the EFS file-system.
access_point = AccessPoint(
self,
filesystem=FileSystem(
self,
'EfsFileSystem',
vpc=props.vpc,
# TODO - Evaluate this removal policy for your own needs. This is set to DESTROY to
# cleanly remove everything when this stack is destroyed. If you would like to ensure
# that your data is not accidentally deleted, you should modify this value.
removal_policy=RemovalPolicy.DESTROY
'AccessPoint',
file_system=file_system,

# The AccessPoint will create the directory (denoted by the path property below) if it doesn't exist with
# the owning UID/GID set as specified here. These should be set up to grant read and write access to the
# UID/GID configured in the "poxis_user" property below.
create_acl=Acl(
owner_uid='10000',
owner_gid='10000',
permissions='750',
),

# When you mount the EFS via the access point, the mount will be rooted at this path in the EFS file-system
path='/DeadlineRepository',

# TODO - When you mount the EFS via the access point, all file-system operations will be performed using
# these UID/GID values instead of those from the user on the system where the EFS is mounted. If you intend
# to use the same EFS file-system for other purposes (e.g. render assets, plug-in storage), you may want to
# evaluate the UID/GID permissions based on your requirements.
posix_user=PosixUser(
uid='10000',
gid='10000'
)
)

self.mountable_file_system = MountableEfs(
self,
filesystem=file_system,
access_point=access_point
)

# The database to connect Deadline to.
self.database: Optional[DatabaseConnection] = None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ if (config.deployMongoDB) {
const service = new ServiceTier(app, 'ServiceTier', {
env,
database: storage.database,
fileSystem: storage.fileSystem,
mountableFileSystem: storage.mountableFileSystem,
vpc: network.vpc,
deadlineVersion: config.deadlineVersion,
ublCertsSecretArn: config.ublCertificatesSecretArn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class AppConfig {

/**
* A map of regions to Deadline Client Linux AMIs. As an example, the Linux Deadline 10.1.13.2 AMI ID from us-west-2
* is filled in. It can be used as-is, added to, or replaced. Ideally the version here should match the one in
* package.json used for fetching the render queue and usage based licensing images.
* is filled in. It can be used as-is, added to, or replaced. Ideally the version here should match the version of
* Deadline used in any connected Deadline constructs.
*/
public readonly deadlineClientLinuxAmiMap: Record<string, string> = {['us-west-2']: 'ami-0237f13ce87af168e'};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '@aws-cdk/aws-route53';
import * as cdk from '@aws-cdk/core';
import {
IMountableLinuxFilesystem,
MountableEfs,
X509CertificatePem,
} from 'aws-rfdk';
import {
Expand All @@ -33,7 +33,6 @@ import {
import {
Secret,
} from '@aws-cdk/aws-secretsmanager';
import { Duration } from '@aws-cdk/core';
import { SessionManagerHelper } from 'aws-rfdk/lib/core';

/**
Expand All @@ -51,9 +50,9 @@ export interface ServiceTierProps extends cdk.StackProps {
readonly database: DatabaseConnection;

/**
* The file system to install Deadline Repository to.
* The file-system to install Deadline Repository to.
*/
readonly fileSystem: IMountableLinuxFilesystem;
readonly mountableFileSystem: MountableEfs;

/**
* Our self-signed root CA certificate for the internal endpoints in the farm.
Expand Down Expand Up @@ -136,11 +135,15 @@ export class ServiceTier extends cdk.Stack {
volume: BlockDeviceVolume.ebs(50, {
encrypted: true,
})},
]
],
});
// Granting the bastion access to the file system mount for convenience
props.database.allowConnectionsFrom(this.bastion);

// Granting the bastion access to the entire EFS file-system.
// This can also be safely removed
props.fileSystem.mountToLinuxInstance(this.bastion.instance, {
new MountableEfs(this, {
filesystem: props.mountableFileSystem.fileSystem,
}).mountToLinuxInstance(this.bastion.instance, {
location: '/mnt/efs',
});

Expand All @@ -152,8 +155,9 @@ export class ServiceTier extends cdk.Stack {
vpc: props.vpc,
version: this.version,
database: props.database,
fileSystem: props.fileSystem,
repositoryInstallationTimeout: Duration.minutes(20),
fileSystem: props.mountableFileSystem,
repositoryInstallationTimeout: cdk.Duration.minutes(20),
repositoryInstallationPrefix: "/",
});

const images = new ThinkboxDockerImages(this, 'Images', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import {
} from '@aws-cdk/aws-ec2';
import * as cdk from '@aws-cdk/core';
import { DatabaseCluster } from '@aws-cdk/aws-docdb';
import { FileSystem } from '@aws-cdk/aws-efs';
import {
AccessPoint,
FileSystem,
} from '@aws-cdk/aws-efs';
import { IPrivateHostedZone } from '@aws-cdk/aws-route53';
import { RemovalPolicy, Duration } from '@aws-cdk/core';
import {
IMountableLinuxFilesystem,
MongoDbInstance,
MongoDbPostInstallSetup,
MongoDbSsplLicenseAcceptance,
Expand Down Expand Up @@ -45,9 +47,9 @@ export interface StorageTierProps extends cdk.StackProps {
*/
export abstract class StorageTier extends cdk.Stack {
/**
* The file system to use (e.g. to install Deadline Repository onto).
* The mountable file-system to use for the Deadline Repository
*/
public readonly fileSystem: IMountableLinuxFilesystem;
public readonly mountableFileSystem: MountableEfs;

/**
* The database to connect Deadline to.
Expand All @@ -63,15 +65,45 @@ export abstract class StorageTier extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props: StorageTierProps) {
super(scope, id, props);

this.fileSystem = new MountableEfs(this, {
filesystem: new FileSystem(this, 'EfsFileSystem', {
vpc: props.vpc,
encrypted: true,
// TODO - Evaluate this removal policy for your own needs. This is set to DESTROY to
// cleanly remove everything when this stack is destroyed. If you would like to ensure
// that your data is not accidentally deleted, you should modify this value.
removalPolicy: RemovalPolicy.DESTROY,
}),
const fileSystem = new FileSystem(this, 'EfsFileSystem', {
vpc: props.vpc,
encrypted: true,
// TODO - Evaluate this removal policy for your own needs. This is set to DESTROY to
// cleanly remove everything when this stack is destroyed. If you would like to ensure
// that your data is not accidentally deleted, you should modify this value.
removalPolicy: RemovalPolicy.DESTROY,
});

// Create an EFS access point that is used to grant the Repository and RenderQueue with write access to the Deadline
// Repository directory in the EFS file-system.
const accessPoint = new AccessPoint(this, 'AccessPoint', {
fileSystem,

// The AccessPoint will create the directory (denoted by the "path" property below) if it doesn't exist with the
// owning UID/GID set as specified here. These should be set up to grant read and write access to the UID/GID
// configured in the "poxisUser" property below.
createAcl: {
ownerGid: '10000',
ownerUid: '10000',
permissions: '750',
},

// When you mount the EFS via the access point, the mount will be rooted at this path in the EFS file-system
path: '/DeadlineRepository',

// TODO - When you mount the EFS via the access point, all file-system operations will be performed using these
// UID/GID values instead of those from the user on the system where the EFS is mounted. If you intend to use the
// same EFS file-system for other purposes (e.g. render assets, plug-in storage), you may want to evaluate the
// UID/GID permissions based on your requirements.
posixUser: {
uid: '10000',
gid: '10000',
},
});

this.mountableFileSystem = new MountableEfs(this, {
filesystem: fileSystem,
accessPoint,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/aws-rfdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ Please see the following sources for additional information:
* The [RFDK API Documentation](https://docs.aws.amazon.com/rfdk/api/latest/docs/aws-rfdk-construct-library.html)
* The [README for the main module](https://github.com/aws/aws-rfdk/blob/mainline/packages/aws-rfdk/lib/core/README.md)
* The [README for the Deadline module](https://github.com/aws/aws-rfdk/blob/mainline/packages/aws-rfdk/lib/deadline/README.md)
* The [RFDK Upgrade Documentation](./docs/upgrade/index.md)
7 changes: 7 additions & 0 deletions packages/aws-rfdk/docs/upgrade/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Upgrading RFDK

This documentation aims to provide information to help planning or troubleshoot issues upgrading RFDK in your CDK
applications. The documentation is separated by RFDK versions that included potentially breaking changes. If you are
upgrading to (or beyond) a version listed below, you should consult the the linked upgrade documentation.

* [`0.27.x`](./upgrading-0.27.md)
Loading

0 comments on commit 544496c

Please sign in to comment.