packages/constructs/L3/dataops/dataops-dms-l3-construct/lib/dms-l3-construct.ts (313 lines of code) (raw):
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
import {
DocDbSettingsProperty,
DynamoDbSettingsProperty,
ElasticsearchSettingsProperty,
IbmDb2SettingsProperty,
KinesisSettingsProperty,
MdaaEndpoint,
MdaaEndpointEngine,
MdaaEndpointProps,
MdaaEndpointType,
MdaaReplicationInstance,
MdaaReplicationInstanceProps,
MicrosoftSqlServerSettingsProperty,
MongoDbSettingsProperty,
MySqlSettingsProperty,
NeptuneSettingsProperty,
OracleSettingsProperty,
PostgreSqlSettingsProperty,
RedshiftSettingsProperty,
S3SettingsProperty,
SybaseSettingsProperty,
} from '@aws-mdaa/dms-constructs';
import { MdaaSecurityGroup, MdaaSecurityGroupProps, MdaaSecurityGroupRuleProps } from '@aws-mdaa/ec2-constructs';
import { MdaaManagedPolicy, MdaaRole } from '@aws-mdaa/iam-constructs';
import { MdaaL3Construct, MdaaL3ConstructProps } from '@aws-mdaa/l3-construct';
import {
CfnEndpoint,
CfnReplicationInstance,
CfnReplicationSubnetGroup,
CfnReplicationSubnetGroupProps,
CfnReplicationTask,
CfnReplicationTaskProps,
} from 'aws-cdk-lib/aws-dms';
import { Vpc } from 'aws-cdk-lib/aws-ec2';
import { Effect, IRole, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
import { IKey, Key } from 'aws-cdk-lib/aws-kms';
import { Bucket, IBucket } from 'aws-cdk-lib/aws-s3';
import { ISecret, Secret } from 'aws-cdk-lib/aws-secretsmanager';
import { Construct } from 'constructs';
export interface EndpointProps {
/**
* The type of Endpoint ("source" or "target")
*/
readonly endpointType: MdaaEndpointType;
/**
* The name of the endpoint engine
*/
readonly engineName: MdaaEndpointEngine;
/**
* The optional name of the endpoint database. Required for certain endpoint types.
*/
readonly databaseName?: string;
/**
* Settings in JSON format for the source and target DocumentDB endpoint.
*
* For more information about other available settings, see [Using extra connections attributes with Amazon DocumentDB as a source](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.DocumentDB.html#CHAP_Source.DocumentDB.ECAs) and [Using Amazon DocumentDB as a target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.DocumentDB.html) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-docdbsettings
*/
readonly docDbSettings?: DocDbSettingsProperty;
/**
* Settings in JSON format for the target Amazon DynamoDB endpoint.
*
* For information about other available settings, see [Using object mapping to migrate data to DynamoDB](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.DynamoDB.html#CHAP_Target.DynamoDB.ObjectMapping) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-dynamodbsettings
*/
readonly dynamoDbSettings?: DynamoDbSettingsProperty;
/**
* Settings in JSON format for the target OpenSearch endpoint.
*
* For more information about the available settings, see [Extra connection attributes when using OpenSearch as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Elasticsearch.html#CHAP_Target.Elasticsearch.Configuration) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-elasticsearchsettings
*/
readonly elasticsearchSettings?: ElasticsearchSettingsProperty;
/**
* Settings in JSON format for the source IBM Db2 LUW endpoint.
*
* For information about other available settings, see [Extra connection attributes when using Db2 LUW as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.DB2.html#CHAP_Source.DB2.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-ibmdb2settings
*/
readonly ibmDb2Settings?: IbmDb2SettingsProperty;
/**
* Settings in JSON format for the target endpoint for Amazon Kinesis Data Streams.
*
* For more information about other available settings, see [Using object mapping to migrate data to a Kinesis data stream](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Kinesis.html#CHAP_Target.Kinesis.ObjectMapping) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-kinesissettings
*/
readonly kinesisSettings?: KinesisSettingsProperty;
/**
* Settings in JSON format for the source and target Microsoft SQL Server endpoint.
*
* For information about other available settings, see [Extra connection attributes when using SQL Server as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.SQLServer.html#CHAP_Source.SQLServer.ConnectionAttrib) and [Extra connection attributes when using SQL Server as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.SQLServer.html#CHAP_Target.SQLServer.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-microsoftsqlserversettings
*/
readonly microsoftSqlServerSettings?: MicrosoftSqlServerSettingsProperty;
/**
* Settings in JSON format for the source MongoDB endpoint.
*
* For more information about the available settings, see [Using MongoDB as a target for AWS Database Migration Service](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MongoDB.html#CHAP_Source.MongoDB.Configuration) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-mongodbsettings
*/
readonly mongoDbSettings?: MongoDbSettingsProperty;
/**
* Settings in JSON format for the source and target MySQL endpoint.
*
* For information about other available settings, see [Extra connection attributes when using MySQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.ConnectionAttrib) and [Extra connection attributes when using a MySQL-compatible database as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.MySQL.html#CHAP_Target.MySQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-mysqlsettings
*/
readonly mySqlSettings?: MySqlSettingsProperty;
/**
* Settings in JSON format for the target Amazon Neptune endpoint.
*
* For more information about the available settings, see [Specifying endpoint settings for Amazon Neptune as a target](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Neptune.html#CHAP_Target.Neptune.EndpointSettings) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-neptunesettings
*/
readonly neptuneSettings?: NeptuneSettingsProperty;
/**
* Settings in JSON format for the source and target Oracle endpoint.
*
* For information about other available settings, see [Extra connection attributes when using Oracle as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.Oracle.html#CHAP_Source.Oracle.ConnectionAttrib) and [Extra connection attributes when using Oracle as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Oracle.html#CHAP_Target.Oracle.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-oraclesettings
*/
readonly oracleSettings?: OracleSettingsProperty;
/**
* Settings in JSON format for the source and target PostgreSQL endpoint.
*
* For information about other available settings, see [Extra connection attributes when using PostgreSQL as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.ConnectionAttrib) and [Extra connection attributes when using PostgreSQL as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.PostgreSQL.html#CHAP_Target.PostgreSQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-postgresqlsettings
*/
readonly postgreSqlSettings?: PostgreSqlSettingsProperty;
/**
* Settings in JSON format for the Amazon Redshift endpoint.
*
* For more information about other available settings, see [Extra connection attributes when using Amazon Redshift as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Redshift.html#CHAP_Target.Redshift.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-redshiftsettings
*/
readonly redshiftSettings?: RedshiftSettingsProperty;
/**
* Settings in JSON format for the source and target Amazon S3 endpoint.
*
* For more information about other available settings, see [Extra connection attributes when using Amazon S3 as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.S3.html#CHAP_Source.S3.Configuring) and [Extra connection attributes when using Amazon S3 as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.S3.html#CHAP_Target.S3.Configuring) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-s3settings
*/
readonly s3Settings?: S3SettingsProperty;
/**
* Settings in JSON format for the source and target SAP ASE endpoint.
*
* For information about other available settings, see [Extra connection attributes when using SAP ASE as a source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.SAP.html#CHAP_Source.SAP.ConnectionAttrib) and [Extra connection attributes when using SAP ASE as a target for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.SAP.html#CHAP_Target.SAP.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-sybasesettings
*/
readonly sybaseSettings?: SybaseSettingsProperty;
}
export interface NamedEndpointProps {
/**
* @jsii ignore
*/
[instanceName: string]: EndpointProps;
}
export interface ReplicationInstanceProps {
/**
* The compute class of the replication instance.
* For supported types, see https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.Types.html
*/
readonly instanceClass: string;
/**
* List of subnet ids on which the replication instance will be deployed.
* This list must span at least two Azs
*/
readonly subnetIds: string[];
/**
* The VPC on which the replication instance will be deployed.
*/
readonly vpcId: string;
/**
* List of ingress rules to be added to the function SG
*/
readonly ingressRules?: MdaaSecurityGroupRuleProps;
/**
* List of egress rules to be added to the function SG
*/
readonly egressRules?: MdaaSecurityGroupRuleProps;
/**
* If true, the SG will allow traffic to and from itself
*/
readonly addSelfReferenceRule?: boolean;
}
export interface NamedReplicationInstanceProps {
/**
* @jsii ignore
*/
[instanceName: string]: ReplicationInstanceProps;
}
export type DmsMigrationType = `full-load` | `cdc` | `full-load-and-cdc`;
export interface ReplicationTaskProps {
/**
* The name of the replication instance from the 'replicationInstances' section.
*/
readonly replicationInstance: string;
/**
* The name of the source endpoint from the 'endpoints' section of this config
*
*/
readonly sourceEndpoint: string;
/**
* The name of the target endpoint from the 'endpoints' section of this config
*/
readonly targetEndpoint: string;
/**
* Indicates when you want a change data capture (CDC) operation to start.
*
* Use either `CdcStartPosition` or `CdcStartTime` to specify when you want a CDC operation to start. Specifying both values results in an error.
*
* The value can be in date, checkpoint, log sequence number (LSN), or system change number (SCN) format.
*
* Here is a date example: `--cdc-start-position "2018-03-08T12:12:12"`
*
* Here is a checkpoint example: `--cdc-start-position "checkpoint:V1#27#mysql-bin-changelog.157832:1975:-1:2002:677883278264080:mysql-bin-changelog.157832:1876#0#0#*#0#93"`
*
* Here is an LSN example: `--cdc-start-position “mysql-bin-changelog.000024:373”`
*
* > When you use this task setting with a source PostgreSQL database, a logical replication slot should already be created and associated with the source endpoint. You can verify this by setting the `slotName` extra connection attribute to the name of this logical replication slot. For more information, see [Extra Connection Attributes When Using PostgreSQL as a Source for AWS DMS](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.ConnectionAttrib) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-cdcstartposition
*/
readonly cdcStartPosition?: string;
/**
* Indicates the start time for a change data capture (CDC) operation.
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-cdcstarttime
*/
readonly cdcStartTime?: number;
/**
* Indicates when you want a change data capture (CDC) operation to stop.
*
* The value can be either server time or commit time.
*
* Here is a server time example: `--cdc-stop-position "server_time:2018-02-09T12:12:12"`
*
* Here is a commit time example: `--cdc-stop-position "commit_time: 2018-02-09T12:12:12"`
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-cdcstopposition
*/
readonly cdcStopPosition?: string;
/**
* The migration type.
*
* Valid values: `full-load` | `cdc` | `full-load-and-cdc`
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-migrationtype
*/
readonly migrationType: DmsMigrationType;
/**
* The table mappings for the task, in JSON format.
*
* For more information, see [Using Table Mapping to Specify Task Settings](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TableMapping.html) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-tablemappings
*/
readonly tableMappings: { [key: string]: unknown };
/**
* Supplemental information that the task requires to migrate the data for certain source and target endpoints.
*
* For more information, see [Specifying Supplemental Data for Task Settings](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.TaskData.html) in the *AWS Database Migration Service User Guide.*
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-taskdata
*/
readonly taskData?: { [key: string]: unknown };
/**
* Overall settings for the task, in JSON format.
*
* For more information, see [Specifying Task Settings for AWS Database Migration Service Tasks](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.html) in the *AWS Database Migration Service User Guide* .
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-replicationtask.html#cfn-dms-replicationtask-replicationtasksettings
*/
readonly replicationTaskSettings?: { [key: string]: unknown };
}
export interface NamedReplicationTaskProps {
/**
* @jsii ignore
*/
[taskName: string]: ReplicationTaskProps;
}
export interface DMSProps {
readonly dmsRoleArn?: string;
readonly replicationInstances?: NamedReplicationInstanceProps;
readonly endpoints?: NamedEndpointProps;
readonly replicationTasks?: NamedReplicationTaskProps;
}
export interface DMSL3ConstructProps extends MdaaL3ConstructProps {
// Name of the Data-Ops project.
readonly projectName: string;
/**
* The name of the Data Ops project bucket which will be used as temporary storage for DMS jobs
*/
readonly projectBucket: string;
/**
* Arn of KMS key which will be used to encrypt the cluster resources
*/
readonly kmsArn: string;
readonly dms: DMSProps;
}
export class DMSL3Construct extends MdaaL3Construct {
private static readonly engineToSettingsNameMap: { [engineName in MdaaEndpointEngine]: string | undefined } = {
mysql: 'mySqlSettings',
oracle: 'oracleSettings',
postgres: 'postgreSqlSettings',
mariadb: 'mySqlSettings',
aurora: 'mySqlSettings',
'aurora-postgresql': 'postgreSqlSettings',
opensearch: undefined,
redshift: 'redshiftSettings',
'redshift-serverless': '',
s3: 's3Settings',
db2: 'ibmDb2Settings',
azuredb: undefined,
sybase: 'sybaseSettings',
dynamodb: 'dynamoDbSettings',
mongodb: 'mongoDbSettings',
kinesis: 'kinesisSettings',
kafka: undefined,
elasticsearch: 'elasticsearchSettings',
docdb: 'docDbSettings',
sqlserver: 'microsoftSqlServerSettings',
neptune: 'neptuneSettings',
};
private static readonly awsServiceEngineNames: MdaaEndpointEngine[] = [
's3',
'dynamodb',
'kinesis',
'docdb',
'neptune',
];
protected readonly props: DMSL3ConstructProps;
protected readonly projectKms: IKey;
protected readonly projectBucket: IBucket;
constructor(scope: Construct, id: string, props: DMSL3ConstructProps) {
super(scope, id, props);
this.props = props;
this.projectKms = Key.fromKeyArn(this.scope, 'project-kms', this.props.kmsArn);
this.projectBucket = Bucket.fromBucketName(this.scope, `project-bucket`, this.props.projectBucket);
const dmsRole = props.dms.dmsRoleArn
? Role.fromRoleArn(this, 'dms-role', props.dms.dmsRoleArn)
: this.createDmsRole();
const replicationInstances = this.createReplicationInstances();
const endpoints = this.createEndpoints(dmsRole);
this.createReplicationTasks(replicationInstances, endpoints);
}
private createReplicationTasks(
replicationInstances: { [name: string]: CfnReplicationInstance },
endpoints: { [name: string]: CfnEndpoint },
) {
Object.entries(this.props.dms.replicationTasks || {}).forEach(([taskName, taskProps]) => {
const replicationInstanceArn = taskProps.replicationInstance
? replicationInstances[taskProps.replicationInstance]?.ref
: undefined;
if (!replicationInstanceArn) {
throw new Error(`Unable to determine replication instance Arn from config ${taskProps.replicationInstance}.`);
}
const sourceEndpointArn = endpoints[taskProps.sourceEndpoint]?.ref;
if (!sourceEndpointArn) {
throw new Error(`Unable to determine source endpoint Arn from config ${taskProps.sourceEndpoint}.`);
}
const targetEndpointArn = endpoints[taskProps.targetEndpoint]?.ref;
if (!targetEndpointArn) {
throw new Error(`Unable to determine target endpoint Arn from config ${taskProps.targetEndpoint}.`);
}
const cfnTaskProps: CfnReplicationTaskProps = {
...taskProps,
replicationInstanceArn: replicationInstanceArn,
sourceEndpointArn: sourceEndpointArn,
targetEndpointArn: targetEndpointArn,
replicationTaskIdentifier: this.props.naming.resourceName(taskName),
taskData: taskProps.taskData ? JSON.stringify(taskProps.taskData) : undefined,
tableMappings: JSON.stringify(taskProps.tableMappings),
replicationTaskSettings: taskProps.replicationTaskSettings
? JSON.stringify(taskProps.replicationTaskSettings)
: undefined,
};
new CfnReplicationTask(this, `replication-task-${taskName}`, cfnTaskProps);
});
}
private createDmsRole(): IRole {
return new MdaaRole(this, 'dms-role', {
naming: this.props.naming,
roleName: 'dms',
assumedBy: new ServicePrincipal(`dms.${this.region}.amazonaws.com`),
});
}
private createEndpoints(dmsRole: IRole): { [name: string]: CfnEndpoint } {
const secrets: ISecret[] = [];
const secretKeys: IKey[] = [];
const endpoints = Object.fromEntries(
Object.entries(this.props.dms.endpoints || {}).map(([endpointName, endpointProps]) => {
const engineSettingsPropName = DMSL3Construct.engineToSettingsNameMap[
endpointProps.engineName
] as keyof EndpointProps;
const engineSettingsProp = endpointProps[engineSettingsPropName];
if (!engineSettingsProp) {
throw new Error(`${engineSettingsPropName} must be defined for engineName ${endpointProps.engineName}`);
}
if (DMSL3Construct.awsServiceEngineNames.includes(endpointProps.engineName)) {
// @ts-ignore need to figure out what type is engineSettingsProps
engineSettingsProp['serviceAccessRoleArn'] = dmsRole.roleArn;
}
Object.entries(endpointProps).forEach(([, prop]) => {
if (!prop || typeof prop !== 'object') {
console.log(`Strange, was expecting ${prop} to be an object`);
return;
}
if ('secretsManagerSecretArn' in prop && prop.secretsManagerAccessRoleArn === undefined) {
const secretArn = prop['secretsManagerSecretArn'];
prop.secretsManagerAccessRoleArn = dmsRole.roleArn;
prop['secretsManagerSecretId'] = secretArn;
secrets.push(Secret.fromSecretCompleteArn(this, `secret-import-${endpointName}`, secretArn));
const secretKeyKMSArn = prop['secretsManagerSecretKMSArn'];
if (secretKeyKMSArn) {
secretKeys.push(Key.fromKeyArn(this, `secret-key-import-${endpointName}`, secretKeyKMSArn));
}
}
if ('secretsManagerOracleAsmSecretArn' in prop && prop.secretsManagerOracleAsmAccessRoleArn === undefined) {
const secretArn = prop['secretsManagerOracleAsmSecretArn'];
prop['secretsManagerOracleAsmSecretId'] = secretArn;
prop['secretsManagerOracleAsmAccessRoleArn'] = dmsRole.roleArn;
secrets.push(Secret.fromSecretCompleteArn(this, `asm-secret-import-${endpointName}`, secretArn));
}
});
const mdaaEndpointProps: MdaaEndpointProps = {
...endpointProps,
endpointIdentifier: endpointName,
kmsKey: this.projectKms,
naming: this.props.naming,
};
const endpoint = new MdaaEndpoint(this, `endpoint-${endpointName}`, mdaaEndpointProps);
return [endpointName, endpoint];
}),
);
this.createSecretsAccessPolicy(dmsRole, secrets, secretKeys);
return endpoints;
}
private createSecretsAccessPolicy(dmsRole: IRole, secrets: ISecret[], secretKeys: IKey[]) {
if (secrets.length > 0) {
const secretsStatement = new PolicyStatement({
actions: ['secretsmanager:DescribeSecret', 'secretsmanager:GetSecretValue'],
resources: secrets.map(x => x.secretArn),
effect: Effect.ALLOW,
});
const secretKMSStatement =
secretKeys.length > 0
? [
new PolicyStatement({
actions: ['kms:Decrypt', 'kms:DescribeKey'],
resources: secretKeys.map(x => x.keyArn),
effect: Effect.ALLOW,
}),
]
: [];
new MdaaManagedPolicy(this, 'secrets-access-policy', {
managedPolicyName: 'secrets-access',
naming: this.props.naming,
roles: [dmsRole],
statements: [secretsStatement, ...secretKMSStatement],
});
}
}
private createReplicationInstances(): { [name: string]: CfnReplicationInstance } {
return Object.fromEntries(
Object.entries(this.props.dms.replicationInstances || {}).map(([instanceName, instanceProps]) => {
const subnetGroupProps: CfnReplicationSubnetGroupProps = {
replicationSubnetGroupIdentifier: this.props.naming.resourceName(instanceName),
replicationSubnetGroupDescription: this.props.naming.resourceName(instanceName),
subnetIds: instanceProps.subnetIds,
};
const subnetGroup = new CfnReplicationSubnetGroup(
this,
`replication-subnet-group-${instanceName}`,
subnetGroupProps,
);
const vpc = Vpc.fromVpcAttributes(this, 'vpc of' + instanceName, {
availabilityZones: ['dummy'],
vpcId: instanceProps.vpcId,
});
const customEgress: boolean =
(instanceProps.egressRules?.ipv4 && instanceProps.egressRules?.ipv4.length > 0) ||
(instanceProps.egressRules?.prefixList && instanceProps.egressRules?.prefixList.length > 0) ||
(instanceProps.egressRules?.sg && instanceProps.egressRules?.sg.length > 0) ||
false;
const securityGroupCreateProps: MdaaSecurityGroupProps = {
securityGroupName: instanceName,
vpc: vpc,
naming: this.props.naming,
ingressRules: instanceProps.ingressRules,
egressRules: instanceProps.egressRules,
allowAllOutbound: !customEgress,
addSelfReferenceRule: instanceProps.addSelfReferenceRule,
};
const securityGroup = new MdaaSecurityGroup(this, `security-group-${instanceName}`, securityGroupCreateProps);
const constructProps: MdaaReplicationInstanceProps = {
replicationInstanceIdentifier: instanceName,
replicationInstanceClass: instanceProps.instanceClass,
kmsKey: this.projectKms,
replicationSubnetGroupIdentifier: this.props.naming.resourceName(instanceName),
naming: this.props.naming,
vpcSecurityGroupIds: [securityGroup.securityGroupId],
};
const replicationInstance = new MdaaReplicationInstance(
this,
`replication-instance-${instanceName}`,
constructProps,
);
replicationInstance.addDependency(subnetGroup);
return [instanceName, replicationInstance];
}),
);
}
}