@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/.jsii +9966 -4578
- package/.jsii.tabl.json.gz +0 -0
- package/.warnings.jsii.js +221 -1
- package/README.md +796 -3
- package/awslint.json +1 -0
- package/lib/amazon-managed-image.d.ts +242 -0
- package/lib/amazon-managed-image.js +522 -0
- package/lib/base-image.d.ts +13 -0
- package/lib/base-image.js +39 -4
- package/lib/component.js +8 -8
- package/lib/container-recipe.js +4 -4
- package/lib/distribution-configuration.js +2 -2
- package/lib/image-pipeline.d.ts +465 -0
- package/lib/image-pipeline.js +469 -0
- package/lib/image-recipe.js +1 -1
- package/lib/image.d.ts +339 -0
- package/lib/image.js +357 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +5 -1
- package/lib/infrastructure-configuration.d.ts +1 -1
- package/lib/infrastructure-configuration.js +2 -2
- package/lib/lifecycle-policy.d.ts +409 -0
- package/lib/lifecycle-policy.js +459 -0
- package/lib/os-version.js +1 -1
- package/lib/private/constants.d.ts +7 -0
- package/lib/private/constants.js +11 -0
- package/lib/private/image-and-pipeline-props-helper.d.ts +26 -0
- package/lib/private/image-and-pipeline-props-helper.js +67 -0
- package/lib/private/policy-helper.d.ts +21 -0
- package/lib/private/policy-helper.js +420 -0
- package/lib/recipe-base.js +1 -1
- package/lib/workflow.d.ts +63 -0
- package/lib/workflow.js +51 -6
- package/package.json +6 -6
- package/rosetta/default.ts-fixture +41 -2
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, '
|
|
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
|
|
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
|
|
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
|
+
```
|