@aws-cdk/aws-imagebuilder-alpha 2.229.1-alpha.0 → 2.231.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,6 +36,457 @@ EC2 Image Builder supports AWS-managed components for common tasks, AWS Marketpl
36
36
  that you create. Components run during specific workflow phases: build and validate phases during the build stage, and
37
37
  test phase during the test stage.
38
38
 
39
+ ### Image Pipeline
40
+
41
+ An image pipeline provides the automation framework for building secure AMIs and container images. The pipeline
42
+ orchestrates the entire image creation process by combining an image recipe or container recipe with infrastructure
43
+ configuration and distribution configuration. Pipelines can run on a schedule or be triggered manually, and they manage
44
+ the build, test, and distribution phases automatically.
45
+
46
+ #### Image Pipeline Basic Usage
47
+
48
+ Create a simple AMI pipeline with just an image recipe:
49
+
50
+ ```ts
51
+ const imageRecipe = new imagebuilder.ImageRecipe(this, 'MyImageRecipe', {
52
+ baseImage: imagebuilder.BaseImage.fromSsmParameterName(
53
+ '/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'
54
+ )
55
+ });
56
+
57
+ const imagePipeline = new imagebuilder.ImagePipeline(this, 'MyImagePipeline', {
58
+ recipe: exampleImageRecipe
59
+ });
60
+ ```
61
+
62
+ Create a simple container pipeline with just a container recipe:
63
+
64
+ ```ts
65
+ const containerRecipe = new imagebuilder.ContainerRecipe(this, 'MyContainerRecipe', {
66
+ baseImage: imagebuilder.BaseContainerImage.fromDockerHub('amazonlinux', 'latest'),
67
+ targetRepository: imagebuilder.Repository.fromEcr(
68
+ ecr.Repository.fromRepositoryName(this, 'Repository', 'my-container-repo')
69
+ )
70
+ });
71
+
72
+ const containerPipeline = new imagebuilder.ImagePipeline(this, 'MyContainerPipeline', {
73
+ recipe: exampleContainerRecipe
74
+ });
75
+ ```
76
+
77
+ #### Image Pipeline Scheduling
78
+
79
+ ##### Manual Pipeline Execution
80
+
81
+ Create a pipeline that runs only when manually triggered:
82
+
83
+ ```ts
84
+ const manualPipeline = new imagebuilder.ImagePipeline(this, 'ManualPipeline', {
85
+ imagePipelineName: 'my-manual-pipeline',
86
+ description: 'Pipeline triggered manually for production builds',
87
+ recipe: exampleImageRecipe
88
+ // No schedule property - manual execution only
89
+ });
90
+
91
+ // Grant Lambda function permission to trigger the pipeline
92
+ manualPipeline.grantStartExecution(lambdaRole);
93
+ ```
94
+
95
+ ##### Automated Pipeline Scheduling
96
+
97
+ Schedule a pipeline to run automatically using cron expressions:
98
+
99
+ ```ts
100
+ const weeklyPipeline = new imagebuilder.ImagePipeline(this, 'WeeklyPipeline', {
101
+ imagePipelineName: 'weekly-build-pipeline',
102
+ recipe: exampleImageRecipe,
103
+ schedule: {
104
+ expression: events.Schedule.cron({
105
+ minute: '0',
106
+ hour: '6',
107
+ weekDay: 'MON'
108
+ })
109
+ }
110
+ });
111
+ ```
112
+
113
+ Use rate expressions for regular intervals:
114
+
115
+ ```ts
116
+ const dailyPipeline = new imagebuilder.ImagePipeline(this, 'DailyPipeline', {
117
+ recipe: exampleContainerRecipe,
118
+ schedule: {
119
+ expression: events.Schedule.rate(Duration.days(1))
120
+ }
121
+ });
122
+ ```
123
+
124
+ ##### Pipeline Schedule Configuration
125
+
126
+ Configure advanced scheduling options:
127
+
128
+ ```ts
129
+ const advancedSchedulePipeline = new imagebuilder.ImagePipeline(this, 'AdvancedSchedulePipeline', {
130
+ recipe: exampleImageRecipe,
131
+ schedule: {
132
+ expression: events.Schedule.rate(Duration.days(7)),
133
+ // Only trigger when dependencies are updated (new base images, components, etc.)
134
+ startCondition: imagebuilder.ScheduleStartCondition.EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE,
135
+ // Automatically disable after 3 consecutive failures
136
+ autoDisableFailureCount: 3
137
+ },
138
+ // Start enabled
139
+ status: imagebuilder.ImagePipelineStatus.ENABLED
140
+ });
141
+ ```
142
+
143
+ #### Image Pipeline Configuration
144
+
145
+ ##### Infrastructure and Distribution in Image Pipelines
146
+
147
+ Configure custom infrastructure and distribution settings:
148
+
149
+ ```ts
150
+ const infrastructureConfiguration = new imagebuilder.InfrastructureConfiguration(this, 'Infrastructure', {
151
+ infrastructureConfigurationName: 'production-infrastructure',
152
+ instanceTypes: [
153
+ ec2.InstanceType.of(ec2.InstanceClass.COMPUTE7_INTEL, ec2.InstanceSize.LARGE)
154
+ ],
155
+ vpc: vpc,
156
+ subnetSelection: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }
157
+ });
158
+
159
+ const distributionConfiguration = new imagebuilder.DistributionConfiguration(this, 'Distribution');
160
+ distributionConfiguration.addAmiDistributions({
161
+ amiName: 'production-ami-{{ imagebuilder:buildDate }}',
162
+ amiTargetAccountIds: ['123456789012', '098765432109']
163
+ });
164
+
165
+ const productionPipeline = new imagebuilder.ImagePipeline(this, 'ProductionPipeline', {
166
+ recipe: exampleImageRecipe,
167
+ infrastructureConfiguration: infrastructureConfiguration,
168
+ distributionConfiguration: distributionConfiguration
169
+ });
170
+ ```
171
+
172
+ ##### Pipeline Logging Configuration
173
+
174
+ Configure custom CloudWatch log groups for pipeline and image logs:
175
+
176
+ ```ts
177
+ const pipelineLogGroup = new logs.LogGroup(this, 'PipelineLogGroup', {
178
+ logGroupName: '/custom/imagebuilder/pipeline/logs',
179
+ retention: logs.RetentionDays.ONE_MONTH
180
+ });
181
+
182
+ const imageLogGroup = new logs.LogGroup(this, 'ImageLogGroup', {
183
+ logGroupName: '/custom/imagebuilder/image/logs',
184
+ retention: logs.RetentionDays.ONE_WEEK
185
+ });
186
+
187
+ const loggedPipeline = new imagebuilder.ImagePipeline(this, 'LoggedPipeline', {
188
+ recipe: exampleImageRecipe,
189
+ imagePipelineLogGroup: pipelineLogGroup,
190
+ imageLogGroup: imageLogGroup
191
+ });
192
+ ```
193
+
194
+ ##### Workflow Integration in Image Pipelines
195
+
196
+ Use AWS-managed workflows for common pipeline phases:
197
+
198
+ ```ts
199
+ const workflowPipeline = new imagebuilder.ImagePipeline(this, 'WorkflowPipeline', {
200
+ recipe: exampleImageRecipe,
201
+ workflows: [
202
+ { workflow: imagebuilder.AwsManagedWorkflow.buildImage(this, 'BuildWorkflow') },
203
+ { workflow: imagebuilder.AwsManagedWorkflow.testImage(this, 'TestWorkflow') }
204
+ ]
205
+ });
206
+ ```
207
+
208
+ For container pipelines, use container-specific workflows:
209
+
210
+ ```ts
211
+ const containerWorkflowPipeline = new imagebuilder.ImagePipeline(this, 'ContainerWorkflowPipeline', {
212
+ recipe: exampleContainerRecipe,
213
+ workflows: [
214
+ { workflow: imagebuilder.AwsManagedWorkflow.buildContainer(this, 'BuildContainer') },
215
+ { workflow: imagebuilder.AwsManagedWorkflow.testContainer(this, 'TestContainer') },
216
+ { workflow: imagebuilder.AwsManagedWorkflow.distributeContainer(this, 'DistributeContainer') }
217
+ ]
218
+ });
219
+ ```
220
+
221
+ ##### Advanced Features in Image Pipelines
222
+
223
+ Configure image scanning for container pipelines:
224
+
225
+ ```ts
226
+ const scanningRepository = new ecr.Repository(this, 'ScanningRepo');
227
+
228
+ const scannedContainerPipeline = new imagebuilder.ImagePipeline(this, 'ScannedContainerPipeline', {
229
+ recipe: exampleContainerRecipe,
230
+ imageScanningEnabled: true,
231
+ imageScanningEcrRepository: scanningRepository,
232
+ imageScanningEcrTags: ['security-scan', 'latest']
233
+ });
234
+ ```
235
+
236
+ Control metadata collection and testing:
237
+
238
+ ```ts
239
+ const controlledPipeline = new imagebuilder.ImagePipeline(this, 'ControlledPipeline', {
240
+ recipe: exampleImageRecipe,
241
+ enhancedImageMetadataEnabled: true, // Collect detailed OS and package info
242
+ imageTestsEnabled: false // Skip testing phase for faster builds
243
+ });
244
+ ```
245
+
246
+ #### Image Pipeline Events
247
+
248
+ ##### Pipeline Event Handling
249
+
250
+ Handle specific pipeline events:
251
+
252
+ ```ts
253
+ // Monitor CVE detection
254
+ examplePipeline.onCVEDetected('CVEAlert', {
255
+ target: new targets.SnsTopic(topic)
256
+ });
257
+
258
+ // Handle pipeline auto-disable events
259
+ examplePipeline.onImagePipelineAutoDisabled('PipelineDisabledAlert', {
260
+ target: new targets.LambdaFunction(lambdaFunction)
261
+ });
262
+ ```
263
+
264
+ #### Importing Image Pipelines
265
+
266
+ Reference existing pipelines created outside CDK:
267
+
268
+ ```ts
269
+ // Import by name
270
+ const existingPipelineByName = imagebuilder.ImagePipeline.fromImagePipelineName(
271
+ this,
272
+ 'ExistingPipelineByName',
273
+ 'my-existing-pipeline'
274
+ );
275
+
276
+ // Import by ARN
277
+ const existingPipelineByArn = imagebuilder.ImagePipeline.fromImagePipelineArn(
278
+ this,
279
+ 'ExistingPipelineByArn',
280
+ 'arn:aws:imagebuilder:us-east-1:123456789012:image-pipeline/imported-pipeline'
281
+ );
282
+
283
+ // Grant permissions to imported pipelines
284
+ const automationRole = new iam.Role(this, 'AutomationRole', {
285
+ assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com')
286
+ });
287
+
288
+ existingPipelineByName.grantStartExecution(automationRole);
289
+ existingPipelineByArn.grantRead(lambdaRole);
290
+ ```
291
+
292
+ ### Image
293
+
294
+ An image is the output resource created by Image Builder, consisting of an AMI or container image plus metadata such as
295
+ version, platform, and creation details. Images are used as base images for future builds and can be shared across AWS
296
+ accounts. While images are the output from image pipeline executions, they can also be created in an ad-hoc manner
297
+ outside a pipeline, defined as a standalone resource.
298
+
299
+ #### Image Basic Usage
300
+
301
+ Create a simple AMI-based image from an image recipe:
302
+
303
+ ```ts
304
+ const imageRecipe = new imagebuilder.ImageRecipe(this, 'MyImageRecipe', {
305
+ baseImage: imagebuilder.BaseImage.fromSsmParameterName(
306
+ '/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'
307
+ )
308
+ });
309
+
310
+ const amiImage = new imagebuilder.Image(this, 'MyAmiImage', {
311
+ recipe: imageRecipe
312
+ });
313
+ ```
314
+
315
+ Create a simple container image from a container recipe:
316
+
317
+ ```ts
318
+ const containerRecipe = new imagebuilder.ContainerRecipe(this, 'MyContainerRecipe', {
319
+ baseImage: imagebuilder.BaseContainerImage.fromDockerHub('amazonlinux', 'latest'),
320
+ targetRepository: imagebuilder.Repository.fromEcr(
321
+ ecr.Repository.fromRepositoryName(this, 'Repository', 'my-container-repo')
322
+ )
323
+ });
324
+
325
+ const containerImage = new imagebuilder.Image(this, 'MyContainerImage', {
326
+ recipe: containerRecipe
327
+ });
328
+ ```
329
+
330
+ #### AWS-Managed Images
331
+
332
+ ##### Pre-defined OS Images
333
+
334
+ Use AWS-managed images for common operating systems:
335
+
336
+ ```ts
337
+ // Amazon Linux 2023 AMI for x86_64
338
+ const amazonLinux2023Ami = imagebuilder.AmazonManagedImage.amazonLinux2023(this, 'AmazonLinux2023', {
339
+ imageType: imagebuilder.ImageType.AMI,
340
+ imageArchitecture: imagebuilder.ImageArchitecture.X86_64
341
+ });
342
+
343
+ // Ubuntu 22.04 AMI for ARM64
344
+ const ubuntu2204Ami = imagebuilder.AmazonManagedImage.ubuntuServer2204(this, 'Ubuntu2204', {
345
+ imageType: imagebuilder.ImageType.AMI,
346
+ imageArchitecture: imagebuilder.ImageArchitecture.ARM64
347
+ });
348
+
349
+ // Windows Server 2022 Full AMI
350
+ const windows2022Ami = imagebuilder.AmazonManagedImage.windowsServer2022Full(this, 'Windows2022', {
351
+ imageType: imagebuilder.ImageType.AMI,
352
+ imageArchitecture: imagebuilder.ImageArchitecture.X86_64
353
+ });
354
+
355
+ // Use as base image in recipe
356
+ const managedImageRecipe = new imagebuilder.ImageRecipe(this, 'ManagedImageRecipe', {
357
+ baseImage: amazonLinux2023Ami.toBaseImage()
358
+ });
359
+ ```
360
+
361
+ ##### Custom AWS-Managed Images
362
+
363
+ Import AWS-managed images by name or attributes:
364
+
365
+ ```ts
366
+ // Import by name
367
+ const managedImageByName = imagebuilder.AmazonManagedImage.fromAmazonManagedImageName(
368
+ this,
369
+ 'ManagedImageByName',
370
+ 'amazon-linux-2023-x86'
371
+ );
372
+
373
+ // Import by attributes with specific version
374
+ const managedImageByAttributes = imagebuilder.AmazonManagedImage.fromAmazonManagedImageAttributes(this, 'ManagedImageByAttributes', {
375
+ imageName: 'ubuntu-server-22-lts-x86',
376
+ imageVersion: '2024.11.25'
377
+ });
378
+ ```
379
+
380
+ #### Image Configuration
381
+
382
+ ##### Infrastructure and Distribution in Images
383
+
384
+ Configure custom infrastructure and distribution settings:
385
+
386
+ ```ts
387
+ const infrastructureConfiguration = new imagebuilder.InfrastructureConfiguration(this, 'Infrastructure', {
388
+ infrastructureConfigurationName: 'production-infrastructure',
389
+ instanceTypes: [
390
+ ec2.InstanceType.of(ec2.InstanceClass.COMPUTE7_INTEL, ec2.InstanceSize.LARGE)
391
+ ],
392
+ vpc: vpc,
393
+ subnetSelection: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }
394
+ });
395
+
396
+ const distributionConfiguration = new imagebuilder.DistributionConfiguration(this, 'Distribution');
397
+ distributionConfiguration.addAmiDistributions({
398
+ amiName: 'production-ami-{{ imagebuilder:buildDate }}',
399
+ amiTargetAccountIds: ['123456789012', '098765432109']
400
+ });
401
+
402
+ const productionImage = new imagebuilder.Image(this, 'ProductionImage', {
403
+ recipe: exampleImageRecipe,
404
+ infrastructureConfiguration: infrastructureConfiguration,
405
+ distributionConfiguration: distributionConfiguration
406
+ });
407
+ ```
408
+
409
+ ##### Logging Configuration
410
+
411
+ Configure custom CloudWatch log groups for image builds:
412
+
413
+ ```ts
414
+ const logGroup = new logs.LogGroup(this, 'ImageLogGroup', {
415
+ logGroupName: '/custom/imagebuilder/image/logs',
416
+ retention: logs.RetentionDays.ONE_MONTH
417
+ });
418
+
419
+ const loggedImage = new imagebuilder.Image(this, 'LoggedImage', {
420
+ recipe: exampleImageRecipe,
421
+ logGroup: logGroup
422
+ });
423
+ ```
424
+
425
+ ##### Workflow Integration in Images
426
+
427
+ Use workflows for custom build, test, and distribution processes:
428
+
429
+ ```ts
430
+ const imageWithWorkflows = new imagebuilder.Image(this, 'ImageWithWorkflows', {
431
+ recipe: exampleImageRecipe,
432
+ workflows: [
433
+ { workflow: imagebuilder.AwsManagedWorkflow.buildImage(this, 'BuildWorkflow') },
434
+ { workflow: imagebuilder.AwsManagedWorkflow.testImage(this, 'TestWorkflow') }
435
+ ]
436
+ });
437
+ ```
438
+
439
+ ##### Advanced Features in Images
440
+
441
+ Configure image scanning, metadata collection, and testing:
442
+
443
+ ```ts
444
+ const scanningRepository = new ecr.Repository(this, 'ScanningRepository');
445
+
446
+ const advancedContainerImage = new imagebuilder.Image(this, 'AdvancedContainerImage', {
447
+ recipe: exampleContainerRecipe,
448
+ imageScanningEnabled: true,
449
+ imageScanningEcrRepository: scanningRepository,
450
+ imageScanningEcrTags: ['security-scan', 'latest'],
451
+ enhancedImageMetadataEnabled: true,
452
+ imageTestsEnabled: false // Skip testing for faster builds
453
+ });
454
+ ```
455
+
456
+ #### Importing Images
457
+
458
+ Reference existing images created outside CDK:
459
+
460
+ ```ts
461
+ // Import by name
462
+ const existingImageByName = imagebuilder.Image.fromImageName(
463
+ this,
464
+ 'ExistingImageByName',
465
+ 'my-existing-image'
466
+ );
467
+
468
+ // Import by ARN
469
+ const existingImageByArn = imagebuilder.Image.fromImageArn(
470
+ this,
471
+ 'ExistingImageByArn',
472
+ 'arn:aws:imagebuilder:us-east-1:123456789012:image/imported-image/1.0.0'
473
+ );
474
+
475
+ // Import by attributes
476
+ const existingImageByAttributes = imagebuilder.Image.fromImageAttributes(this, 'ExistingImageByAttributes', {
477
+ imageName: 'shared-base-image',
478
+ imageVersion: '2024.11.25'
479
+ });
480
+
481
+ // Grant permissions to imported images
482
+ const role = new iam.Role(this, 'ImageAccessRole', {
483
+ assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com')
484
+ });
485
+
486
+ existingImageByName.grantRead(role);
487
+ existingImageByArn.grant(role, 'imagebuilder:GetImage', 'imagebuilder:ListImagePackages');
488
+ ```
489
+
39
490
  ### Image Recipe
40
491
 
41
492
  #### Image Recipe Basic Usage
@@ -146,7 +597,7 @@ const imageRecipe = new imagebuilder.ImageRecipe(this, 'ComponentImageRecipe', {
146
597
  Use pre-built AWS components:
147
598
 
148
599
  ```ts
149
- const imageRecipe = new imagebuilder.ImageRecipe(this, 'AwsManagedImageRecipe', {
600
+ const imageRecipe = new imagebuilder.ImageRecipe(this, 'AmazonManagedImageRecipe', {
150
601
  baseImage: imagebuilder.BaseImage.fromSsmParameterName(
151
602
  '/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'
152
603
  ),
@@ -853,7 +1304,8 @@ containerDistributionConfiguration.addContainerDistributions({
853
1304
 
854
1305
  ### Workflow
855
1306
 
856
- Workflows define the sequence of steps that Image Builder performs during image creation. There are three workflow types: BUILD (image building), TEST (testing images), and DISTRIBUTION (distributing container images).
1307
+ Workflows define the sequence of steps that Image Builder performs during image creation. There are three workflow
1308
+ types: BUILD (image building), TEST (testing images), and DISTRIBUTION (distributing container images).
857
1309
 
858
1310
  #### Basic Workflow Usage
859
1311
 
@@ -1014,7 +1466,8 @@ const workflowFromS3 = new imagebuilder.Workflow(this, 'S3Workflow', {
1014
1466
 
1015
1467
  #### Encrypt workflow data with a KMS key
1016
1468
 
1017
- You can encrypt workflow data with a KMS key, so that only principals with access to decrypt with the key are able to access the workflow data.
1469
+ You can encrypt workflow data with a KMS key, so that only principals with access to decrypt with the key are able to
1470
+ access the workflow data.
1018
1471
 
1019
1472
  ```ts
1020
1473
  const workflow = new imagebuilder.Workflow(this, 'EncryptedWorkflow', {
@@ -1074,3 +1527,343 @@ const testContainerWorkflow = imagebuilder.AwsManagedWorkflow.testContainer(this
1074
1527
  // Distribution workflows
1075
1528
  const distributeContainerWorkflow = imagebuilder.AwsManagedWorkflow.distributeContainer(this, 'DistributeContainer');
1076
1529
  ```
1530
+
1531
+ ### Lifecycle Policy
1532
+
1533
+ Lifecycle policies help you manage the retention and cleanup of Image Builder resources automatically. These policies
1534
+ define rules for deprecating or deleting old image versions, managing AMI snapshots, and controlling resource costs by
1535
+ removing unused images based on age, count, or other criteria.
1536
+
1537
+ #### Lifecycle Policy Basic Usage
1538
+
1539
+ Create a lifecycle policy to automatically delete old AMI images after 30 days:
1540
+
1541
+ ```ts
1542
+ const lifecyclePolicy = new imagebuilder.LifecyclePolicy(this, 'MyLifecyclePolicy', {
1543
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1544
+ details: [
1545
+ {
1546
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1547
+ filter: { ageFilter: { age: Duration.days(30) } }
1548
+ }
1549
+ ],
1550
+ resourceSelection: {
1551
+ tags: { Environment: 'development' }
1552
+ }
1553
+ });
1554
+ ```
1555
+
1556
+ Create a lifecycle policy to keep only the 10 most recent container images:
1557
+
1558
+ ```ts
1559
+ const containerLifecyclePolicy = new imagebuilder.LifecyclePolicy(this, 'ContainerLifecyclePolicy', {
1560
+ resourceType: imagebuilder.LifecyclePolicyResourceType.CONTAINER_IMAGE,
1561
+ details: [
1562
+ {
1563
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1564
+ filter: { countFilter: { count: 10 } }
1565
+ }
1566
+ ],
1567
+ resourceSelection: {
1568
+ tags: { Application: 'web-app' }
1569
+ }
1570
+ });
1571
+ ```
1572
+
1573
+ #### Lifecycle Policy Resource Selection
1574
+
1575
+ ##### Tag-Based Resource Selection
1576
+
1577
+ Apply lifecycle policies to images with specific tags:
1578
+
1579
+ ```ts
1580
+ const tagBasedPolicy = new imagebuilder.LifecyclePolicy(this, 'TagBasedPolicy', {
1581
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1582
+ details: [
1583
+ {
1584
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1585
+ filter: { ageFilter: { age: Duration.days(90) } }
1586
+ }
1587
+ ],
1588
+ resourceSelection: {
1589
+ tags: {
1590
+ Environment: 'staging',
1591
+ Team: 'backend'
1592
+ }
1593
+ }
1594
+ });
1595
+ ```
1596
+
1597
+ ##### Recipe-Based Resource Selection
1598
+
1599
+ Apply lifecycle policies to specific image or container recipes:
1600
+
1601
+ ```ts
1602
+ const imageRecipe = new imagebuilder.ImageRecipe(this, 'MyImageRecipe', {
1603
+ baseImage: imagebuilder.BaseImage.fromSsmParameterName(
1604
+ '/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'
1605
+ )
1606
+ });
1607
+
1608
+ const containerRecipe = new imagebuilder.ContainerRecipe(this, 'MyContainerRecipe', {
1609
+ baseImage: imagebuilder.BaseContainerImage.fromDockerHub('amazonlinux', 'latest'),
1610
+ targetRepository: imagebuilder.Repository.fromEcr(
1611
+ ecr.Repository.fromRepositoryName(this, 'Repository', 'my-container-repo')
1612
+ )
1613
+ });
1614
+
1615
+ const recipeBasedPolicy = new imagebuilder.LifecyclePolicy(this, 'RecipeBasedPolicy', {
1616
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1617
+ details: [
1618
+ {
1619
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1620
+ filter: { countFilter: { count: 5 } }
1621
+ }
1622
+ ],
1623
+ resourceSelection: {
1624
+ recipes: [imageRecipe, containerRecipe]
1625
+ }
1626
+ });
1627
+ ```
1628
+
1629
+ #### Lifecycle Policy Rules
1630
+
1631
+ ##### Age-Based Rules
1632
+
1633
+ Delete images older than a specific time period:
1634
+
1635
+ ```ts
1636
+ const ageBasedPolicy = new imagebuilder.LifecyclePolicy(this, 'AgeBasedPolicy', {
1637
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1638
+ details: [
1639
+ {
1640
+ action: {
1641
+ type: imagebuilder.LifecyclePolicyActionType.DELETE,
1642
+ includeAmis: true,
1643
+ includeSnapshots: true
1644
+ },
1645
+ filter: {
1646
+ ageFilter: {
1647
+ age: Duration.days(60),
1648
+ retainAtLeast: 3 // Always keep at least 3 images
1649
+ }
1650
+ }
1651
+ }
1652
+ ],
1653
+ resourceSelection: {
1654
+ tags: { Environment: 'testing' }
1655
+ }
1656
+ });
1657
+ ```
1658
+
1659
+ ##### Count-Based Rules
1660
+
1661
+ Keep only a specific number of the most recent images:
1662
+
1663
+ ```ts
1664
+ const countBasedPolicy = new imagebuilder.LifecyclePolicy(this, 'CountBasedPolicy', {
1665
+ resourceType: imagebuilder.LifecyclePolicyResourceType.CONTAINER_IMAGE,
1666
+ details: [
1667
+ {
1668
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1669
+ filter: { countFilter: { count: 15 } } // Keep only the 15 most recent images
1670
+ }
1671
+ ],
1672
+ resourceSelection: {
1673
+ tags: { Application: 'microservice' }
1674
+ }
1675
+ });
1676
+ ```
1677
+
1678
+ ##### Multiple Lifecycle Rules
1679
+
1680
+ Implement a graduated approach with multiple actions:
1681
+
1682
+ ```ts
1683
+ const graduatedPolicy = new imagebuilder.LifecyclePolicy(this, 'GraduatedPolicy', {
1684
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1685
+ details: [
1686
+ {
1687
+ // First: Deprecate images after 30 days
1688
+ action: {
1689
+ type: imagebuilder.LifecyclePolicyActionType.DEPRECATE,
1690
+ includeAmis: true
1691
+ },
1692
+ filter: {
1693
+ ageFilter: {
1694
+ age: Duration.days(30),
1695
+ retainAtLeast: 5
1696
+ }
1697
+ }
1698
+ },
1699
+ {
1700
+ // Second: Disable images after 60 days
1701
+ action: {
1702
+ type: imagebuilder.LifecyclePolicyActionType.DISABLE,
1703
+ includeAmis: true
1704
+ },
1705
+ filter: {
1706
+ ageFilter: {
1707
+ age: Duration.days(60),
1708
+ retainAtLeast: 3
1709
+ }
1710
+ }
1711
+ },
1712
+ {
1713
+ // Finally: Delete images after 90 days
1714
+ action: {
1715
+ type: imagebuilder.LifecyclePolicyActionType.DELETE,
1716
+ includeAmis: true,
1717
+ includeSnapshots: true
1718
+ },
1719
+ filter: {
1720
+ ageFilter: {
1721
+ age: Duration.days(90),
1722
+ retainAtLeast: 1
1723
+ }
1724
+ }
1725
+ }
1726
+ ],
1727
+ resourceSelection: {
1728
+ tags: { Environment: 'production' }
1729
+ }
1730
+ });
1731
+ ```
1732
+
1733
+ #### Lifecycle Policy Exclusion Rules
1734
+
1735
+ ##### AMI Exclusion Rules
1736
+
1737
+ Exclude specific AMIs from lifecycle actions based on various criteria:
1738
+
1739
+ ```ts
1740
+ const excludeAmisPolicy = new imagebuilder.LifecyclePolicy(this, 'ExcludeAmisPolicy', {
1741
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1742
+ details: [
1743
+ {
1744
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1745
+ filter: { ageFilter: { age: Duration.days(30) } },
1746
+ exclusionRules: {
1747
+ amiExclusionRules: {
1748
+ isPublic: true, // Exclude public AMIs
1749
+ lastLaunched: Duration.days(7), // Exclude AMIs launched in last 7 days
1750
+ regions: ['us-west-2', 'eu-west-1'], // Exclude AMIs in specific regions
1751
+ sharedAccounts: ['123456789012'], // Exclude AMIs shared with specific accounts
1752
+ tags: {
1753
+ Protected: 'true',
1754
+ Environment: 'production'
1755
+ }
1756
+ }
1757
+ }
1758
+ }
1759
+ ],
1760
+ resourceSelection: {
1761
+ tags: { Team: 'infrastructure' }
1762
+ }
1763
+ });
1764
+ ```
1765
+
1766
+ ##### Image Exclusion Rules
1767
+
1768
+ Exclude Image Builder images with protective tags:
1769
+
1770
+ ```ts
1771
+ const excludeImagesPolicy = new imagebuilder.LifecyclePolicy(this, 'ExcludeImagesPolicy', {
1772
+ resourceType: imagebuilder.LifecyclePolicyResourceType.CONTAINER_IMAGE,
1773
+ details: [
1774
+ {
1775
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1776
+ filter: { countFilter: { count: 20 } },
1777
+ exclusionRules: {
1778
+ imageExclusionRules: {
1779
+ tags: {
1780
+ DoNotDelete: 'true',
1781
+ Critical: 'baseline'
1782
+ }
1783
+ }
1784
+ }
1785
+ }
1786
+ ],
1787
+ resourceSelection: {
1788
+ tags: { Application: 'frontend' }
1789
+ }
1790
+ });
1791
+ ```
1792
+
1793
+ #### Advanced Lifecycle Configuration
1794
+
1795
+ ##### Custom Execution Roles
1796
+
1797
+ Provide your own IAM execution role with specific permissions:
1798
+
1799
+ ```ts
1800
+ const executionRole = new iam.Role(this, 'LifecycleExecutionRole', {
1801
+ assumedBy: new iam.ServicePrincipal('imagebuilder.amazonaws.com'),
1802
+ managedPolicies: [
1803
+ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/EC2ImageBuilderLifecycleExecutionPolicy')
1804
+ ]
1805
+ });
1806
+
1807
+ const customRolePolicy = new imagebuilder.LifecyclePolicy(this, 'CustomRolePolicy', {
1808
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1809
+ executionRole: executionRole,
1810
+ details: [
1811
+ {
1812
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1813
+ filter: { ageFilter: { age: Duration.days(45) } }
1814
+ }
1815
+ ],
1816
+ resourceSelection: {
1817
+ tags: { Environment: 'development' }
1818
+ }
1819
+ });
1820
+ ```
1821
+
1822
+ ##### Lifecycle Policy Status
1823
+
1824
+ Control whether the lifecycle policy is active:
1825
+
1826
+ ```ts
1827
+ const disabledPolicy = new imagebuilder.LifecyclePolicy(this, 'DisabledPolicy', {
1828
+ lifecyclePolicyName: 'my-disabled-policy',
1829
+ description: 'A lifecycle policy that is temporarily disabled',
1830
+ status: imagebuilder.LifecyclePolicyStatus.DISABLED,
1831
+ resourceType: imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
1832
+ details: [
1833
+ {
1834
+ action: { type: imagebuilder.LifecyclePolicyActionType.DELETE },
1835
+ filter: { ageFilter: { age: Duration.days(30) } }
1836
+ }
1837
+ ],
1838
+ resourceSelection: {
1839
+ tags: { Environment: 'testing' }
1840
+ },
1841
+ tags: {
1842
+ Owner: 'DevOps',
1843
+ CostCenter: 'Engineering'
1844
+ }
1845
+ });
1846
+ ```
1847
+
1848
+ ##### Importing Lifecycle Policies
1849
+
1850
+ Reference lifecycle policies created outside CDK:
1851
+
1852
+ ```ts
1853
+ // Import by name
1854
+ const importedByName = imagebuilder.LifecyclePolicy.fromLifecyclePolicyName(
1855
+ this,
1856
+ 'ImportedByName',
1857
+ 'existing-lifecycle-policy'
1858
+ );
1859
+
1860
+ // Import by ARN
1861
+ const importedByArn = imagebuilder.LifecyclePolicy.fromLifecyclePolicyArn(
1862
+ this,
1863
+ 'ImportedByArn',
1864
+ 'arn:aws:imagebuilder:us-east-1:123456789012:lifecycle-policy/my-policy'
1865
+ );
1866
+
1867
+ importedByName.grantRead(lambdaRole);
1868
+ importedByArn.grant(lambdaRole, 'imagebuilder:UpdateLifecyclePolicy');
1869
+ ```