in core/src/notebook-platform/notebook-platform.ts [192:317]
constructor(scope: Construct, id: string, props: NotebookPlatformProps) {
super(scope, id);
this.studioServicePolicy = [];
this.studioUserPolicy = [];
this.studioSubnetList = [];
this.managedEndpointExecutionPolicyArnMapping = new Map<string, string>();
this.authMode = props.studioAuthMode;
if (props.idpArn !== undefined) {
this.federatedIdPARN = props.idpArn;
}
//Create encryption key to use with cloudwatch loggroup and S3 bucket storing notebooks and
this.notebookPlatformEncryptionKey = new Key(
this,
'KMS-key-'+ Utils.stringSanitizer(props.studioName), {
enableKeyRotation: true,
},
);
this.emrVirtualClusterName = 'emr-vc-' + Utils.stringSanitizer(props.studioName);
this.emrEks = props.emrEks;
//Get the list of private subnets in VPC
this.studioSubnetList = this.emrEks.eksCluster.vpc.selectSubnets({
onePerAz: true,
subnetType: SubnetType.PRIVATE_WITH_NAT,
}).subnetIds;
//Create a virtual cluster a give it a name of 'emr-vc-'+studioName provided by user
this.emrVirtCluster = this.emrEks.addEmrVirtualCluster(this, {
createNamespace: true,
eksNamespace: props.eksNamespace,
name: Utils.stringSanitizer(this.emrVirtualClusterName),
});
//Create a security group to be attached to the studio workspaces
this.workSpaceSecurityGroup = new SecurityGroup(this, 'workspaceSecurityGroup', {
vpc: this.emrEks.eksCluster.vpc,
securityGroupName: 'workSpaceSecurityGroup-'+props.studioName,
allowAllOutbound: false,
});
//Tag workSpaceSecurityGroup to be used with EMR Studio
Tags.of(this.workSpaceSecurityGroup).add('for-use-with-amazon-emr-managed-policies', 'true');
//Create a security group to be attached to the engine for EMR
//This is mandatory for Amazon EMR Studio although we are not using EMR on EC2
this.engineSecurityGroup = new SecurityGroup(this, 'engineSecurityGroup', {
vpc: this.emrEks.eksCluster.vpc,
securityGroupName: 'engineSecurityGroup-'+props.studioName,
allowAllOutbound: false,
});
//Tag engineSecurityGroup to be used with EMR Studio
Tags.of(this.engineSecurityGroup).add('for-use-with-amazon-emr-managed-policies', 'true');
//Create S3 bucket to store EMR Studio workspaces
//Bucket is kept after destroying the construct
this.workspacesBucket = new Bucket(this, 'WorkspacesBucket' + props.studioName, {
bucketName: 'ara-workspaces-bucket-' + Aws.ACCOUNT_ID + '-' + Utils.stringSanitizer(props.studioName),
enforceSSL: true,
encryptionKey: this.notebookPlatformEncryptionKey,
encryption: BucketEncryption.KMS,
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
});
//Create a Managed policy for Studio service role
this.studioServicePolicy.push(ManagedPolicy.fromManagedPolicyArn(this,
'StudioServiceManagedPolicy', createStudioServiceRolePolicy(this, this.notebookPlatformEncryptionKey.keyArn, this.workspacesBucket.bucketName,
props.studioName),
));
//Create a role for the Studio
this.studioServiceRole = new Role(this, 'studioServiceRole', {
assumedBy: new ServicePrincipal(NotebookPlatform.STUDIO_PRINCIPAL),
roleName: 'studioServiceRole+' + Utils.stringSanitizer(props.studioName),
managedPolicies: this.studioServicePolicy,
});
// Create an EMR Studio user role only if the user uses SSO as authentication mode
if (props.studioAuthMode === 'SSO') {
//Get Managed policy for Studio user role and put it in an array to be assigned to a user role
this.studioUserPolicy.push(ManagedPolicy.fromManagedPolicyArn(this,
'StudioUserManagedPolicy',
createStudioUserRolePolicy(this, props.studioName, this.studioServiceRole.roleName),
));
//Create a role for the EMR Studio user, this roles is further restricted by session policy for each user
this.studioUserRole = new Role(this, 'studioUserRole', {
assumedBy: new ServicePrincipal(NotebookPlatform.STUDIO_PRINCIPAL),
roleName: 'studioUserRole+' + Utils.stringSanitizer(props.studioName),
managedPolicies: this.studioUserPolicy,
});
}
// Create the EMR Studio
this.studioInstance = new CfnStudio(this, 'Studio', <CfnStudioProps>{
authMode: props.studioAuthMode,
defaultS3Location: 's3://' + this.workspacesBucket.bucketName + '/',
engineSecurityGroupId: this.engineSecurityGroup.securityGroupId,
name: props.studioName,
serviceRole: this.studioServiceRole.roleArn,
subnetIds: this.studioSubnetList,
userRole: this.studioUserRole ? this.studioUserRole.roleArn : undefined,
vpcId: this.emrEks.eksCluster.vpc.vpcId,
workspaceSecurityGroupId: this.workSpaceSecurityGroup.securityGroupId,
idpAuthUrl: props.idpAuthUrl ? props.idpAuthUrl : undefined,
idpRelayStateParameterName: props.idpRelayStateParameterName ? props.idpRelayStateParameterName: undefined,
});
// Set the Studio URL and Studio Id this is used in session Mapping for
// EMR Studio when {@linkcode addFederatedUsers} or {@linkcode addSSOUsers} are called
this.studioName = props.studioName;
//Set the Studio Id to use for SessionMapping
this.studioId = this.studioInstance.attrStudioId;
//Return EMR Studio URL as CfnOutput
if (this.nestedStackParent != undefined) {
new CfnOutput(this.nestedStackParent, `URL for EMR Studio: ${this.studioName}`, {
value: this.studioInstance.attrUrl,
});
}
}