Skip to content

Commit

Permalink
fix(pipelines): Reduce template size by combining IAM roles and policies
Browse files Browse the repository at this point in the history
This change combines the two roles (and policies) per pipeline asset into a
single role + policy for all assets in a pipeline. In a small pipeline with only
3 assets, this reduced the overall template size by a third.

With a pipeline stack with 30 assets, this change reduces the template size from
363111 bytes to 190223 bytes.

Tested on a cross-account pipeline to verify permissions were retained.

fixes #9066
mitigates #9225
mitigates #9237
  • Loading branch information
njlynch committed Jul 24, 2020
1 parent d3e5533 commit 4a4b8a7
Show file tree
Hide file tree
Showing 5 changed files with 1,861 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export interface PublishAssetsActionProps {
* @default - Automatically generated
*/
readonly projectName?: string;

/**
* Role to use for CodePipeline and CodeBuild to build and publish the assets.
*
* @default - Automatically generated
*/
readonly role?: iam.IRole;
}

/**
Expand Down Expand Up @@ -87,6 +94,7 @@ export class PublishAssetsAction extends Construct implements codepipeline.IActi
}),
// Needed to perform Docker builds
environment: props.assetType === AssetType.DOCKER_IMAGE ? { privileged: true } : undefined,
role: props.role,
});

const rolePattern = props.assetType === AssetType.DOCKER_IMAGE
Expand All @@ -102,6 +110,7 @@ export class PublishAssetsAction extends Construct implements codepipeline.IActi
actionName: props.actionName,
project,
input: this.props.cloudAssemblyInput,
role: props.role,
});
}

Expand Down
19 changes: 16 additions & 3 deletions packages/@aws-cdk/pipelines/lib/pipeline.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as codepipeline from '@aws-cdk/aws-codepipeline';
import { App, CfnOutput, Construct, Stack, Stage } from '@aws-cdk/core';
import * as path from 'path';
import * as codepipeline from '@aws-cdk/aws-codepipeline';
import * as iam from '@aws-cdk/aws-iam';
import { App, CfnOutput, Construct, PhysicalName, Stack, Stage } from '@aws-cdk/core';
import { AssetType, DeployCdkStackAction, PublishAssetsAction, UpdatePipelineAction } from './actions';
import { appOf, assemblyBuilderOf } from './private/construct-internals';
import { AddStageOptions, AssetPublishingCommand, CdkStage, StackOutput } from './stage';
Expand Down Expand Up @@ -244,6 +245,7 @@ class AssetPublishing extends Construct {
private readonly myCxAsmRoot: string;

private readonly stage: codepipeline.IStage;
private assetRole?: iam.Role;
private _fileAssetCtr = 1;
private _dockerAssetCtr = 1;

Expand All @@ -267,6 +269,17 @@ class AssetPublishing extends Construct {
// FIXME: this is silly, we need the relative path here but no easy way to get it
const relativePath = path.relative(this.myCxAsmRoot, command.assetManifestPath);

// This role is used by both the CodePipeline build action and related CodeBuild project. Consolidating these two
// roles into one, and re-using across all assets, saves significant size of the final synthesized output.
// Modeled after the CodePipeline role and 'CodePipelineActionRole' roles.
// Late-binding here to prevent creating the role in cases where no asset actions are created.
if (!this.assetRole) {
this.assetRole = new iam.Role(this, 'Role', {
roleName: PhysicalName.GENERATE_IF_NEEDED,
assumedBy: new iam.CompositePrincipal(new iam.ServicePrincipal('codebuild.amazonaws.com'), new iam.AccountPrincipal(Stack.of(this).account)),
});
}

let action = this.publishers[command.assetId];
if (!action) {
// The asset ID would be a logical candidate for the construct path and project names, but if the asset
Expand All @@ -275,7 +288,6 @@ class AssetPublishing extends Construct {
//
// FIXME: The ultimate best solution is probably to generate a single Project per asset type
// and reuse that for all assets.

const id = command.assetType === AssetType.FILE ? `FileAsset${this._fileAssetCtr++}` : `DockerAsset${this._dockerAssetCtr++}`;

// NOTE: It's important that asset changes don't force a pipeline self-mutation.
Expand All @@ -286,6 +298,7 @@ class AssetPublishing extends Construct {
cloudAssemblyInput: this.props.cloudAssemblyInput,
cdkCliVersion: this.props.cdkCliVersion,
assetType: command.assetType,
role: this.assetRole,
});
this.stage.addAction(action);
}
Expand Down
Loading

0 comments on commit 4a4b8a7

Please sign in to comment.