in packages/apps/core/devops/lib/devops.ts [114:339]
constructor(scope: Construct, id: string, props: MdaaDevopsL3ConstructProps) {
super(scope, id, props);
this.props = props;
const pipelineRole = new MdaaRole(this, 'pipeline-role', {
roleName: 'pipeline',
naming: this.props.naming,
assumedBy: new ServicePrincipal('codepipeline.amazonaws.com'),
});
const mdaaRepo = Repository.fromRepositoryName(this, 'mdaa-import-repo', this.props.mdaaCodeCommitRepo);
const configsRepo = Repository.fromRepositoryName(this, 'configs-import-repo', this.props.configsCodeCommitRepo);
const kmsKey = new MdaaKmsKey(this, 'kms-key', {
naming: this.props.naming,
keyUserRoleIds: [pipelineRole.roleId],
});
const devOpsBucket = new MdaaBucket(this, 'pipeline-bucket', {
naming: this.props.naming,
encryptionKey: kmsKey,
});
MdaaNagSuppressions.addCodeResourceSuppressions(
devOpsBucket,
[
{
id: 'NIST.800.53.R5-S3BucketReplicationEnabled',
reason: 'Bucket does not contain data assets. Replication not required.',
},
{
id: 'HIPAA.Security-S3BucketReplicationEnabled',
reason: 'Bucket does not contain data assets. Replication not required.',
},
{
id: 'PCI.DSS.321-S3BucketReplicationEnabled',
reason: 'Bucket does not contain data assets. Replication not required.',
},
],
true,
);
const codeCommitEventRole = new MdaaRole(this, 'codecommit-event-role', {
roleName: 'codecommit-event',
naming: this.props.naming,
assumedBy: new ServicePrincipal('events.amazonaws.com'),
});
const codeCommitReadPolicy = new PolicyDocument({
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['codecommit:GetBranch', 'codecommit:GetCommit', 'codecommit:GetRepository', 'codecommit:GitPull'],
resources: [mdaaRepo.repositoryArn, configsRepo.repositoryArn],
}),
],
});
const codeCommitActionRole = new MdaaRole(this, 'codecommit-action-role', {
roleName: 'codecommit-action',
naming: this.props.naming,
assumedBy: new AccountPrincipal(this.account),
inlinePolicies: { codecommit_read: codeCommitReadPolicy },
});
const codeBuildActionRole = new MdaaRole(this, 'codebuild-action-role', {
roleName: 'codebuild-action',
naming: this.props.naming,
assumedBy: new CompositePrincipal(
new ServicePrincipal('codebuild.amazonaws.com'),
new AccountPrincipal(this.account),
),
managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName('AWSCloudFormationReadOnlyAccess')],
});
const codeBuildActionPolicy = new Policy(this, 'codebuild-policy');
const cdkLookupRole = this.importCdkRole(this, 'lookup', this.props.cdkBootstrapContext);
const cdkDeployRole = this.importCdkRole(this, 'deploy', this.props.cdkBootstrapContext);
const cdkExecRole = this.importCdkRole(this, 'exec', this.props.cdkBootstrapContext);
const cdkFilePublishingRole = this.importCdkRole(this, 'file-publishing', this.props.cdkBootstrapContext);
const cdkImagePublishingRole = this.importCdkRole(this, 'image-publishing', this.props.cdkBootstrapContext);
const cdkBucket = Bucket.fromBucketName(
this,
`cdk-bucket-import`,
`cdk-${this.props.cdkBootstrapContext ?? MdaaDevopsL3Construct.DEFAULT_CDK_BOOTSTRAP_CONTEXT}-assets-${
this.account
}-${this.region}`,
);
codeBuildActionPolicy.addStatements(
new PolicyStatement({
sid: 'ASSUMECDKROLES',
actions: ['sts:AssumeRole'],
resources: [
cdkLookupRole.roleArn,
cdkDeployRole.roleArn,
cdkFilePublishingRole.roleArn,
cdkImagePublishingRole.roleArn,
cdkExecRole.roleArn,
],
effect: Effect.ALLOW,
}),
);
codeBuildActionPolicy.addStatements(
new PolicyStatement({
sid: 'S3List',
actions: ['s3:ListAllMyBuckets'],
resources: ['*'],
effect: Effect.ALLOW,
}),
new PolicyStatement({
sid: 'CloudFormationChangeSets',
actions: [
'cloudformation:CreateChangeSet',
'cloudformation:DescribeChangeSet',
'cloudformation:DeleteChangeSet',
],
resources: ['*'],
effect: Effect.ALLOW,
}),
);
codeBuildActionPolicy.addStatements(
new PolicyStatement({
sid: 'CDKS3',
actions: ['s3:Get*', 's3:Put*', 's3:List*'],
resources: [cdkBucket.bucketArn, cdkBucket.arnForObjects('*')],
effect: Effect.ALLOW,
}),
);
MdaaNagSuppressions.addCodeResourceSuppressions(
codeBuildActionPolicy,
[
{ id: 'AwsSolutions-IAM5', reason: 'Permissions are scoped least privilege for deployment time.' },
{ id: 'NIST.800.53.R5-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'HIPAA.Security-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'PCI.DSS.321-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
],
true,
);
codeBuildActionPolicy.attachToRole(codeBuildActionRole);
const manualActionRole = new MdaaRole(this, 'manual-action-role', {
roleName: 'manual-action',
naming: this.props.naming,
assumedBy: new AccountPrincipal(this.account),
});
const assumeActionRoleGrant = codeBuildActionRole.grantAssumeRole(pipelineRole);
Object.entries(this.props.pipelines ?? {}).forEach(entry => {
const pipelineProps: MdaaPipelineProps = {
pipelineType: PipelineType.V2,
naming: this.props.naming.withModuleName(`devops-${entry[0]}`),
pipelineName: this.props.naming.resourceName(entry[0]),
...entry[1],
role: pipelineRole,
artifactBucket: devOpsBucket,
codeCommitActionRole: codeCommitActionRole,
codeCommitEventRole: codeCommitEventRole,
codeBuildActionRole: codeBuildActionRole,
mdaaRepo: mdaaRepo,
configsRepo: configsRepo,
kmsKey: kmsKey,
manualActionRole: manualActionRole,
install: [...(this.props.install ?? []), ...(entry[1].install ?? [])],
pre: [...(this.props.pre ?? []), ...(entry[1].pre ?? [])],
post: [...(this.props.post ?? []), ...(entry[1].post ?? [])],
preDeploy: { ...this.props.preDeploy, ...entry[1].preDeploy },
preDeployValidate:
this.props.preDeployValidate || entry[1].preDeployValidate
? { ...this.props.preDeployValidate, ...entry[1].preDeployValidate }
: undefined,
deploy: { ...this.props.deploy, ...entry[1].deploy },
postDeployValidate:
this.props.postDeployValidate || entry[1].postDeployValidate
? { ...this.props.postDeployValidate, ...entry[1].postDeployValidate }
: undefined,
};
const pipeline = new MdaaPipeline(this, `mdaa-pipeline-${entry[0]}`, pipelineProps);
assumeActionRoleGrant.applyBefore(pipeline);
});
MdaaNagSuppressions.addCodeResourceSuppressions(
pipelineRole,
[
{ id: 'AwsSolutions-IAM5', reason: 'Permissions are scoped least privilege for deployment time.' },
{ id: 'NIST.800.53.R5-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'HIPAA.Security-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'PCI.DSS.321-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
],
true,
);
MdaaNagSuppressions.addCodeResourceSuppressions(
codeBuildActionRole,
[
{ id: 'AwsSolutions-IAM4', reason: 'AWSCloudFormationReadOnlyAccess is Read Only Access' },
{ id: 'AwsSolutions-IAM5', reason: 'Permissions are scoped least privilege for deployment time.' },
{ id: 'NIST.800.53.R5-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'HIPAA.Security-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'PCI.DSS.321-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
],
true,
);
MdaaNagSuppressions.addCodeResourceSuppressions(
codeCommitActionRole,
[
{ id: 'AwsSolutions-IAM5', reason: 'Permissions are scoped least privilege for deployment time.' },
{ id: 'NIST.800.53.R5-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'HIPAA.Security-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'PCI.DSS.321-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
],
true,
);
MdaaNagSuppressions.addCodeResourceSuppressions(
codeCommitEventRole,
[
{ id: 'NIST.800.53.R5-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'HIPAA.Security-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
{ id: 'PCI.DSS.321-IAMNoInlinePolicy', reason: 'Inline policy appropriate.' },
],
true,
);
}