in source/lib/stage-four.ts [43:149]
constructor(scope: cdk.Construct, id: string, props: StageFourProps) {
super(scope, id);
// -------------------------------------------------------------------------------------------
// Get Destination S3 bucket
const destinationBucket = s3.Bucket.fromBucketName(this, 'destinationBucket', props.destinationBucket)
// -------------------------------------------------------------------------------------------
// copyToDestinationBucketQueue Queue
const copyToDestinationBucketQueue = new sqs.Queue(this, 'destination-copy-queue',
{
queueName: `${cdk.Aws.STACK_NAME}-destination-copy-queue`,
retentionPeriod: cdk.Duration.days(14),
visibilityTimeout: cdk.Duration.seconds(905)
}
);
CfnNagSuppressor.addSuppression(copyToDestinationBucketQueue, 'W48', 'Non sensitive metadata - encryption is not required and cost inefficient');
copyToDestinationBucketQueue.addToResourcePolicy(iamSec.IamPermissions.sqsDenyInsecureTransport(copyToDestinationBucketQueue));
// -------------------------------------------------------------------------------------------
// Calculate Treehash and verify SHA256TreeHash Glacier == SHA256TreeHash S3
const calculateTreehashRole = new iam.Role(this, 'CalculateTreehashRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com')
});
const calculateTreehashRolePolicy = new iam.Policy(this, 'CalculateTreehashRolePolicy', {
statements: [
iamSec.IamPermissions.lambdaLogGroup(`${cdk.Aws.STACK_NAME}-calculateTreehash`),
new iam.PolicyStatement({
sid: 'allowPutObject',
effect: iam.Effect.ALLOW,
actions: [
's3:PutObject'
],
resources: [`${destinationBucket.bucketArn}/*`]
}),
new iam.PolicyStatement({
sid: 'allowListBucket',
effect: iam.Effect.ALLOW,
actions: [
's3:ListBucket'
],
resources: [`${destinationBucket.bucketArn}`]
}),
]
});
calculateTreehashRolePolicy.attachToRole(calculateTreehashRole);
props.stagingBucket.grantReadWrite(calculateTreehashRole);
props.statusTable.grantReadWriteData(calculateTreehashRole);
props.metricTable.grantReadWriteData(calculateTreehashRole);
props.archiveNotificationQueue.grantSendMessages(calculateTreehashRole);
copyToDestinationBucketQueue.grantSendMessages(calculateTreehashRole);
const defaultCalculateTreehashPolicy = calculateTreehashRole.node.findChild('DefaultPolicy').node.defaultChild as cdk.CfnResource;
CfnNagSuppressor.addCfnSuppression(defaultCalculateTreehashPolicy, 'W76', 'Policy is auto-generated by CDK');
const calculateTreehash = new lambda.Function(this, 'calculateTreehash', {
functionName: `${cdk.Aws.STACK_NAME}-calculateTreehash`,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
memorySize: 1024,
timeout: cdk.Duration.minutes(15),
reservedConcurrentExecutions: 55,
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/calculateTreehash')),
role: calculateTreehashRole,
environment:
{
DESTINATION_BUCKET: props.destinationBucket,
STORAGE_CLASS: props.destinationStorageClass,
STAGING_BUCKET: props.stagingBucket.bucketName,
STAGING_BUCKET_PREFIX: 'stagingdata',
STATUS_TABLE: props.statusTable.tableName,
METRIC_TABLE: props.metricTable.tableName,
SQS_ARCHIVE_NOTIFICATION: props.archiveNotificationQueue.queueName,
SQS_COPY_TO_DESTINATION_NOTIFICATION: copyToDestinationBucketQueue.queueName
}
});
calculateTreehash.addEventSource(new SqsEventSource(props.treehashCalcQueue, { batchSize: 1 }));
CfnNagSuppressor.addLambdaSuppression(calculateTreehash);
// -------------------------------------------------------------------------------------------
// Copy archive from Staging to Destination and delete Staging thereafter
const copyToDestinationBucket = new lambda.Function(this, 'copyToDestinationBucket', {
functionName: `${cdk.Aws.STACK_NAME}-copyToDestinationBucket`,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
memorySize: 128,
timeout: cdk.Duration.minutes(15),
reservedConcurrentExecutions: 100,
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/copyToDestinationBucket')),
environment:
{
DESTINATION_BUCKET: props.destinationBucket,
STORAGE_CLASS: props.destinationStorageClass,
STAGING_BUCKET: props.stagingBucket.bucketName,
STAGING_BUCKET_PREFIX: 'stagingdata',
STATUS_TABLE: props.statusTable.tableName
}
});
props.stagingBucket.grantReadWrite(copyToDestinationBucket);
props.statusTable.grantReadWriteData(copyToDestinationBucket);
destinationBucket.grantReadWrite(copyToDestinationBucket);
copyToDestinationBucket.addEventSource(new SqsEventSource(copyToDestinationBucketQueue, { batchSize: 1 }));
CfnNagSuppressor.addLambdaSuppression(copyToDestinationBucket);
}