Skip to content

Commit eee3ae6

Browse files
authored
feat(imagebuilder-alpha): add support for Image Construct (#36154)
### Issue aws/aws-cdk-rfcs#789 ### Reason for this change This change adds a new alpha module for EC2 Image Builder L2 Constructs (@aws-cdk/aws-imagebuilder-alpha), as outlined in aws/aws-cdk-rfcs#789. This PR specifically implements the Image construct. ### Description of changes This change implements the Image construct, which is a higher-level construct of [CfnImage](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_imagebuilder.CfnImage.html). #### Example ```ts const image = new Image(this, 'Image', { recipe: ImageRecipe.fromImageRecipeAttributes(this, 'ImageRecipe', { imageRecipeName: 'test-image-recipe' }), infrastructureConfiguration: InfrastructureConfiguration.fromInfrastructureConfigurationName( this, 'InfrastructureConfiguration', 'test-infrastructure-configuration', ), distributionConfiguration: DistributionConfiguration.fromDistributionConfigurationName( this, 'DistributionConfiguration', 'test-distribution-configuration', ), workflows: [{ workflow: AwsManagedWorkflow.buildImage(this, 'BuildImageWorkflow') }], executionRole: iam.Role.fromRoleName(this, 'ExecutionRole', 'test-execution-role'), logGroup: logs.LogGroup.fromLogGroupName(this, 'LogGroup', 'test-log-group'), imageTestsEnabled: true, imageScanningEnabled: true, enhancedImageMetadataEnabled: true, tags: { key1: 'value1', key2: 'value2' }, }); ``` ### Describe any new or updated permissions being added N/A - new L2 construct in alpha module ### Description of how you validated changes Validated with unit tests and integration tests. Manually verified generated CFN templates as well. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 6e7ca2b commit eee3ae6

File tree

59 files changed

+9931
-38
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+9931
-38
lines changed

packages/@aws-cdk/aws-imagebuilder-alpha/README.md

Lines changed: 216 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ test phase during the test stage.
3838

3939
### Image Pipeline
4040

41-
An image pipeline provides the automation framework for building secure AMIs and container images. The pipeline orchestrates the entire image creation process by combining an image recipe or container recipe with infrastructure configuration and distribution configuration. Pipelines can run on a schedule or be triggered manually, and they manage the build, test, and distribution phases automatically.
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.
4245

4346
#### Image Pipeline Basic Usage
4447

@@ -139,7 +142,7 @@ const advancedSchedulePipeline = new imagebuilder.ImagePipeline(this, 'AdvancedS
139142

140143
#### Image Pipeline Configuration
141144

142-
##### Infrastructure and Distribution
145+
##### Infrastructure and Distribution in Image Pipelines
143146

144147
Configure custom infrastructure and distribution settings:
145148

@@ -177,7 +180,7 @@ const pipelineLogGroup = new logs.LogGroup(this, 'PipelineLogGroup', {
177180
});
178181

179182
const imageLogGroup = new logs.LogGroup(this, 'ImageLogGroup', {
180-
logGroupName: '/custom/imagebuilder/image/logs',
183+
logGroupName: '/custom/imagebuilder/image/logs',
181184
retention: logs.RetentionDays.ONE_WEEK
182185
});
183186

@@ -188,7 +191,7 @@ const loggedPipeline = new imagebuilder.ImagePipeline(this, 'LoggedPipeline', {
188191
});
189192
```
190193

191-
##### Workflow Integration
194+
##### Workflow Integration in Image Pipelines
192195

193196
Use AWS-managed workflows for common pipeline phases:
194197

@@ -215,7 +218,7 @@ const containerWorkflowPipeline = new imagebuilder.ImagePipeline(this, 'Containe
215218
});
216219
```
217220

218-
##### Advanced Features
221+
##### Advanced Features in Image Pipelines
219222

220223
Configure image scanning for container pipelines:
221224

@@ -286,6 +289,204 @@ existingPipelineByName.grantStartExecution(automationRole);
286289
existingPipelineByArn.grantRead(lambdaRole);
287290
```
288291

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+
289490
### Image Recipe
290491

291492
#### Image Recipe Basic Usage
@@ -396,7 +597,7 @@ const imageRecipe = new imagebuilder.ImageRecipe(this, 'ComponentImageRecipe', {
396597
Use pre-built AWS components:
397598

398599
```ts
399-
const imageRecipe = new imagebuilder.ImageRecipe(this, 'AwsManagedImageRecipe', {
600+
const imageRecipe = new imagebuilder.ImageRecipe(this, 'AmazonManagedImageRecipe', {
400601
baseImage: imagebuilder.BaseImage.fromSsmParameterName(
401602
'/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'
402603
),
@@ -1103,7 +1304,8 @@ containerDistributionConfiguration.addContainerDistributions({
11031304

11041305
### Workflow
11051306

1106-
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).
11071309

11081310
#### Basic Workflow Usage
11091311

@@ -1264,7 +1466,8 @@ const workflowFromS3 = new imagebuilder.Workflow(this, 'S3Workflow', {
12641466

12651467
#### Encrypt workflow data with a KMS key
12661468

1267-
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.
12681471

12691472
```ts
12701473
const workflow = new imagebuilder.Workflow(this, 'EncryptedWorkflow', {
@@ -1327,7 +1530,9 @@ const distributeContainerWorkflow = imagebuilder.AwsManagedWorkflow.distributeCo
13271530

13281531
### Lifecycle Policy
13291532

1330-
Lifecycle policies help you manage the retention and cleanup of Image Builder resources automatically. These policies define rules for deprecating or deleting old image versions, managing AMI snapshots, and controlling resource costs by removing unused images based on age, count, or other criteria.
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.
13311536

13321537
#### Lifecycle Policy Basic Usage
13331538

@@ -1642,7 +1847,7 @@ const disabledPolicy = new imagebuilder.LifecyclePolicy(this, 'DisabledPolicy',
16421847

16431848
##### Importing Lifecycle Policies
16441849

1645-
Reference lifecycle policies created outside of CDK:
1850+
Reference lifecycle policies created outside CDK:
16461851

16471852
```ts
16481853
// Import by name
@@ -1660,5 +1865,5 @@ const importedByArn = imagebuilder.LifecyclePolicy.fromLifecyclePolicyArn(
16601865
);
16611866

16621867
importedByName.grantRead(lambdaRole);
1663-
importedByArn.grant(lambdaRole, 'imagebuilder:PutLifecyclePolicy');
1868+
importedByArn.grant(lambdaRole, 'imagebuilder:UpdateLifecyclePolicy');
16641869
```

packages/@aws-cdk/aws-imagebuilder-alpha/awslint.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"exclude": [
33
"props-no-arn-refs:@aws-cdk/aws-imagebuilder-alpha.InfrastructureConfigurationProps.ec2InstanceHostResourceGroupArn",
4+
"props-physical-name:@aws-cdk/aws-imagebuilder-alpha.ImageProps",
45
"no-unused-type:@aws-cdk/aws-imagebuilder-alpha.ContainerType",
56
"no-unused-type:@aws-cdk/aws-imagebuilder-alpha.WorkflowAction",
67
"no-unused-type:@aws-cdk/aws-imagebuilder-alpha.WorkflowOnFailure",

0 commit comments

Comments
 (0)