@@ -2,21 +2,26 @@ import * as cdk from 'aws-cdk-lib';
22import * as iam from 'aws-cdk-lib/aws-iam' ;
33import * as logs from 'aws-cdk-lib/aws-logs' ;
44import { Construct } from 'constructs' ;
5+ import { ImagePipelineProps } from '../image-pipeline' ;
56import { WorkflowConfiguration } from '../workflow' ;
67
78/**
89 * Returns the default execution role policy, for auto-generated execution roles.
910 *
1011 * @param scope The construct scope
12+ * @param props Props input for the construct
1113 *
1214 * @see https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSServiceRoleForImageBuilder.html
1315 */
14- export const defaultExecutionRolePolicy = ( scope : Construct ) : iam . PolicyStatement [ ] => {
16+ export const defaultExecutionRolePolicy = < PropsT extends ImagePipelineProps > (
17+ scope : Construct ,
18+ props ?: PropsT ,
19+ ) : iam . PolicyStatement [ ] => {
1520 const partition = cdk . Stack . of ( scope ) . partition ;
1621
1722 // Permissions are identical to https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSServiceRoleForImageBuilder.html
1823 // SLR policies cannot be attached to roles, and no managed policy exists for these permissions yet
19- return [
24+ const policies = [
2025 new iam . PolicyStatement ( {
2126 effect : iam . Effect . ALLOW ,
2227 actions : [ 'ec2:RegisterImage' ] ,
@@ -98,7 +103,6 @@ export const defaultExecutionRolePolicy = (scope: Construct): iam.PolicyStatemen
98103 'ec2:DescribeTags' ,
99104 'ec2:ModifyImageAttribute' ,
100105 'ec2:DescribeImportImageTasks' ,
101- 'ec2:DescribeExportImageTasks' ,
102106 'ec2:DescribeSnapshots' ,
103107 'ec2:DescribeHosts' ,
104108 ] ,
@@ -140,11 +144,6 @@ export const defaultExecutionRolePolicy = (scope: Construct): iam.PolicyStatemen
140144 } ,
141145 } ,
142146 } ) ,
143- new iam . PolicyStatement ( {
144- effect : iam . Effect . ALLOW ,
145- actions : [ 'license-manager:UpdateLicenseSpecificationsForResource' ] ,
146- resources : [ '*' ] ,
147- } ) ,
148147 new iam . PolicyStatement ( {
149148 effect : iam . Effect . ALLOW ,
150149 actions : [ 'sns:Publish' ] ,
@@ -235,103 +234,18 @@ export const defaultExecutionRolePolicy = (scope: Construct): iam.PolicyStatemen
235234 } ,
236235 } ,
237236 } ) ,
238- new iam . PolicyStatement ( {
239- effect : iam . Effect . ALLOW ,
240- actions : [ 'sts:AssumeRole' ] ,
241- resources : [ `arn:${ partition } :iam::*:role/EC2ImageBuilderDistributionCrossAccountRole` ] ,
242- } ) ,
243237 new iam . PolicyStatement ( {
244238 effect : iam . Effect . ALLOW ,
245239 actions : [ 'logs:CreateLogStream' , 'logs:CreateLogGroup' , 'logs:PutLogEvents' ] ,
246240 resources : [ `arn:${ partition } :logs:*:*:log-group:/aws/imagebuilder/*` ] ,
247241 } ) ,
248- new iam . PolicyStatement ( {
249- effect : iam . Effect . ALLOW ,
250- actions : [
251- 'ec2:CreateLaunchTemplateVersion' ,
252- 'ec2:DescribeLaunchTemplates' ,
253- 'ec2:ModifyLaunchTemplate' ,
254- 'ec2:DescribeLaunchTemplateVersions' ,
255- ] ,
256- resources : [ '*' ] ,
257- } ) ,
258- new iam . PolicyStatement ( {
259- effect : iam . Effect . ALLOW ,
260- actions : [ 'ec2:ExportImage' ] ,
261- resources : [ `arn:${ partition } :ec2:*::image/*` ] ,
262- conditions : {
263- StringEquals : {
264- 'ec2:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
265- } ,
266- } ,
267- } ) ,
268- new iam . PolicyStatement ( {
269- effect : iam . Effect . ALLOW ,
270- actions : [ 'ec2:ExportImage' ] ,
271- resources : [ `arn:${ partition } :ec2:*:*:export-image-task/*` ] ,
272- } ) ,
273- new iam . PolicyStatement ( {
274- effect : iam . Effect . ALLOW ,
275- actions : [ 'ec2:CancelExportTask' ] ,
276- resources : [ `arn:${ partition } :ec2:*:*:export-image-task/*` ] ,
277- conditions : {
278- StringEquals : {
279- 'ec2:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
280- } ,
281- } ,
282- } ) ,
283242 new iam . PolicyStatement ( {
284243 effect : iam . Effect . ALLOW ,
285244 actions : [ 'iam:CreateServiceLinkedRole' ] ,
286245 resources : [ '*' ] ,
287246 conditions : {
288247 StringEquals : {
289- 'iam:AWSServiceName' : [ 'ssm.amazonaws.com' , 'ec2fastlaunch.amazonaws.com' ] ,
290- } ,
291- } ,
292- } ) ,
293- new iam . PolicyStatement ( {
294- effect : iam . Effect . ALLOW ,
295- actions : [ 'ec2:EnableFastLaunch' ] ,
296- resources : [ `arn:${ partition } :ec2:*::image/*` , `arn:${ partition } :ec2:*:*:launch-template/*` ] ,
297- conditions : {
298- StringEquals : {
299- 'ec2:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
300- } ,
301- } ,
302- } ) ,
303- new iam . PolicyStatement ( {
304- effect : iam . Effect . ALLOW ,
305- actions : [ 'inspector2:ListCoverage' , 'inspector2:ListFindings' ] ,
306- resources : [ '*' ] ,
307- } ) ,
308- new iam . PolicyStatement ( {
309- effect : iam . Effect . ALLOW ,
310- actions : [ 'ecr:CreateRepository' ] ,
311- resources : [ '*' ] ,
312- conditions : {
313- StringEquals : {
314- 'aws:RequestTag/CreatedBy' : 'EC2 Image Builder' ,
315- } ,
316- } ,
317- } ) ,
318- new iam . PolicyStatement ( {
319- effect : iam . Effect . ALLOW ,
320- actions : [ 'ecr:TagResource' ] ,
321- resources : [ `arn:${ partition } :ecr:*:*:repository/image-builder-*` ] ,
322- conditions : {
323- StringEquals : {
324- 'aws:RequestTag/CreatedBy' : 'EC2 Image Builder' ,
325- } ,
326- } ,
327- } ) ,
328- new iam . PolicyStatement ( {
329- effect : iam . Effect . ALLOW ,
330- actions : [ 'ecr:BatchDeleteImage' ] ,
331- resources : [ `arn:${ partition } :ecr:*:*:repository/image-builder-*` ] ,
332- conditions : {
333- StringEquals : {
334- 'ecr:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
248+ 'iam:AWSServiceName' : [ 'ssm.amazonaws.com' ] ,
335249 } ,
336250 } ,
337251 } ) ,
@@ -357,6 +271,133 @@ export const defaultExecutionRolePolicy = (scope: Construct): iam.PolicyStatemen
357271 resources : [ `arn:${ partition } :ssm:*::parameter/aws/service/*` ] ,
358272 } ) ,
359273 ] ;
274+
275+ const hasProps = props !== undefined ;
276+ if ( ! hasProps || ( props . recipe . _isImageRecipe ( ) && props . distributionConfiguration !== undefined ) ) {
277+ // Distribution-specific permissions if distribution settings are provided. All permissions here are for AMI builds
278+ // specifically.
279+ policies . push (
280+ new iam . PolicyStatement ( {
281+ effect : iam . Effect . ALLOW ,
282+ actions : [ 'ec2:DescribeExportImageTasks' ] ,
283+ resources : [ '*' ] ,
284+ } ) ,
285+ new iam . PolicyStatement ( {
286+ effect : iam . Effect . ALLOW ,
287+ actions : [ 'license-manager:UpdateLicenseSpecificationsForResource' ] ,
288+ resources : [ '*' ] ,
289+ } ) ,
290+ new iam . PolicyStatement ( {
291+ effect : iam . Effect . ALLOW ,
292+ actions : [ 'sts:AssumeRole' ] ,
293+ resources : [ `arn:${ partition } :iam::*:role/EC2ImageBuilderDistributionCrossAccountRole` ] ,
294+ } ) ,
295+ new iam . PolicyStatement ( {
296+ effect : iam . Effect . ALLOW ,
297+ actions : [
298+ 'ec2:CreateLaunchTemplateVersion' ,
299+ 'ec2:DescribeLaunchTemplates' ,
300+ 'ec2:ModifyLaunchTemplate' ,
301+ 'ec2:DescribeLaunchTemplateVersions' ,
302+ ] ,
303+ resources : [ '*' ] ,
304+ } ) ,
305+ new iam . PolicyStatement ( {
306+ effect : iam . Effect . ALLOW ,
307+ actions : [ 'ec2:ExportImage' ] ,
308+ resources : [ `arn:${ partition } :ec2:*::image/*` ] ,
309+ conditions : {
310+ StringEquals : {
311+ 'ec2:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
312+ } ,
313+ } ,
314+ } ) ,
315+ new iam . PolicyStatement ( {
316+ effect : iam . Effect . ALLOW ,
317+ actions : [ 'ec2:ExportImage' ] ,
318+ resources : [ `arn:${ partition } :ec2:*:*:export-image-task/*` ] ,
319+ } ) ,
320+ new iam . PolicyStatement ( {
321+ effect : iam . Effect . ALLOW ,
322+ actions : [ 'ec2:CancelExportTask' ] ,
323+ resources : [ `arn:${ partition } :ec2:*:*:export-image-task/*` ] ,
324+ conditions : {
325+ StringEquals : {
326+ 'ec2:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
327+ } ,
328+ } ,
329+ } ) ,
330+ new iam . PolicyStatement ( {
331+ effect : iam . Effect . ALLOW ,
332+ actions : [ 'iam:CreateServiceLinkedRole' ] ,
333+ resources : [ '*' ] ,
334+ conditions : {
335+ StringEquals : {
336+ 'iam:AWSServiceName' : [ 'ec2fastlaunch.amazonaws.com' ] ,
337+ } ,
338+ } ,
339+ } ) ,
340+ new iam . PolicyStatement ( {
341+ effect : iam . Effect . ALLOW ,
342+ actions : [ 'ec2:EnableFastLaunch' ] ,
343+ resources : [ `arn:${ partition } :ec2:*::image/*` , `arn:${ partition } :ec2:*:*:launch-template/*` ] ,
344+ conditions : {
345+ StringEquals : {
346+ 'ec2:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
347+ } ,
348+ } ,
349+ } ) ,
350+ ) ;
351+ }
352+
353+ if ( ! hasProps || props . imageScanningEnabled !== false ) {
354+ // Add Inspector permissions if scanning is enabled
355+ policies . push (
356+ new iam . PolicyStatement ( {
357+ effect : iam . Effect . ALLOW ,
358+ actions : [ 'inspector2:ListCoverage' , 'inspector2:ListFindings' ] ,
359+ resources : [ '*' ] ,
360+ } ) ,
361+ ) ;
362+
363+ // Add image scanning ECR permissions for container builds
364+ if ( ! hasProps || props . recipe . _isContainerRecipe ( ) ) {
365+ policies . push (
366+ new iam . PolicyStatement ( {
367+ effect : iam . Effect . ALLOW ,
368+ actions : [ 'ecr:CreateRepository' ] ,
369+ resources : [ '*' ] ,
370+ conditions : {
371+ StringEquals : {
372+ 'aws:RequestTag/CreatedBy' : 'EC2 Image Builder' ,
373+ } ,
374+ } ,
375+ } ) ,
376+ new iam . PolicyStatement ( {
377+ effect : iam . Effect . ALLOW ,
378+ actions : [ 'ecr:TagResource' ] ,
379+ resources : [ `arn:${ partition } :ecr:*:*:repository/image-builder-*` ] ,
380+ conditions : {
381+ StringEquals : {
382+ 'aws:RequestTag/CreatedBy' : 'EC2 Image Builder' ,
383+ } ,
384+ } ,
385+ } ) ,
386+ new iam . PolicyStatement ( {
387+ effect : iam . Effect . ALLOW ,
388+ actions : [ 'ecr:BatchDeleteImage' ] ,
389+ resources : [ `arn:${ partition } :ecr:*:*:repository/image-builder-*` ] ,
390+ conditions : {
391+ StringEquals : {
392+ 'ecr:ResourceTag/CreatedBy' : 'EC2 Image Builder' ,
393+ } ,
394+ } ,
395+ } ) ,
396+ ) ;
397+ }
398+ }
399+
400+ return policies ;
360401} ;
361402
362403export const getExecutionRole = (
0 commit comments