packages/constructs/L3/ai/sm-shared/lib/sm-shared.ts (126 lines of code) (raw):
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
import { Fn, Stack } from 'aws-cdk-lib';
import { IRole } from 'aws-cdk-lib/aws-iam';
import { IBucket } from 'aws-cdk-lib/aws-s3';
import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
import { MdaaNagSuppressions } from '@aws-mdaa/construct'; //NOSONAR
import { Construct } from 'constructs';
export interface LifecycleScriptProps {
readonly assets?: NamedAssetProps;
readonly cmds: string[];
}
export interface NamedAssetProps {
/** @jsii ignore */
readonly [name: string]: AssetProps;
}
export interface AssetProps {
readonly sourcePath: string;
readonly exclude?: string[];
}
export interface AssetDeploymentProps {
readonly scope: Construct;
readonly assetBucket: IBucket;
readonly assetPrefix: string;
readonly assetDeploymentRole: IRole;
readonly memoryLimitMB?: number;
}
export class LifeCycleConfigHelper {
public static createLifecycleConfigContents(
scriptProps: LifecycleScriptProps,
lifecycleType: string,
assetDeployment?: AssetDeploymentProps,
): string {
let cmds = scriptProps.cmds;
if (scriptProps.assets) {
if (!assetDeployment) {
throw new Error('assetDeployment must be defined if assets defined');
}
this.createAssets(scriptProps.assets, lifecycleType, assetDeployment);
const assetS3CopyPath = `${assetDeployment.assetPrefix}/${lifecycleType}/`;
const setAssetEnvCmd = `export ASSETS_DIR=/tmp/lifecycle-assets/${lifecycleType}`;
const assetCopyCmd = `aws s3 cp --recursive ${assetDeployment.assetBucket.s3UrlForObject(
assetS3CopyPath,
)} $ASSETS_DIR`;
cmds = [setAssetEnvCmd, assetCopyCmd, ...scriptProps.cmds];
}
const cmdsString = cmds.join('\n');
return Fn.base64(cmdsString);
}
private static createAssets(
namedAssetProps: NamedAssetProps,
lifecycleType: string,
assetDeployment: AssetDeploymentProps,
) {
//create assets
Object.entries(namedAssetProps).forEach(assetEntry => {
const assetName = assetEntry[0];
const assetProps = assetEntry[1];
const assetSource = Source.asset(assetProps.sourcePath, { exclude: assetProps.exclude });
new BucketDeployment(assetDeployment.scope, `asset-deployment-${assetName}-${lifecycleType}`, {
sources: [assetSource],
destinationBucket: assetDeployment.assetBucket,
destinationKeyPrefix: `${assetDeployment.assetPrefix}/${lifecycleType}/${assetName}`,
role: assetDeployment.assetDeploymentRole,
extract: true,
memoryLimit: assetDeployment.memoryLimitMB,
});
});
// BucketDeployment adds an inline policy to asset deployment role
// permitting the copy of assets from cdk depoy bucket to destination bucket.
MdaaNagSuppressions.addCodeResourceSuppressions(
assetDeployment.assetDeploymentRole,
[
{ id: 'AwsSolutions-IAM5', reason: 'Inline policy used only for deployment.' },
{ id: 'NIST.800.53.R5-IAMNoInlinePolicy', reason: 'Policy used only for deployment.' },
{ id: 'HIPAA.Security-IAMNoInlinePolicy', reason: 'Policy used only for deployment.' },
{ id: 'PCI.DSS.321-IAMNoInlinePolicy', reason: 'Policy used only for deployment.' },
],
true,
);
// BucketDeployment uses a Custom Resource Lambda to copy assets
// from CDK Deployment bucket to destination bucket.
Stack.of(assetDeployment.scope).node.children.forEach(child => {
if (child.node.id.includes('Custom::CDKBucketDeployment')) {
MdaaNagSuppressions.addCodeResourceSuppressions(
child,
[
{ id: 'AwsSolutions-L1', reason: 'Function is used only as custom resource during CDK deployment.' },
{
id: 'NIST.800.53.R5-LambdaConcurrency',
reason: 'Function is used only as custom resource during CDK deployment.',
},
{
id: 'NIST.800.53.R5-LambdaInsideVPC',
reason: 'Function is used only as custom resource during CDK deployment and interacts only with S3.',
},
{
id: 'NIST.800.53.R5-LambdaDLQ',
reason:
'Function is used only as custom resource during CDK deployment. Errors will be handled by CloudFormation.',
},
{
id: 'HIPAA.Security-LambdaConcurrency',
reason: 'Function is used only as custom resource during CDK deployment.',
},
{
id: 'PCI.DSS.321-LambdaConcurrency',
reason: 'Function is used only as custom resource during CDK deployment.',
},
{
id: 'HIPAA.Security-LambdaInsideVPC',
reason: 'Function is used only as custom resource during CDK deployment and interacts only with S3.',
},
{
id: 'PCI.DSS.321-LambdaInsideVPC',
reason: 'Function is used only as custom resource during CDK deployment and interacts only with S3.',
},
{
id: 'HIPAA.Security-LambdaDLQ',
reason:
'Function is used only as custom resource during CDK deployment. Errors will be handled by CloudFormation.',
},
{
id: 'PCI.DSS.321-LambdaDLQ',
reason:
'Function is used only as custom resource during CDK deployment. Errors will be handled by CloudFormation.',
},
],
true,
);
}
});
}
}