EC2 Image Builder Construct Library
---The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the Semantic Versioning model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package.
This module is part of the AWS Cloud Development Kit project.
README
Amazon EC2 Image Builder is a fully managed AWS service that helps you automate the creation, management, and deployment of customized, secure, and up-to-date server images. You can use Image Builder to create Amazon Machine Images (AMIs) and container images for use across AWS Regions.
This module is part of the AWS Cloud Development Kit project. It allows you to define Image Builder pipelines, images, recipes, components, workflows, and lifecycle policies. A component defines the sequence of steps required to customize an instance during image creation (build component) or test an instance launched from the created image (test component). Components are created from declarative YAML or JSON documents that describe runtime configuration for building, validating, or testing instances. Components are included when added to the image recipe or container recipe for an image build.
EC2 Image Builder supports AWS-managed components for common tasks, AWS Marketplace components, and custom components that you create. Components run during specific workflow phases: build and validate phases during the build stage, and test phase during the test stage.
Image Pipeline
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.
Image Pipeline Basic Usage
Create a simple AMI pipeline with just an image recipe:
image_recipe = imagebuilder.ImageRecipe(self, "MyImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
)
image_pipeline = imagebuilder.ImagePipeline(self, "MyImagePipeline",
recipe=example_image_recipe
)
Create a simple container pipeline with just a container recipe:
container_recipe = imagebuilder.ContainerRecipe(self, "MyContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo"))
)
container_pipeline = imagebuilder.ImagePipeline(self, "MyContainerPipeline",
recipe=example_container_recipe
)
Image Pipeline Scheduling
Manual Pipeline Execution
Create a pipeline that runs only when manually triggered:
manual_pipeline = imagebuilder.ImagePipeline(self, "ManualPipeline",
image_pipeline_name="my-manual-pipeline",
description="Pipeline triggered manually for production builds",
recipe=example_image_recipe
)
# Grant Lambda function permission to trigger the pipeline
manual_pipeline.grant_start_execution(lambda_role)
Automated Pipeline Scheduling
Schedule a pipeline to run automatically using cron expressions:
weekly_pipeline = imagebuilder.ImagePipeline(self, "WeeklyPipeline",
image_pipeline_name="weekly-build-pipeline",
recipe=example_image_recipe,
schedule=imagebuilder.ImagePipelineSchedule(
expression=events.Schedule.cron(
minute="0",
hour="6",
week_day="MON"
)
)
)
Use rate expressions for regular intervals:
daily_pipeline = imagebuilder.ImagePipeline(self, "DailyPipeline",
recipe=example_container_recipe,
schedule=imagebuilder.ImagePipelineSchedule(
expression=events.Schedule.rate(Duration.days(1))
)
)
Pipeline Schedule Configuration
Configure advanced scheduling options:
advanced_schedule_pipeline = imagebuilder.ImagePipeline(self, "AdvancedSchedulePipeline",
recipe=example_image_recipe,
schedule=imagebuilder.ImagePipelineSchedule(
expression=events.Schedule.rate(Duration.days(7)),
# Only trigger when dependencies are updated (new base images, components, etc.)
start_condition=imagebuilder.ScheduleStartCondition.EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE,
# Automatically disable after 3 consecutive failures
auto_disable_failure_count=3
),
# Start enabled
status=imagebuilder.ImagePipelineStatus.ENABLED
)
Image Pipeline Configuration
Infrastructure and Distribution in Image Pipelines
Configure custom infrastructure and distribution settings:
infrastructure_configuration = imagebuilder.InfrastructureConfiguration(self, "Infrastructure",
infrastructure_configuration_name="production-infrastructure",
instance_types=[
ec2.InstanceType.of(ec2.InstanceClass.COMPUTE7_INTEL, ec2.InstanceSize.LARGE)
],
vpc=vpc,
subnet_selection=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS)
)
distribution_configuration = imagebuilder.DistributionConfiguration(self, "Distribution")
distribution_configuration.add_ami_distributions(
ami_name="production-ami-{{ imagebuilder:buildDate }}",
ami_target_account_ids=["123456789012", "098765432109"]
)
production_pipeline = imagebuilder.ImagePipeline(self, "ProductionPipeline",
recipe=example_image_recipe,
infrastructure_configuration=infrastructure_configuration,
distribution_configuration=distribution_configuration
)
Pipeline Logging Configuration
Configure custom CloudWatch log groups for pipeline and image logs:
pipeline_log_group = logs.LogGroup(self, "PipelineLogGroup",
log_group_name="/custom/imagebuilder/pipeline/logs",
retention=logs.RetentionDays.ONE_MONTH
)
image_log_group = logs.LogGroup(self, "ImageLogGroup",
log_group_name="/custom/imagebuilder/image/logs",
retention=logs.RetentionDays.ONE_WEEK
)
logged_pipeline = imagebuilder.ImagePipeline(self, "LoggedPipeline",
recipe=example_image_recipe,
image_pipeline_log_group=pipeline_log_group,
image_log_group=image_log_group
)
Workflow Integration in Image Pipelines
Use AWS-managed workflows for common pipeline phases:
workflow_pipeline = imagebuilder.ImagePipeline(self, "WorkflowPipeline",
recipe=example_image_recipe,
workflows=[imagebuilder.WorkflowConfiguration(workflow=imagebuilder.AmazonManagedWorkflow.build_image(self, "BuildWorkflow")), imagebuilder.WorkflowConfiguration(workflow=imagebuilder.AmazonManagedWorkflow.test_image(self, "TestWorkflow"))
]
)
For container pipelines, use container-specific workflows:
container_workflow_pipeline = imagebuilder.ImagePipeline(self, "ContainerWorkflowPipeline",
recipe=example_container_recipe,
workflows=[imagebuilder.WorkflowConfiguration(workflow=imagebuilder.AmazonManagedWorkflow.build_container(self, "BuildContainer")), imagebuilder.WorkflowConfiguration(workflow=imagebuilder.AmazonManagedWorkflow.test_container(self, "TestContainer")), imagebuilder.WorkflowConfiguration(workflow=imagebuilder.AmazonManagedWorkflow.distribute_container(self, "DistributeContainer"))
]
)
Advanced Features in Image Pipelines
Configure image scanning for container pipelines:
scanning_repository = ecr.Repository(self, "ScanningRepo")
scanned_container_pipeline = imagebuilder.ImagePipeline(self, "ScannedContainerPipeline",
recipe=example_container_recipe,
image_scanning_enabled=True,
image_scanning_ecr_repository=scanning_repository,
image_scanning_ecr_tags=["security-scan", "latest"]
)
Control metadata collection and testing:
controlled_pipeline = imagebuilder.ImagePipeline(self, "ControlledPipeline",
recipe=example_image_recipe,
enhanced_image_metadata_enabled=True, # Collect detailed OS and package info
image_tests_enabled=False
)
Image Pipeline Events
Pipeline Event Handling
Handle specific pipeline events:
# Monitor CVE detection
example_pipeline.on_cVEDetected("CVEAlert",
target=targets.SnsTopic(topic)
)
# Handle pipeline auto-disable events
example_pipeline.on_image_pipeline_auto_disabled("PipelineDisabledAlert",
target=targets.LambdaFunction(lambda_function)
)
Importing Image Pipelines
Reference existing pipelines created outside CDK:
# Import by name
existing_pipeline_by_name = imagebuilder.ImagePipeline.from_image_pipeline_name(self, "ExistingPipelineByName", "my-existing-pipeline")
# Import by ARN
existing_pipeline_by_arn = imagebuilder.ImagePipeline.from_image_pipeline_arn(self, "ExistingPipelineByArn", "arn:aws:imagebuilder:us-east-1:123456789012:image-pipeline/imported-pipeline")
# Grant permissions to imported pipelines
automation_role = iam.Role(self, "AutomationRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com")
)
existing_pipeline_by_name.grant_start_execution(automation_role)
existing_pipeline_by_arn.grant_read(lambda_role)
Image
An image is the output resource created by Image Builder, consisting of an AMI or container image plus metadata such as version, platform, and creation details. Images are used as base images for future builds and can be shared across AWS accounts. While images are the output from image pipeline executions, they can also be created in an ad-hoc manner outside a pipeline, defined as a standalone resource.
Image Basic Usage
Create a simple AMI-based image from an image recipe:
image_recipe = imagebuilder.ImageRecipe(self, "MyImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
)
ami_image = imagebuilder.Image(self, "MyAmiImage",
recipe=image_recipe
)
Create a simple container image from a container recipe:
container_recipe = imagebuilder.ContainerRecipe(self, "MyContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo"))
)
container_image = imagebuilder.Image(self, "MyContainerImage",
recipe=container_recipe
)
AWS-Managed Images
Pre-defined OS Images
Use AWS-managed images for common operating systems:
# Amazon Linux 2023 AMI for x86_64
amazon_linux2023_ami = imagebuilder.AmazonManagedImage.amazon_linux2023(self, "AmazonLinux2023",
image_type=imagebuilder.ImageType.AMI,
image_architecture=imagebuilder.ImageArchitecture.X86_64
)
# Ubuntu 22.04 AMI for ARM64
ubuntu2204_ami = imagebuilder.AmazonManagedImage.ubuntu_server2204(self, "Ubuntu2204",
image_type=imagebuilder.ImageType.AMI,
image_architecture=imagebuilder.ImageArchitecture.ARM64
)
# Windows Server 2022 Full AMI
windows2022_ami = imagebuilder.AmazonManagedImage.windows_server2022_full(self, "Windows2022",
image_type=imagebuilder.ImageType.AMI,
image_architecture=imagebuilder.ImageArchitecture.X86_64
)
# Use as base image in recipe
managed_image_recipe = imagebuilder.ImageRecipe(self, "ManagedImageRecipe",
base_image=amazon_linux2023_ami.to_base_image()
)
Custom AWS-Managed Images
Import AWS-managed images by name or attributes:
# Import by name
managed_image_by_name = imagebuilder.AmazonManagedImage.from_amazon_managed_image_name(self, "ManagedImageByName", "amazon-linux-2023-x86")
# Import by attributes with specific version
managed_image_by_attributes = imagebuilder.AmazonManagedImage.from_amazon_managed_image_attributes(self, "ManagedImageByAttributes",
image_name="ubuntu-server-22-lts-x86",
image_version="2024.11.25"
)
Image Configuration
Infrastructure and Distribution in Images
Configure custom infrastructure and distribution settings:
infrastructure_configuration = imagebuilder.InfrastructureConfiguration(self, "Infrastructure",
infrastructure_configuration_name="production-infrastructure",
instance_types=[
ec2.InstanceType.of(ec2.InstanceClass.COMPUTE7_INTEL, ec2.InstanceSize.LARGE)
],
vpc=vpc,
subnet_selection=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS)
)
distribution_configuration = imagebuilder.DistributionConfiguration(self, "Distribution")
distribution_configuration.add_ami_distributions(
ami_name="production-ami-{{ imagebuilder:buildDate }}",
ami_target_account_ids=["123456789012", "098765432109"]
)
production_image = imagebuilder.Image(self, "ProductionImage",
recipe=example_image_recipe,
infrastructure_configuration=infrastructure_configuration,
distribution_configuration=distribution_configuration
)
Logging Configuration
Configure custom CloudWatch log groups for image builds:
log_group = logs.LogGroup(self, "ImageLogGroup",
log_group_name="/custom/imagebuilder/image/logs",
retention=logs.RetentionDays.ONE_MONTH
)
logged_image = imagebuilder.Image(self, "LoggedImage",
recipe=example_image_recipe,
log_group=log_group
)
Workflow Integration in Images
Use workflows for custom build, test, and distribution processes:
image_with_workflows = imagebuilder.Image(self, "ImageWithWorkflows",
recipe=example_image_recipe,
workflows=[imagebuilder.WorkflowConfiguration(workflow=imagebuilder.AmazonManagedWorkflow.build_image(self, "BuildWorkflow")), imagebuilder.WorkflowConfiguration(workflow=imagebuilder.AmazonManagedWorkflow.test_image(self, "TestWorkflow"))
]
)
Advanced Features in Images
Configure image scanning, metadata collection, and testing:
scanning_repository = ecr.Repository(self, "ScanningRepository")
advanced_container_image = imagebuilder.Image(self, "AdvancedContainerImage",
recipe=example_container_recipe,
image_scanning_enabled=True,
image_scanning_ecr_repository=scanning_repository,
image_scanning_ecr_tags=["security-scan", "latest"],
enhanced_image_metadata_enabled=True,
image_tests_enabled=False
)
Importing Images
Reference existing images created outside CDK:
# Import by name
existing_image_by_name = imagebuilder.Image.from_image_name(self, "ExistingImageByName", "my-existing-image")
# Import by ARN
existing_image_by_arn = imagebuilder.Image.from_image_arn(self, "ExistingImageByArn", "arn:aws:imagebuilder:us-east-1:123456789012:image/imported-image/1.0.0")
# Import by attributes
existing_image_by_attributes = imagebuilder.Image.from_image_attributes(self, "ExistingImageByAttributes",
image_name="shared-base-image",
image_version="2024.11.25"
)
# Grant permissions to imported images
role = iam.Role(self, "ImageAccessRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com")
)
existing_image_by_name.grant_read(role)
existing_image_by_arn.grant(role, "imagebuilder:GetImage", "imagebuilder:ListImagePackages")
Image Recipe
Image Recipe Basic Usage
Create an image recipe with the required base image:
image_recipe = imagebuilder.ImageRecipe(self, "MyImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
)
Image Recipe Base Images
To create a recipe, you have to select a base image to build and customize from. This base image can be referenced from various sources, such as from SSM parameters, AWS Marketplace products, and AMI IDs directly.
SSM Parameters
Using SSM parameter references:
image_recipe = imagebuilder.ImageRecipe(self, "SsmImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
)
# Using an SSM parameter construct
parameter = ssm.StringParameter.from_string_parameter_name(self, "BaseImageParameter", "/aws/service/ami-windows-latest/Windows_Server-2022-English-Full-Base")
windows_recipe = imagebuilder.ImageRecipe(self, "WindowsImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter(parameter)
)
AMI IDs
When you have a specific AMI to use:
image_recipe = imagebuilder.ImageRecipe(self, "AmiImageRecipe",
base_image=imagebuilder.BaseImage.from_ami_id("ami-12345678")
)
Marketplace Images
For marketplace base images:
image_recipe = imagebuilder.ImageRecipe(self, "MarketplaceImageRecipe",
base_image=imagebuilder.BaseImage.from_marketplace_product_id("prod-1234567890abcdef0")
)
Image Recipe Components
Components from various sources, such as custom-owned, AWS-owned, or AWS Marketplace-owned, can optionally be included in recipes. For parameterized components, you are able to provide the parameters to use in the recipe, which will be applied during the image build when executing components.
Custom Components in Image Recipes
Add your own components to the recipe:
custom_component = imagebuilder.Component(self, "MyComponent",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_json_object({
"schema_version": imagebuilder.ComponentSchemaVersion.V1_0,
"phases": [{
"name": imagebuilder.ComponentPhaseName.BUILD,
"steps": [{
"name": "install-app",
"action": imagebuilder.ComponentAction.EXECUTE_BASH,
"inputs": {
"commands": ["yum install -y my-application"]
}
}
]
}
]
})
)
image_recipe = imagebuilder.ImageRecipe(self, "ComponentImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
components=[imagebuilder.ComponentConfiguration(
component=custom_component
)
]
)
AWS-Managed Components in Image Recipes
Use pre-built AWS components:
image_recipe = imagebuilder.ImageRecipe(self, "AmazonManagedImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
components=[imagebuilder.ComponentConfiguration(
component=imagebuilder.AmazonManagedComponent.update_os(self, "UpdateOS",
platform=imagebuilder.Platform.LINUX
)
), imagebuilder.ComponentConfiguration(
component=imagebuilder.AmazonManagedComponent.aws_cli_v2(self, "AwsCli",
platform=imagebuilder.Platform.LINUX
)
)
]
)
Component Parameters in Image Recipes
Pass parameters to components that accept them:
parameterized_component = imagebuilder.Component.from_component_name(self, "ParameterizedComponent", "my-parameterized-component")
image_recipe = imagebuilder.ImageRecipe(self, "ParameterizedImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
components=[imagebuilder.ComponentConfiguration(
component=parameterized_component,
parameters={
"environment": imagebuilder.ComponentParameterValue.from_string("production"),
"version": imagebuilder.ComponentParameterValue.from_string("1.0.0")
}
)
]
)
Image Recipe Configuration
Block Device Configuration
Configure storage for the build instance:
image_recipe = imagebuilder.ImageRecipe(self, "BlockDeviceImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
block_devices=[ec2.BlockDevice(
device_name="/dev/sda1",
volume=ec2.BlockDeviceVolume.ebs(100,
encrypted=True,
volume_type=ec2.EbsDeviceVolumeType.GENERAL_PURPOSE_SSD_GP3
)
)
]
)
AMI Tagging
Tag the output AMI:
image_recipe = imagebuilder.ImageRecipe(self, "TaggedImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
ami_tags={
"Environment": "Production",
"Application": "WebServer",
"Owner": "DevOps Team"
}
)
Container Recipe
A container recipe is similar to an image recipe but specifically for container images. It defines the base container image and components applied to produce the desired configuration for the output container image. Container recipes work with Docker images from DockerHub, Amazon ECR, or Amazon-managed container images as starting points.
Container Recipe Basic Usage
Create a container recipe with the required base image and target repository:
container_recipe = imagebuilder.ContainerRecipe(self, "MyContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo"))
)
Container Recipe Base Images
DockerHub Images
Using public Docker Hub images:
container_recipe = imagebuilder.ContainerRecipe(self, "DockerHubContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo"))
)
ECR Images
Using images from your own ECR repositories:
source_repo = ecr.Repository.from_repository_name(self, "SourceRepo", "my-base-image")
target_repo = ecr.Repository.from_repository_name(self, "TargetRepo", "my-container-repo")
container_recipe = imagebuilder.ContainerRecipe(self, "EcrContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_ecr(source_repo, "1.0.0"),
target_repository=imagebuilder.Repository.from_ecr(target_repo)
)
ECR Public Images
Using images from Amazon ECR Public:
container_recipe = imagebuilder.ContainerRecipe(self, "EcrPublicContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_ecr_public("amazonlinux", "amazonlinux", "2023"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo"))
)
Container Recipe Components
Custom Components in Container Recipes
Add your own components to the container recipe:
custom_component = imagebuilder.Component(self, "MyComponent",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_json_object({
"schema_version": imagebuilder.ComponentSchemaVersion.V1_0,
"phases": [{
"name": imagebuilder.ComponentPhaseName.BUILD,
"steps": [{
"name": "install-app",
"action": imagebuilder.ComponentAction.EXECUTE_BASH,
"inputs": {
"commands": ["yum install -y my-container-application"]
}
}
]
}
]
})
)
container_recipe = imagebuilder.ContainerRecipe(self, "ComponentContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo")),
components=[imagebuilder.ComponentConfiguration(
component=custom_component
)
]
)
AWS-Managed Components in Container Recipes
Use pre-built AWS components:
container_recipe = imagebuilder.ContainerRecipe(self, "AmazonManagedContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo")),
components=[imagebuilder.ComponentConfiguration(
component=imagebuilder.AmazonManagedComponent.update_os(self, "UpdateOS",
platform=imagebuilder.Platform.LINUX
)
), imagebuilder.ComponentConfiguration(
component=imagebuilder.AmazonManagedComponent.aws_cli_v2(self, "AwsCli",
platform=imagebuilder.Platform.LINUX
)
)
]
)
Container Recipe Configuration
Custom Dockerfile
Provide your own Dockerfile template:
container_recipe = imagebuilder.ContainerRecipe(self, "CustomDockerfileContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo")),
dockerfile=imagebuilder.DockerfileData.from_inline("""
FROM {{{ imagebuilder:parentImage }}}
CMD ["echo", "Hello, world!"]
{{{ imagebuilder:environments }}}
{{{ imagebuilder:components }}}
""")
)
Instance Configuration
Configure the build instance:
container_recipe = imagebuilder.ContainerRecipe(self, "InstanceConfigContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo")),
# Custom ECS-optimized AMI for building
instance_image=imagebuilder.ContainerInstanceImage.from_ssm_parameter_name("/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id"),
# Additional storage for build process
instance_block_devices=[ec2.BlockDevice(
device_name="/dev/xvda",
volume=ec2.BlockDeviceVolume.ebs(50,
encrypted=True,
volume_type=ec2.EbsDeviceVolumeType.GENERAL_PURPOSE_SSD_GP3
)
)
]
)
Component
A component defines the sequence of steps required to customize an instance during image creation (build component) or test an instance launched from the created image (test component). Components are created from declarative YAML or JSON documents that describe runtime configuration for building, validating, or testing instances. Components are included when added to the image recipe or container recipe for an image build.
EC2 Image Builder supports AWS-managed components for common tasks, AWS Marketplace components, and custom components that you create. Components run during specific workflow phases: build and validate phases during the build stage, and test phase during the test stage.
Basic Component Usage
Create a component with the required properties: platform and component data.
component = imagebuilder.Component(self, "MyComponent",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_json_object({
"schema_version": imagebuilder.ComponentSchemaVersion.V1_0,
"phases": [{
"name": imagebuilder.ComponentPhaseName.BUILD,
"steps": [{
"name": "install-app",
"action": imagebuilder.ComponentAction.EXECUTE_BASH,
"inputs": {
"commands": ["echo \"Installing my application...\"", "yum update -y"]
}
}
]
}
]
})
)
Component Data Sources
Inline Component Data
Use ComponentData.fromInline() for existing YAML/JSON definitions:
component = imagebuilder.Component(self, "InlineComponent",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_inline("""
name: my-component
schemaVersion: 1.0
phases:
- name: build
steps:
- name: update-os
action: ExecuteBash
inputs:
commands: ['yum update -y']
""")
)
JSON Object Component Data
Most developer-friendly approach using objects:
component = imagebuilder.Component(self, "JsonComponent",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_json_object({
"schema_version": imagebuilder.ComponentSchemaVersion.V1_0,
"phases": [{
"name": imagebuilder.ComponentPhaseName.BUILD,
"steps": [{
"name": "configure-app",
"action": imagebuilder.ComponentAction.CREATE_FILE,
"inputs": {
"path": "/etc/myapp/config.json",
"content": "{\"env\": \"production\"}"
}
}
]
}
]
})
)
Structured Component Document
For type-safe, CDK-native definitions with enhanced properties like timeout and onFailure.
Defining a component step
You can define steps in the component which will be executed in order when the component is applied:
step = imagebuilder.ComponentDocumentStep(
name="configure-app",
action=imagebuilder.ComponentAction.CREATE_FILE,
inputs=imagebuilder.ComponentStepInputs.from_object({
"path": "/etc/myapp/config.json",
"content": "{\"env\": \"production\"}"
})
)
Defining a component phase
Phases group steps together, which run in sequence when building, validating or testing in the component:
phase = imagebuilder.ComponentDocumentPhase(
name=imagebuilder.ComponentPhaseName.BUILD,
steps=[imagebuilder.ComponentDocumentStep(
name="configure-app",
action=imagebuilder.ComponentAction.CREATE_FILE,
inputs=imagebuilder.ComponentStepInputs.from_object({
"path": "/etc/myapp/config.json",
"content": "{\"env\": \"production\"}"
})
)
]
)
Defining a component
The component data defines all steps across the provided phases to execute during the build:
component = imagebuilder.Component(self, "StructuredComponent",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_component_document_json_object(
schema_version=imagebuilder.ComponentSchemaVersion.V1_0,
phases=[imagebuilder.ComponentDocumentPhase(
name=imagebuilder.ComponentPhaseName.BUILD,
steps=[imagebuilder.ComponentDocumentStep(
name="install-with-timeout",
action=imagebuilder.ComponentAction.EXECUTE_BASH,
timeout=Duration.minutes(10),
on_failure=imagebuilder.ComponentOnFailure.CONTINUE,
inputs=imagebuilder.ComponentStepInputs.from_object({
"commands": ["./install-script.sh"]
})
)
]
)
]
)
)
S3 Component Data
For those components you want to upload or have uploaded to S3:
# Upload a local file
component_from_asset = imagebuilder.Component(self, "AssetComponent",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_asset(self, "ComponentAsset", "./my-component.yml")
)
# Reference an existing S3 object
bucket = s3.Bucket.from_bucket_name(self, "ComponentBucket", "my-components-bucket")
component_from_s3 = imagebuilder.Component(self, "S3Component",
platform=imagebuilder.Platform.LINUX,
data=imagebuilder.ComponentData.from_s3(bucket, "components/my-component.yml")
)
Encrypt component data with a KMS key
You can encrypt component data with a KMS key, so that only principals with access to decrypt with the key are able to access the component data.
component = imagebuilder.Component(self, "EncryptedComponent",
platform=imagebuilder.Platform.LINUX,
kms_key=kms.Key(self, "ComponentKey"),
data=imagebuilder.ComponentData.from_json_object({
"schema_version": imagebuilder.ComponentSchemaVersion.V1_0,
"phases": [{
"name": imagebuilder.ComponentPhaseName.BUILD,
"steps": [{
"name": "secure-setup",
"action": imagebuilder.ComponentAction.EXECUTE_BASH,
"inputs": {
"commands": ["echo \"This component data is encrypted with KMS\""]
}
}
]
}
]
})
)
AWS-Managed Components
AWS provides a collection of managed components for common tasks:
# Install AWS CLI v2
aws_cli_component = imagebuilder.AmazonManagedComponent.aws_cli_v2(self, "AwsCli",
platform=imagebuilder.Platform.LINUX
)
# Update the operating system
update_component = imagebuilder.AmazonManagedComponent.update_os(self, "UpdateOS",
platform=imagebuilder.Platform.LINUX
)
# Reference any AWS-managed component by name
custom_aws_component = imagebuilder.AmazonManagedComponent.from_amazon_managed_component_name(self, "CloudWatchAgent", "amazon-cloudwatch-agent-linux")
AWS Marketplace Components
You can reference AWS Marketplace components using the marketplace component name and its product ID:
marketplace_component = imagebuilder.AwsMarketplaceComponent.from_aws_marketplace_component_attributes(self, "MarketplaceComponent",
component_name="my-marketplace-component",
marketplace_product_id="prod-1234567890abcdef0"
)
Infrastructure Configuration
Infrastructure configuration defines the compute resources and environment settings used during the image building process. This includes instance types, IAM instance profile, VPC settings, subnets, security groups, SNS topics for notifications, logging configuration, and troubleshooting settings like whether to terminate instances on failure or keep them running for debugging. These settings are applied to builds when included in an image or an image pipeline.
infrastructure_configuration = imagebuilder.InfrastructureConfiguration(self, "InfrastructureConfiguration",
infrastructure_configuration_name="test-infrastructure-configuration",
description="An Infrastructure Configuration",
# Optional - instance types to use for build/test
instance_types=[
ec2.InstanceType.of(ec2.InstanceClass.STANDARD7_INTEL, ec2.InstanceSize.LARGE),
ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.LARGE)
],
# Optional - create an instance profile with necessary permissions
instance_profile=iam.InstanceProfile(self, "InstanceProfile",
instance_profile_name="test-instance-profile",
role=iam.Role(self, "InstanceProfileRole",
assumed_by=iam.ServicePrincipal.from_static_service_principle_name("ec2.amazonaws.com"),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSSMManagedInstanceCore"),
iam.ManagedPolicy.from_aws_managed_policy_name("EC2InstanceProfileForImageBuilder")
]
)
),
# Use VPC network configuration
vpc=vpc,
subnet_selection=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC),
security_groups=[ec2.SecurityGroup.from_security_group_id(self, "SecurityGroup", vpc.vpc_default_security_group)],
key_pair=ec2.KeyPair.from_key_pair_name(self, "KeyPair", "imagebuilder-instance-key-pair"),
terminate_instance_on_failure=True,
# Optional - IMDSv2 settings
http_tokens=imagebuilder.HttpTokens.REQUIRED,
http_put_response_hop_limit=1,
# Optional - publish image completion messages to an SNS topic
notification_topic=sns.Topic.from_topic_arn(self, "Topic",
self.format_arn(service="sns", resource="image-builder-topic")),
# Optional - log settings. Logging is enabled by default
logging=imagebuilder.InfrastructureConfigurationLogging(
s3_bucket=s3.Bucket.from_bucket_name(self, "LogBucket", f"imagebuilder-logging-{Aws.ACCOUNT_ID}"),
s3_key_prefix="imagebuilder-logs"
),
# Optional - host placement settings
ec2_instance_availability_zone=Stack.of(self).availability_zones[0],
ec2_instance_host_id=dedicated_host.attr_host_id,
ec2_instance_tenancy=imagebuilder.Tenancy.HOST,
resource_tags={
"Environment": "production"
}
)
Distribution Configuration
Distribution configuration defines how and where your built images are distributed after successful creation. For AMIs, this includes target AWS Regions, KMS encryption keys, account sharing permissions, License Manager associations, and launch template configurations. For container images, it specifies the target Amazon ECR repositories across regions. A distribution configuration can be associated with an image or an image pipeline to define these distribution settings for image builds.
AMI Distributions
AMI distributions can be defined to copy and modify AMIs in different accounts and regions, and apply them to launch templates, SSM parameters, etc.:
distribution_configuration = imagebuilder.DistributionConfiguration(self, "DistributionConfiguration",
distribution_configuration_name="test-distribution-configuration",
description="A Distribution Configuration",
ami_distributions=[imagebuilder.AmiDistribution(
# Distribute AMI to us-east-2 and publish the AMI ID to an SSM parameter
region="us-east-2",
ssm_parameters=[imagebuilder.SSMParameterConfigurations(
parameter=ssm.StringParameter.from_string_parameter_attributes(self, "CrossRegionParameter",
parameter_name="/imagebuilder/ami",
force_dynamic_reference=True
)
)
]
)
]
)
# For AMI-based image builds - add an AMI distribution in the current region
distribution_configuration.add_ami_distributions(
ami_name="imagebuilder-{{ imagebuilder:buildDate }}",
ami_description="Build AMI",
ami_kms_key=kms.Key.from_lookup(self, "ComponentKey", alias_name="alias/distribution-encryption-key"),
# Copy the AMI to different accounts
ami_target_account_ids=["123456789012", "098765432109"],
# Add launch permissions on the AMI
ami_launch_permission=imagebuilder.AmiLaunchPermission(
organization_arns=[
self.format_arn(region="", service="organizations", resource="organization", resource_name="o-1234567abc")
],
organizational_unit_arns=[
self.format_arn(
region="",
service="organizations",
resource="ou",
resource_name="o-1234567abc/ou-a123-b4567890"
)
],
is_public_user_group=True,
account_ids=["234567890123"]
),
# Attach tags to the AMI
ami_tags={
"Environment": "production",
"Version": "{{ imagebuilder:buildVersion }}"
},
# Optional - publish the distributed AMI ID to an SSM parameter
ssm_parameters=[imagebuilder.SSMParameterConfigurations(
parameter=ssm.StringParameter.from_string_parameter_attributes(self, "Parameter",
parameter_name="/imagebuilder/ami",
force_dynamic_reference=True
)
), imagebuilder.SSMParameterConfigurations(
ami_account="098765432109",
data_type=ssm.ParameterDataType.TEXT,
parameter=ssm.StringParameter.from_string_parameter_attributes(self, "CrossAccountParameter",
parameter_name="imagebuilder-prod-ami",
force_dynamic_reference=True
)
)
],
# Optional - create a new launch template version with the distributed AMI ID
launch_templates=[imagebuilder.LaunchTemplateConfiguration(
launch_template=ec2.LaunchTemplate.from_launch_template_attributes(self, "LaunchTemplate",
launch_template_id="lt-1234"
),
set_default_version=True
), imagebuilder.LaunchTemplateConfiguration(
account_id="123456789012",
launch_template=ec2.LaunchTemplate.from_launch_template_attributes(self, "CrossAccountLaunchTemplate",
launch_template_id="lt-5678"
),
set_default_version=True
)
],
# Optional - enable Fast Launch on an imported launch template
fast_launch_configurations=[imagebuilder.FastLaunchConfiguration(
enabled=True,
launch_template=ec2.LaunchTemplate.from_launch_template_attributes(self, "FastLaunchLT",
launch_template_name="fast-launch-lt"
),
max_parallel_launches=10,
target_snapshot_count=2
)
],
# Optional - license configurations to apply to the AMI
license_configuration_arns=["arn:aws:license-manager:us-west-2:123456789012:license-configuration:lic-abcdefghijklmnopqrstuvwxyz"
]
)
Container Distributions
Container repositories
Container distributions can be configured to distribute to ECR repositories:
ecr_repository = ecr.Repository.from_repository_name(self, "ECRRepository", "my-repo")
image_builder_repository = imagebuilder.Repository.from_ecr(ecr_repository)
Defining a container distribution
You can configure the container repositories as well as the description and tags applied to the distributed container images:
ecr_repository = ecr.Repository.from_repository_name(self, "ECRRepository", "my-repo")
container_repository = imagebuilder.Repository.from_ecr(ecr_repository)
container_distribution_configuration = imagebuilder.DistributionConfiguration(self, "ContainerDistributionConfiguration")
container_distribution_configuration.add_container_distributions(
container_repository=container_repository,
container_description="Test container image",
container_tags=["latest", "latest-1.0"]
)
Workflow
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).
Basic Workflow Usage
Create a workflow with the required properties: workflow type and workflow data.
workflow = imagebuilder.Workflow(self, "MyWorkflow",
workflow_type=imagebuilder.WorkflowType.BUILD,
data=imagebuilder.WorkflowData.from_json_object({
"schema_version": imagebuilder.WorkflowSchemaVersion.V1_0,
"steps": [{
"name": "LaunchBuildInstance",
"action": imagebuilder.WorkflowAction.LAUNCH_INSTANCE,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"wait_for": "ssmAgent"
}
}, {
"name": "ExecuteComponents",
"action": imagebuilder.WorkflowAction.EXECUTE_COMPONENTS,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"instance_id": "i-123"
}
}, {
"name": "CreateImage",
"action": imagebuilder.WorkflowAction.CREATE_IMAGE,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"instance_id": "i-123"
}
}, {
"name": "TerminateInstance",
"action": imagebuilder.WorkflowAction.TERMINATE_INSTANCE,
"on_failure": imagebuilder.WorkflowOnFailure.CONTINUE,
"inputs": {
"instance_id": "i-123"
}
}
],
"outputs": [{
"name": "ImageId",
"value": "$.stepOutputs.CreateImage.imageId"
}
]
})
)
Workflow Data Sources
Inline Workflow Data
Use WorkflowData.fromInline() for existing YAML/JSON definitions:
workflow = imagebuilder.Workflow(self, "InlineWorkflow",
workflow_type=imagebuilder.WorkflowType.TEST,
data=imagebuilder.WorkflowData.from_inline("""
schemaVersion: 1.0
steps:
- name: LaunchTestInstance
action: LaunchInstance
onFailure: Abort
inputs:
waitFor: ssmAgent
- name: RunTests
action: RunCommand
onFailure: Abort
inputs:
instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId"
commands: ['./run-tests.sh']
- name: TerminateTestInstance
action: TerminateInstance
onFailure: Continue
inputs:
instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId"
""")
)
JSON Object Workflow Data
Most developer-friendly approach using JavaScript objects:
workflow = imagebuilder.Workflow(self, "JsonWorkflow",
workflow_type=imagebuilder.WorkflowType.BUILD,
data=imagebuilder.WorkflowData.from_json_object({
"schema_version": imagebuilder.WorkflowSchemaVersion.V1_0,
"steps": [{
"name": "LaunchBuildInstance",
"action": imagebuilder.WorkflowAction.LAUNCH_INSTANCE,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"wait_for": "ssmAgent"
}
}, {
"name": "ExecuteComponents",
"action": imagebuilder.WorkflowAction.EXECUTE_COMPONENTS,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"instance_id": "i-123"
}
}, {
"name": "CreateImage",
"action": imagebuilder.WorkflowAction.CREATE_IMAGE,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"instance_id": "i-123"
}
}, {
"name": "TerminateInstance",
"action": imagebuilder.WorkflowAction.TERMINATE_INSTANCE,
"on_failure": imagebuilder.WorkflowOnFailure.CONTINUE,
"inputs": {
"instance_id": "i-123"
}
}
],
"outputs": [{
"name": "ImageId",
"value": "$.stepOutputs.CreateImage.imageId"
}
]
})
)
S3 Workflow Data
For those workflows you want to upload or have uploaded to S3:
# Upload a local file
workflow_from_asset = imagebuilder.Workflow(self, "AssetWorkflow",
workflow_type=imagebuilder.WorkflowType.BUILD,
data=imagebuilder.WorkflowData.from_asset(self, "WorkflowAsset", "./my-workflow.yml")
)
# Reference an existing S3 object
bucket = s3.Bucket.from_bucket_name(self, "WorkflowBucket", "my-workflows-bucket")
workflow_from_s3 = imagebuilder.Workflow(self, "S3Workflow",
workflow_type=imagebuilder.WorkflowType.BUILD,
data=imagebuilder.WorkflowData.from_s3(bucket, "workflows/my-workflow.yml")
)
Encrypt workflow data with a KMS key
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.
workflow = imagebuilder.Workflow(self, "EncryptedWorkflow",
workflow_type=imagebuilder.WorkflowType.BUILD,
kms_key=kms.Key(self, "WorkflowKey"),
data=imagebuilder.WorkflowData.from_json_object({
"schema_version": imagebuilder.WorkflowSchemaVersion.V1_0,
"steps": [{
"name": "LaunchBuildInstance",
"action": imagebuilder.WorkflowAction.LAUNCH_INSTANCE,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"wait_for": "ssmAgent"
}
}, {
"name": "CreateImage",
"action": imagebuilder.WorkflowAction.CREATE_IMAGE,
"on_failure": imagebuilder.WorkflowOnFailure.ABORT,
"inputs": {
"instance_id": "i-123"
}
}, {
"name": "TerminateInstance",
"action": imagebuilder.WorkflowAction.TERMINATE_INSTANCE,
"on_failure": imagebuilder.WorkflowOnFailure.CONTINUE,
"inputs": {
"instance_id": "i-123"
}
}
],
"outputs": [{
"name": "ImageId",
"value": "$.stepOutputs.CreateImage.imageId"
}
]
})
)
AWS-Managed Workflows
AWS provides a collection of workflows for common scenarios:
# Build workflows
build_image_workflow = imagebuilder.AmazonManagedWorkflow.build_image(self, "BuildImage")
build_container_workflow = imagebuilder.AmazonManagedWorkflow.build_container(self, "BuildContainer")
# Test workflows
test_image_workflow = imagebuilder.AmazonManagedWorkflow.test_image(self, "TestImage")
test_container_workflow = imagebuilder.AmazonManagedWorkflow.test_container(self, "TestContainer")
# Distribution workflows
distribute_container_workflow = imagebuilder.AmazonManagedWorkflow.distribute_container(self, "DistributeContainer")
Lifecycle Policy
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.
Lifecycle Policy Basic Usage
Create a lifecycle policy to automatically delete old AMI images after 30 days:
lifecycle_policy = imagebuilder.LifecyclePolicy(self, "MyLifecyclePolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(age_filter=imagebuilder.LifecyclePolicyAgeFilter(age=Duration.days(30)))
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Environment": "development"}
)
)
Create a lifecycle policy to keep only the 10 most recent container images:
container_lifecycle_policy = imagebuilder.LifecyclePolicy(self, "ContainerLifecyclePolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.CONTAINER_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(count_filter=imagebuilder.LifecyclePolicyCountFilter(count=10))
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Application": "web-app"}
)
)
Lifecycle Policy Resource Selection
Tag-Based Resource Selection
Apply lifecycle policies to images with specific tags:
tag_based_policy = imagebuilder.LifecyclePolicy(self, "TagBasedPolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(age_filter=imagebuilder.LifecyclePolicyAgeFilter(age=Duration.days(90)))
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={
"Environment": "staging",
"Team": "backend"
}
)
)
Recipe-Based Resource Selection
Apply lifecycle policies to specific image or container recipes:
image_recipe = imagebuilder.ImageRecipe(self, "MyImageRecipe",
base_image=imagebuilder.BaseImage.from_ssm_parameter_name("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
)
container_recipe = imagebuilder.ContainerRecipe(self, "MyContainerRecipe",
base_image=imagebuilder.BaseContainerImage.from_docker_hub("amazonlinux", "latest"),
target_repository=imagebuilder.Repository.from_ecr(
ecr.Repository.from_repository_name(self, "Repository", "my-container-repo"))
)
recipe_based_policy = imagebuilder.LifecyclePolicy(self, "RecipeBasedPolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(count_filter=imagebuilder.LifecyclePolicyCountFilter(count=5))
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
recipes=[image_recipe, container_recipe]
)
)
Lifecycle Policy Rules
Age-Based Rules
Delete images older than a specific time period:
age_based_policy = imagebuilder.LifecyclePolicy(self, "AgeBasedPolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(
type=imagebuilder.LifecyclePolicyActionType.DELETE,
include_amis=True,
include_snapshots=True
),
filter=imagebuilder.LifecyclePolicyFilter(
age_filter=imagebuilder.LifecyclePolicyAgeFilter(
age=Duration.days(60),
retain_at_least=3
)
)
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Environment": "testing"}
)
)
Count-Based Rules
Keep only a specific number of the most recent images:
count_based_policy = imagebuilder.LifecyclePolicy(self, "CountBasedPolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.CONTAINER_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(count_filter=imagebuilder.LifecyclePolicyCountFilter(count=15))
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Application": "microservice"}
)
)
Multiple Lifecycle Rules
Implement a graduated approach with multiple actions:
graduated_policy = imagebuilder.LifecyclePolicy(self, "GraduatedPolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
# First: Deprecate images after 30 days
action=imagebuilder.LifecyclePolicyAction(
type=imagebuilder.LifecyclePolicyActionType.DEPRECATE,
include_amis=True
),
filter=imagebuilder.LifecyclePolicyFilter(
age_filter=imagebuilder.LifecyclePolicyAgeFilter(
age=Duration.days(30),
retain_at_least=5
)
)
), imagebuilder.LifecyclePolicyDetail(
# Second: Disable images after 60 days
action=imagebuilder.LifecyclePolicyAction(
type=imagebuilder.LifecyclePolicyActionType.DISABLE,
include_amis=True
),
filter=imagebuilder.LifecyclePolicyFilter(
age_filter=imagebuilder.LifecyclePolicyAgeFilter(
age=Duration.days(60),
retain_at_least=3
)
)
), imagebuilder.LifecyclePolicyDetail(
# Finally: Delete images after 90 days
action=imagebuilder.LifecyclePolicyAction(
type=imagebuilder.LifecyclePolicyActionType.DELETE,
include_amis=True,
include_snapshots=True
),
filter=imagebuilder.LifecyclePolicyFilter(
age_filter=imagebuilder.LifecyclePolicyAgeFilter(
age=Duration.days(90),
retain_at_least=1
)
)
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Environment": "production"}
)
)
Lifecycle Policy Exclusion Rules
AMI Exclusion Rules
Exclude specific AMIs from lifecycle actions based on various criteria:
exclude_amis_policy = imagebuilder.LifecyclePolicy(self, "ExcludeAmisPolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(age_filter=imagebuilder.LifecyclePolicyAgeFilter(age=Duration.days(30))),
exclusion_rules=imagebuilder.LifecyclePolicyExclusionRules(
ami_exclusion_rules=imagebuilder.LifecyclePolicyAmiExclusionRules(
is_public=True, # Exclude public AMIs
last_launched=Duration.days(7), # Exclude AMIs launched in last 7 days
regions=["us-west-2", "eu-west-1"], # Exclude AMIs in specific regions
shared_accounts=["123456789012"], # Exclude AMIs shared with specific accounts
tags={
"Protected": "true",
"Environment": "production"
}
)
)
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Team": "infrastructure"}
)
)
Image Exclusion Rules
Exclude Image Builder images with protective tags:
exclude_images_policy = imagebuilder.LifecyclePolicy(self, "ExcludeImagesPolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.CONTAINER_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(count_filter=imagebuilder.LifecyclePolicyCountFilter(count=20)),
exclusion_rules=imagebuilder.LifecyclePolicyExclusionRules(
image_exclusion_rules=imagebuilder.LifecyclePolicyImageExclusionRules(
tags={
"DoNotDelete": "true",
"Critical": "baseline"
}
)
)
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Application": "frontend"}
)
)
Advanced Lifecycle Configuration
Custom Execution Roles
Provide your own IAM execution role with specific permissions:
execution_role = iam.Role(self, "LifecycleExecutionRole",
assumed_by=iam.ServicePrincipal("imagebuilder.amazonaws.com"),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name("service-role/EC2ImageBuilderLifecycleExecutionPolicy")
]
)
custom_role_policy = imagebuilder.LifecyclePolicy(self, "CustomRolePolicy",
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
execution_role=execution_role,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(age_filter=imagebuilder.LifecyclePolicyAgeFilter(age=Duration.days(45)))
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Environment": "development"}
)
)
Lifecycle Policy Status
Control whether the lifecycle policy is active:
disabled_policy = imagebuilder.LifecyclePolicy(self, "DisabledPolicy",
lifecycle_policy_name="my-disabled-policy",
description="A lifecycle policy that is temporarily disabled",
status=imagebuilder.LifecyclePolicyStatus.DISABLED,
resource_type=imagebuilder.LifecyclePolicyResourceType.AMI_IMAGE,
details=[imagebuilder.LifecyclePolicyDetail(
action=imagebuilder.LifecyclePolicyAction(type=imagebuilder.LifecyclePolicyActionType.DELETE),
filter=imagebuilder.LifecyclePolicyFilter(age_filter=imagebuilder.LifecyclePolicyAgeFilter(age=Duration.days(30)))
)
],
resource_selection=imagebuilder.LifecyclePolicyResourceSelection(
tags={"Environment": "testing"}
),
tags={
"Owner": "DevOps",
"CostCenter": "Engineering"
}
)
Importing Lifecycle Policies
Reference lifecycle policies created outside CDK:
# Import by name
imported_by_name = imagebuilder.LifecyclePolicy.from_lifecycle_policy_name(self, "ImportedByName", "existing-lifecycle-policy")
# Import by ARN
imported_by_arn = imagebuilder.LifecyclePolicy.from_lifecycle_policy_arn(self, "ImportedByArn", "arn:aws:imagebuilder:us-east-1:123456789012:lifecycle-policy/my-policy")
imported_by_name.grant_read(lambda_role)
imported_by_arn.grant(lambda_role, "imagebuilder:UpdateLifecyclePolicy")