Skip to content

Commit 14d8a47

Browse files
committed
fix(pipelines): reduce assets IAM policy size
Collapse the PipelineAssetsRoleDefaultPolicy into a single up-front policy that doesn't grow per-asset. This relaxes some of the permissions in exchange for avoiding an O(N) policy size. fixes #9316
1 parent cbfdc15 commit 14d8a47

File tree

1 file changed

+67
-10
lines changed

1 file changed

+67
-10
lines changed

packages/@aws-cdk/pipelines/lib/pipeline.ts

+67-10
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ class AssetPublishing extends Construct {
245245
private readonly myCxAsmRoot: string;
246246

247247
private readonly stage: codepipeline.IStage;
248-
private assetRole?: iam.Role;
248+
private readonly pipeline: codepipeline.Pipeline;
249+
private assetRole?: iam.IRole;
249250
private _fileAssetCtr = 1;
250251
private _dockerAssetCtr = 1;
251252

@@ -256,6 +257,7 @@ class AssetPublishing extends Construct {
256257
// We MUST add the Stage immediately here, otherwise it will be in the wrong place
257258
// in the pipeline!
258259
this.stage = this.props.pipeline.addStage({ stageName: 'Assets' });
260+
this.pipeline = this.props.pipeline;
259261
}
260262

261263
/**
@@ -269,15 +271,9 @@ class AssetPublishing extends Construct {
269271
// FIXME: this is silly, we need the relative path here but no easy way to get it
270272
const relativePath = path.relative(this.myCxAsmRoot, command.assetManifestPath);
271273

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

283279
let action = this.publishers[command.assetId];
@@ -321,9 +317,70 @@ class AssetPublishing extends Construct {
321317
}
322318
}
323319
}
320+
321+
/**
322+
* This role is used by both the CodePipeline build action and related CodeBuild project. Consolidating these two
323+
* roles into one, and re-using across all assets, saves significant size of the final synthesized output.
324+
* Modeled after the CodePipeline role and 'CodePipelineActionRole' roles.
325+
*/
326+
private generateAssetRole() {
327+
const assetRole = new iam.Role(this, 'Role', {
328+
roleName: PhysicalName.GENERATE_IF_NEEDED,
329+
assumedBy: new iam.CompositePrincipal(new iam.ServicePrincipal('codebuild.amazonaws.com'), new iam.AccountPrincipal(Stack.of(this).account)),
330+
});
331+
332+
// Logging permissions
333+
const logGroupArn = Stack.of(this).formatArn({
334+
service: 'logs',
335+
resource: 'log-group',
336+
sep: ':',
337+
resourceName: '/aws/codebuild/*',
338+
});
339+
assetRole.addToPolicy(new iam.PolicyStatement({
340+
resources: [logGroupArn],
341+
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
342+
}));
343+
344+
// CodeBuild report groups
345+
const codeBuildArn = Stack.of(this).formatArn({
346+
service: 'codebuild',
347+
resource: 'report-group',
348+
resourceName: '*',
349+
});
350+
assetRole.addToPolicy(new iam.PolicyStatement({
351+
actions: [
352+
'codebuild:CreateReportGroup',
353+
'codebuild:CreateReport',
354+
'codebuild:UpdateReport',
355+
'codebuild:BatchPutTestCases',
356+
],
357+
resources: [codeBuildArn],
358+
}));
359+
360+
// CodeBuild start/stop
361+
assetRole.addToPolicy(new iam.PolicyStatement({
362+
resources: ['*'],
363+
actions: [
364+
'codebuild:BatchGetBuilds',
365+
'codebuild:StartBuild',
366+
'codebuild:StopBuild',
367+
],
368+
}));
369+
370+
// Publishing role access
371+
assetRole.addToPolicy(new iam.PolicyStatement({
372+
actions: ['sts:AssumeRole'],
373+
resources: ['arn:*:iam::*:role/*-image-publishing-role-*', 'arn:*:iam::*:role/*-file-publishing-role-*'],
374+
}));
375+
376+
this.pipeline.artifactBucket.grantRead(assetRole);
377+
378+
this.assetRole = assetRole.withoutPolicyUpdates();
379+
return this.assetRole;
380+
}
324381
}
325382

326383
function maybeSuffix(x: string | undefined, suffix: string): string | undefined {
327384
if (x === undefined) { return undefined; }
328385
return `${x}${suffix}`;
329-
}
386+
}

0 commit comments

Comments
 (0)