Skip to main content
net6.0

The CDK Construct Library for EC2 Image Builder (Stability: Experimental)

Published
Oct 20, 2026
yesterday
Total Downloads
7.2K
7,208

Install

dotnet add package Amazon.CDK.AWS.ImageBuilder.Alpha --version 2.274.0-alpha.0
ProductVersions
.NET
net6.0

README

EC2 Image Builder Construct Library


cdk-constructs: Experimental

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:

var imageRecipe = new ImageRecipe(this, "MyImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
});

var imagePipeline = new ImagePipeline(this, "MyImagePipeline", new ImagePipelineProps {
    Recipe = exampleImageRecipe
});

Create a simple container pipeline with just a container recipe:

var containerRecipe = new ContainerRecipe(this, "MyContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo"))
});

var containerPipeline = new ImagePipeline(this, "MyContainerPipeline", new ImagePipelineProps {
    Recipe = exampleContainerRecipe
});
Image Pipeline Scheduling
Manual Pipeline Execution

Create a pipeline that runs only when manually triggered:

var manualPipeline = new ImagePipeline(this, "ManualPipeline", new ImagePipelineProps {
    ImagePipelineName = "my-manual-pipeline",
    Description = "Pipeline triggered manually for production builds",
    Recipe = exampleImageRecipe
});

// Grant Lambda function permission to trigger the pipeline
manualPipeline.GrantStartExecution(lambdaRole);
Automated Pipeline Scheduling

Schedule a pipeline to run automatically using cron expressions:

var weeklyPipeline = new ImagePipeline(this, "WeeklyPipeline", new ImagePipelineProps {
    ImagePipelineName = "weekly-build-pipeline",
    Recipe = exampleImageRecipe,
    Schedule = new ImagePipelineSchedule {
        Expression = Schedule.Cron(new CronOptions {
            Minute = "0",
            Hour = "6",
            WeekDay = "MON"
        })
    }
});

Use rate expressions for regular intervals:

var dailyPipeline = new ImagePipeline(this, "DailyPipeline", new ImagePipelineProps {
    Recipe = exampleContainerRecipe,
    Schedule = new ImagePipelineSchedule {
        Expression = Schedule.Rate(Duration.Days(1))
    }
});
Pipeline Schedule Configuration

Configure advanced scheduling options:

var advancedSchedulePipeline = new ImagePipeline(this, "AdvancedSchedulePipeline", new ImagePipelineProps {
    Recipe = exampleImageRecipe,
    Schedule = new ImagePipelineSchedule {
        Expression = Schedule.Rate(Duration.Days(7)),
        // Only trigger when dependencies are updated (new base images, components, etc.)
        StartCondition = ScheduleStartCondition.EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE,
        // Automatically disable after 3 consecutive failures
        AutoDisableFailureCount = 3
    },
    // Start enabled
    Status = ImagePipelineStatus.ENABLED
});
Image Pipeline Configuration
Infrastructure and Distribution in Image Pipelines

Configure custom infrastructure and distribution settings:

var infrastructureConfiguration = new InfrastructureConfiguration(this, "Infrastructure", new InfrastructureConfigurationProps {
    InfrastructureConfigurationName = "production-infrastructure",
    InstanceTypes = new [] { InstanceType.Of(InstanceClass.COMPUTE7_INTEL, InstanceSize.LARGE) },
    Vpc = vpc,
    SubnetSelection = new SubnetSelection { SubnetType = SubnetType.PRIVATE_WITH_EGRESS }
});

var distributionConfiguration = new DistributionConfiguration(this, "Distribution");
distributionConfiguration.AddAmiDistributions(new AmiDistribution {
    AmiName = "production-ami-{{ imagebuilder:buildDate }}",
    AmiTargetAccountIds = new [] { "123456789012", "098765432109" }
});

var productionPipeline = new ImagePipeline(this, "ProductionPipeline", new ImagePipelineProps {
    Recipe = exampleImageRecipe,
    InfrastructureConfiguration = infrastructureConfiguration,
    DistributionConfiguration = distributionConfiguration
});
Pipeline Logging Configuration

Configure custom CloudWatch log groups for pipeline and image logs:

var pipelineLogGroup = new LogGroup(this, "PipelineLogGroup", new LogGroupProps {
    LogGroupName = "/custom/imagebuilder/pipeline/logs",
    Retention = RetentionDays.ONE_MONTH
});

var imageLogGroup = new LogGroup(this, "ImageLogGroup", new LogGroupProps {
    LogGroupName = "/custom/imagebuilder/image/logs",
    Retention = RetentionDays.ONE_WEEK
});

var loggedPipeline = new ImagePipeline(this, "LoggedPipeline", new ImagePipelineProps {
    Recipe = exampleImageRecipe,
    ImagePipelineLogGroup = pipelineLogGroup,
    ImageLogGroup = imageLogGroup
});
Workflow Integration in Image Pipelines

Use AWS-managed workflows for common pipeline phases:

var workflowPipeline = new ImagePipeline(this, "WorkflowPipeline", new ImagePipelineProps {
    Recipe = exampleImageRecipe,
    Workflows = new [] { new WorkflowConfiguration { Workflow = AmazonManagedWorkflow.BuildImage(this, "BuildWorkflow") }, new WorkflowConfiguration { Workflow = AmazonManagedWorkflow.TestImage(this, "TestWorkflow") } }
});

For container pipelines, use container-specific workflows:

var containerWorkflowPipeline = new ImagePipeline(this, "ContainerWorkflowPipeline", new ImagePipelineProps {
    Recipe = exampleContainerRecipe,
    Workflows = new [] { new WorkflowConfiguration { Workflow = AmazonManagedWorkflow.BuildContainer(this, "BuildContainer") }, new WorkflowConfiguration { Workflow = AmazonManagedWorkflow.TestContainer(this, "TestContainer") }, new WorkflowConfiguration { Workflow = AmazonManagedWorkflow.DistributeContainer(this, "DistributeContainer") } }
});
Advanced Features in Image Pipelines

Configure image scanning for container pipelines:

var scanningRepository = new Repository(this, "ScanningRepo");

var scannedContainerPipeline = new ImagePipeline(this, "ScannedContainerPipeline", new ImagePipelineProps {
    Recipe = exampleContainerRecipe,
    ImageScanningEnabled = true,
    ImageScanningEcrRepository = scanningRepository,
    ImageScanningEcrTags = new [] { "security-scan", "latest" }
});

Control metadata collection and testing:

var controlledPipeline = new ImagePipeline(this, "ControlledPipeline", new ImagePipelineProps {
    Recipe = exampleImageRecipe,
    EnhancedImageMetadataEnabled = true,  // Collect detailed OS and package info
    ImageTestsEnabled = false
});
Image Pipeline Events
Pipeline Event Handling

Handle specific pipeline events:

// Monitor CVE detection
examplePipeline.OnCVEDetected("CVEAlert", new OnEventOptions {
    Target = new SnsTopic(topic)
});

// Handle pipeline auto-disable events
examplePipeline.OnImagePipelineAutoDisabled("PipelineDisabledAlert", new OnEventOptions {
    Target = new LambdaFunction(lambdaFunction)
});
Importing Image Pipelines

Reference existing pipelines created outside CDK:

// Import by name
var existingPipelineByName = ImagePipeline.FromImagePipelineName(this, "ExistingPipelineByName", "my-existing-pipeline");

// Import by ARN
var existingPipelineByArn = ImagePipeline.FromImagePipelineArn(this, "ExistingPipelineByArn", "arn:aws:imagebuilder:us-east-1:123456789012:image-pipeline/imported-pipeline");

// Grant permissions to imported pipelines
var automationRole = new Role(this, "AutomationRole", new RoleProps {
    AssumedBy = new ServicePrincipal("lambda.amazonaws.com")
});

existingPipelineByName.GrantStartExecution(automationRole);
existingPipelineByArn.GrantRead(lambdaRole);

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:

var imageRecipe = new ImageRecipe(this, "MyImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
});

var amiImage = new Image(this, "MyAmiImage", new ImageProps {
    Recipe = imageRecipe
});

Create a simple container image from a container recipe:

var containerRecipe = new ContainerRecipe(this, "MyContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo"))
});

var containerImage = new Image(this, "MyContainerImage", new ImageProps {
    Recipe = containerRecipe
});
AWS-Managed Images
Pre-defined OS Images

Use AWS-managed images for common operating systems:

// Amazon Linux 2023 AMI for x86_64
var amazonLinux2023Ami = AmazonManagedImage.AmazonLinux2023(this, "AmazonLinux2023", new AmazonManagedImageOptions {
    ImageType = ImageType.AMI,
    ImageArchitecture = ImageArchitecture.X86_64
});

// Ubuntu 22.04 AMI for ARM64
var ubuntu2204Ami = AmazonManagedImage.UbuntuServer2204(this, "Ubuntu2204", new AmazonManagedImageOptions {
    ImageType = ImageType.AMI,
    ImageArchitecture = ImageArchitecture.ARM64
});

// Windows Server 2022 Full AMI
var windows2022Ami = AmazonManagedImage.WindowsServer2022Full(this, "Windows2022", new AmazonManagedImageOptions {
    ImageType = ImageType.AMI,
    ImageArchitecture = ImageArchitecture.X86_64
});

// Use as base image in recipe
var managedImageRecipe = new ImageRecipe(this, "ManagedImageRecipe", new ImageRecipeProps {
    BaseImage = amazonLinux2023Ami.ToBaseImage()
});
Custom AWS-Managed Images

Import AWS-managed images by name or attributes:

// Import by name
var managedImageByName = AmazonManagedImage.FromAmazonManagedImageName(this, "ManagedImageByName", "amazon-linux-2023-x86");

// Import by attributes with specific version
var managedImageByAttributes = AmazonManagedImage.FromAmazonManagedImageAttributes(this, "ManagedImageByAttributes", new AmazonManagedImageAttributes {
    ImageName = "ubuntu-server-22-lts-x86",
    ImageVersion = "2024.11.25"
});
Image Configuration
Infrastructure and Distribution in Images

Configure custom infrastructure and distribution settings:

var infrastructureConfiguration = new InfrastructureConfiguration(this, "Infrastructure", new InfrastructureConfigurationProps {
    InfrastructureConfigurationName = "production-infrastructure",
    InstanceTypes = new [] { InstanceType.Of(InstanceClass.COMPUTE7_INTEL, InstanceSize.LARGE) },
    Vpc = vpc,
    SubnetSelection = new SubnetSelection { SubnetType = SubnetType.PRIVATE_WITH_EGRESS }
});

var distributionConfiguration = new DistributionConfiguration(this, "Distribution");
distributionConfiguration.AddAmiDistributions(new AmiDistribution {
    AmiName = "production-ami-{{ imagebuilder:buildDate }}",
    AmiTargetAccountIds = new [] { "123456789012", "098765432109" }
});

var productionImage = new Image(this, "ProductionImage", new ImageProps {
    Recipe = exampleImageRecipe,
    InfrastructureConfiguration = infrastructureConfiguration,
    DistributionConfiguration = distributionConfiguration
});
Logging Configuration

Configure custom CloudWatch log groups for image builds:

var logGroup = new LogGroup(this, "ImageLogGroup", new LogGroupProps {
    LogGroupName = "/custom/imagebuilder/image/logs",
    Retention = RetentionDays.ONE_MONTH
});

var loggedImage = new Image(this, "LoggedImage", new ImageProps {
    Recipe = exampleImageRecipe,
    LogGroup = logGroup
});
Workflow Integration in Images

Use workflows for custom build, test, and distribution processes:

var imageWithWorkflows = new Image(this, "ImageWithWorkflows", new ImageProps {
    Recipe = exampleImageRecipe,
    Workflows = new [] { new WorkflowConfiguration { Workflow = AmazonManagedWorkflow.BuildImage(this, "BuildWorkflow") }, new WorkflowConfiguration { Workflow = AmazonManagedWorkflow.TestImage(this, "TestWorkflow") } }
});
Advanced Features in Images

Configure image scanning, metadata collection, and testing:

var scanningRepository = new Repository(this, "ScanningRepository");

var advancedContainerImage = new Image(this, "AdvancedContainerImage", new ImageProps {
    Recipe = exampleContainerRecipe,
    ImageScanningEnabled = true,
    ImageScanningEcrRepository = scanningRepository,
    ImageScanningEcrTags = new [] { "security-scan", "latest" },
    EnhancedImageMetadataEnabled = true,
    ImageTestsEnabled = false
});
Importing Images

Reference existing images created outside CDK:

// Import by name
var existingImageByName = Image.FromImageName(this, "ExistingImageByName", "my-existing-image");

// Import by ARN
var existingImageByArn = Image.FromImageArn(this, "ExistingImageByArn", "arn:aws:imagebuilder:us-east-1:123456789012:image/imported-image/1.0.0");

// Import by attributes
var existingImageByAttributes = Image.FromImageAttributes(this, "ExistingImageByAttributes", new ImageAttributes {
    ImageName = "shared-base-image",
    ImageVersion = "2024.11.25"
});

// Grant permissions to imported images
var role = new Role(this, "ImageAccessRole", new RoleProps {
    AssumedBy = new ServicePrincipal("lambda.amazonaws.com")
});

existingImageByName.GrantRead(role);
existingImageByArn.Grant(role, "imagebuilder:GetImage", "imagebuilder:ListImagePackages");

Image Recipe

Image Recipe Basic Usage

Create an image recipe with the required base image:

var imageRecipe = new ImageRecipe(this, "MyImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/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:

var imageRecipe = new ImageRecipe(this, "SsmImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
});

// Using an SSM parameter construct
var parameter = StringParameter.FromStringParameterName(this, "BaseImageParameter", "/aws/service/ami-windows-latest/Windows_Server-2022-English-Full-Base");
var windowsRecipe = new ImageRecipe(this, "WindowsImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameter(parameter)
});
AMI IDs

When you have a specific AMI to use:

var imageRecipe = new ImageRecipe(this, "AmiImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromAmiId("ami-12345678")
});
Marketplace Images

For marketplace base images:

var imageRecipe = new ImageRecipe(this, "MarketplaceImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromMarketplaceProductId("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:

var customComponent = new Component(this, "MyComponent", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", ComponentSchemaVersion.V1_0 },
        { "phases", new [] { new Dictionary<string, object> {
            { "name", ComponentPhaseName.BUILD },
            { "steps", new [] { new Struct {
                Name = "install-app",
                Action = ComponentAction.EXECUTE_BASH,
                Inputs = new Struct {
                    Commands = new [] { "yum install -y my-application" }
                }
            } } }
        } } }
    })
});

var imageRecipe = new ImageRecipe(this, "ComponentImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
    Components = new [] { new ComponentConfiguration {
        Component = customComponent
    } }
});
AWS-Managed Components in Image Recipes

Use pre-built AWS components:

var imageRecipe = new ImageRecipe(this, "AmazonManagedImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
    Components = new [] { new ComponentConfiguration {
        Component = AmazonManagedComponent.UpdateOs(this, "UpdateOS", new AmazonManagedComponentOptions {
            Platform = Platform.LINUX
        })
    }, new ComponentConfiguration {
        Component = AmazonManagedComponent.AwsCliV2(this, "AwsCli", new AmazonManagedComponentOptions {
            Platform = Platform.LINUX
        })
    } }
});
Component Parameters in Image Recipes

Pass parameters to components that accept them:

var parameterizedComponent = Component.FromComponentName(this, "ParameterizedComponent", "my-parameterized-component");

var imageRecipe = new ImageRecipe(this, "ParameterizedImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
    Components = new [] { new ComponentConfiguration {
        Component = parameterizedComponent,
        Parameters = new Dictionary<string, ComponentParameterValue> {
            { "environment", ComponentParameterValue.FromString("production") },
            { "version", ComponentParameterValue.FromString("1.0.0") }
        }
    } }
});
Image Recipe Configuration
Block Device Configuration

Configure storage for the build instance:

var imageRecipe = new ImageRecipe(this, "BlockDeviceImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
    BlockDevices = new [] { new BlockDevice {
        DeviceName = "/dev/sda1",
        Volume = BlockDeviceVolume.Ebs(100, new EbsDeviceOptions {
            Encrypted = true,
            VolumeType = EbsDeviceVolumeType.GENERAL_PURPOSE_SSD_GP3
        })
    } }
});
AMI Tagging

Tag the output AMI:

var imageRecipe = new ImageRecipe(this, "TaggedImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64"),
    AmiTags = new Dictionary<string, string> {
        { "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:

var containerRecipe = new ContainerRecipe(this, "MyContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo"))
});
Container Recipe Base Images
DockerHub Images

Using public Docker Hub images:

var containerRecipe = new ContainerRecipe(this, "DockerHubContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo"))
});
ECR Images

Using images from your own ECR repositories:

var sourceRepo = Repository.FromRepositoryName(this, "SourceRepo", "my-base-image");
var targetRepo = Repository.FromRepositoryName(this, "TargetRepo", "my-container-repo");

var containerRecipe = new ContainerRecipe(this, "EcrContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromEcr(sourceRepo, "1.0.0"),
    TargetRepository = Repository.FromEcr(targetRepo)
});
ECR Public Images

Using images from Amazon ECR Public:

var containerRecipe = new ContainerRecipe(this, "EcrPublicContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromEcrPublic("amazonlinux", "amazonlinux", "2023"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo"))
});
Container Recipe Components
Custom Components in Container Recipes

Add your own components to the container recipe:

var customComponent = new Component(this, "MyComponent", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", ComponentSchemaVersion.V1_0 },
        { "phases", new [] { new Dictionary<string, object> {
            { "name", ComponentPhaseName.BUILD },
            { "steps", new [] { new Struct {
                Name = "install-app",
                Action = ComponentAction.EXECUTE_BASH,
                Inputs = new Struct {
                    Commands = new [] { "yum install -y my-container-application" }
                }
            } } }
        } } }
    })
});

var containerRecipe = new ContainerRecipe(this, "ComponentContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo")),
    Components = new [] { new ComponentConfiguration {
        Component = customComponent
    } }
});
AWS-Managed Components in Container Recipes

Use pre-built AWS components:

var containerRecipe = new ContainerRecipe(this, "AmazonManagedContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo")),
    Components = new [] { new ComponentConfiguration {
        Component = AmazonManagedComponent.UpdateOs(this, "UpdateOS", new AmazonManagedComponentOptions {
            Platform = Platform.LINUX
        })
    }, new ComponentConfiguration {
        Component = AmazonManagedComponent.AwsCliV2(this, "AwsCli", new AmazonManagedComponentOptions {
            Platform = Platform.LINUX
        })
    } }
});
Container Recipe Configuration
Custom Dockerfile

Provide your own Dockerfile template:

var containerRecipe = new ContainerRecipe(this, "CustomDockerfileContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo")),
    Dockerfile = DockerfileData.FromInline(@"
    FROM {{{ imagebuilder:parentImage }}}
    CMD [""echo"", ""Hello, world!""]
    {{{ imagebuilder:environments }}}
    {{{ imagebuilder:components }}}
    ")
});
Instance Configuration

Configure the build instance:

var containerRecipe = new ContainerRecipe(this, "InstanceConfigContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo")),
    // Custom ECS-optimized AMI for building
    InstanceImage = ContainerInstanceImage.FromSsmParameterName("/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id"),
    // Additional storage for build process
    InstanceBlockDevices = new [] { new BlockDevice {
        DeviceName = "/dev/xvda",
        Volume = BlockDeviceVolume.Ebs(50, new EbsDeviceOptions {
            Encrypted = true,
            VolumeType = 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.

var component = new Component(this, "MyComponent", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", ComponentSchemaVersion.V1_0 },
        { "phases", new [] { new Dictionary<string, object> {
            { "name", ComponentPhaseName.BUILD },
            { "steps", new [] { new Struct {
                Name = "install-app",
                Action = ComponentAction.EXECUTE_BASH,
                Inputs = new Struct {
                    Commands = new [] { "echo \"Installing my application...\"", "yum update -y" }
                }
            } } }
        } } }
    })
});
Component Data Sources
Inline Component Data

Use ComponentData.fromInline() for existing YAML/JSON definitions:

var component = new Component(this, "InlineComponent", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromInline(@"
    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:

var component = new Component(this, "JsonComponent", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", ComponentSchemaVersion.V1_0 },
        { "phases", new [] { new Dictionary<string, object> {
            { "name", ComponentPhaseName.BUILD },
            { "steps", new [] { new Struct {
                Name = "configure-app",
                Action = ComponentAction.CREATE_FILE,
                Inputs = new Struct {
                    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:

var step = new ComponentDocumentStep {
    Name = "configure-app",
    Action = ComponentAction.CREATE_FILE,
    Inputs = ComponentStepInputs.FromObject(new Dictionary<string, 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:

var phase = new ComponentDocumentPhase {
    Name = ComponentPhaseName.BUILD,
    Steps = new [] { new ComponentDocumentStep {
        Name = "configure-app",
        Action = ComponentAction.CREATE_FILE,
        Inputs = ComponentStepInputs.FromObject(new Dictionary<string, 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:

var component = new Component(this, "StructuredComponent", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromComponentDocumentJsonObject(new ComponentDocument {
        SchemaVersion = ComponentSchemaVersion.V1_0,
        Phases = new [] { new ComponentDocumentPhase {
            Name = ComponentPhaseName.BUILD,
            Steps = new [] { new ComponentDocumentStep {
                Name = "install-with-timeout",
                Action = ComponentAction.EXECUTE_BASH,
                Timeout = Duration.Minutes(10),
                OnFailure = ComponentOnFailure.CONTINUE,
                Inputs = ComponentStepInputs.FromObject(new Dictionary<string, object> {
                    { "commands", new [] { "./install-script.sh" } }
                })
            } }
        } }
    })
});
S3 Component Data

For those components you want to upload or have uploaded to S3:

// Upload a local file
var componentFromAsset = new Component(this, "AssetComponent", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromAsset(this, "ComponentAsset", "./my-component.yml")
});

// Reference an existing S3 object
var bucket = Bucket.FromBucketName(this, "ComponentBucket", "my-components-bucket");
var componentFromS3 = new Component(this, "S3Component", new ComponentProps {
    Platform = Platform.LINUX,
    Data = ComponentData.FromS3(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.

var component = new Component(this, "EncryptedComponent", new ComponentProps {
    Platform = Platform.LINUX,
    KmsKey = new Key(this, "ComponentKey"),
    Data = ComponentData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", ComponentSchemaVersion.V1_0 },
        { "phases", new [] { new Dictionary<string, object> {
            { "name", ComponentPhaseName.BUILD },
            { "steps", new [] { new Struct {
                Name = "secure-setup",
                Action = ComponentAction.EXECUTE_BASH,
                Inputs = new Struct {
                    Commands = new [] { "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
var awsCliComponent = AmazonManagedComponent.AwsCliV2(this, "AwsCli", new AmazonManagedComponentOptions {
    Platform = Platform.LINUX
});

// Update the operating system
var updateComponent = AmazonManagedComponent.UpdateOs(this, "UpdateOS", new AmazonManagedComponentOptions {
    Platform = Platform.LINUX
});

// Reference any AWS-managed component by name
var customAwsComponent = AmazonManagedComponent.FromAmazonManagedComponentName(this, "CloudWatchAgent", "amazon-cloudwatch-agent-linux");
AWS Marketplace Components

You can reference AWS Marketplace components using the marketplace component name and its product ID:

var marketplaceComponent = AwsMarketplaceComponent.FromAwsMarketplaceComponentAttributes(this, "MarketplaceComponent", new AwsMarketplaceComponentAttributes {
    ComponentName = "my-marketplace-component",
    MarketplaceProductId = "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.

var infrastructureConfiguration = new InfrastructureConfiguration(this, "InfrastructureConfiguration", new InfrastructureConfigurationProps {
    InfrastructureConfigurationName = "test-infrastructure-configuration",
    Description = "An Infrastructure Configuration",
    // Optional - instance types to use for build/test
    InstanceTypes = new [] { InstanceType.Of(InstanceClass.STANDARD7_INTEL, InstanceSize.LARGE), InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.LARGE) },
    // Optional - create an instance profile with necessary permissions
    InstanceProfile = new InstanceProfile(this, "InstanceProfile", new InstanceProfileProps {
        InstanceProfileName = "test-instance-profile",
        Role = new Role(this, "InstanceProfileRole", new RoleProps {
            AssumedBy = ServicePrincipal.FromStaticServicePrincipleName("ec2.amazonaws.com"),
            ManagedPolicies = new [] { ManagedPolicy.FromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"), ManagedPolicy.FromAwsManagedPolicyName("EC2InstanceProfileForImageBuilder") }
        })
    }),
    // Use VPC network configuration
    Vpc = vpc,
    SubnetSelection = new SubnetSelection { SubnetType = SubnetType.PUBLIC },
    SecurityGroups = new [] { SecurityGroup.FromSecurityGroupId(this, "SecurityGroup", vpc.VpcDefaultSecurityGroup) },
    KeyPair = KeyPair.FromKeyPairName(this, "KeyPair", "imagebuilder-instance-key-pair"),
    TerminateInstanceOnFailure = true,
    // Optional - IMDSv2 settings
    HttpTokens = HttpTokens.REQUIRED,
    HttpPutResponseHopLimit = 1,
    // Optional - publish image completion messages to an SNS topic
    NotificationTopic = Topic.FromTopicArn(this, "Topic", FormatArn(new ArnComponents { Service = "sns", Resource = "image-builder-topic" })),
    // Optional - log settings. Logging is enabled by default
    Logging = new InfrastructureConfigurationLogging {
        S3Bucket = Bucket.FromBucketName(this, "LogBucket", $"imagebuilder-logging-{Aws.ACCOUNT_ID}"),
        S3KeyPrefix = "imagebuilder-logs"
    },
    // Optional - host placement settings
    Ec2InstanceAvailabilityZone = Stack.Of(this).AvailabilityZones[0],
    Ec2InstanceHostId = dedicatedHost.AttrHostId,
    Ec2InstanceTenancy = Tenancy.HOST,
    ResourceTags = new Dictionary<string, string> {
        { "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.:

var distributionConfiguration = new DistributionConfiguration(this, "DistributionConfiguration", new DistributionConfigurationProps {
    DistributionConfigurationName = "test-distribution-configuration",
    Description = "A Distribution Configuration",
    AmiDistributions = new [] { new AmiDistribution {
        // Distribute AMI to us-east-2 and publish the AMI ID to an SSM parameter
        Region = "us-east-2",
        SsmParameters = new [] { new SSMParameterConfigurations {
            Parameter = StringParameter.FromStringParameterAttributes(this, "CrossRegionParameter", new StringParameterAttributes {
                ParameterName = "/imagebuilder/ami",
                ForceDynamicReference = true
            })
        } }
    } }
});

// For AMI-based image builds - add an AMI distribution in the current region
distributionConfiguration.AddAmiDistributions(new AmiDistribution {
    AmiName = "imagebuilder-{{ imagebuilder:buildDate }}",
    AmiDescription = "Build AMI",
    AmiKmsKey = Key.FromLookup(this, "ComponentKey", new KeyLookupOptions { AliasName = "alias/distribution-encryption-key" }),
    // Copy the AMI to different accounts
    AmiTargetAccountIds = new [] { "123456789012", "098765432109" },
    // Add launch permissions on the AMI
    AmiLaunchPermission = new AmiLaunchPermission {
        OrganizationArns = new [] { FormatArn(new ArnComponents { Region = "", Service = "organizations", Resource = "organization", ResourceName = "o-1234567abc" }) },
        OrganizationalUnitArns = new [] { FormatArn(new ArnComponents {
            Region = "",
            Service = "organizations",
            Resource = "ou",
            ResourceName = "o-1234567abc/ou-a123-b4567890"
        }) },
        IsPublicUserGroup = true,
        AccountIds = new [] { "234567890123" }
    },
    // Attach tags to the AMI
    AmiTags = new Dictionary<string, string> {
        { "Environment", "production" },
        { "Version", "{{ imagebuilder:buildVersion }}" }
    },
    // Optional - publish the distributed AMI ID to an SSM parameter
    SsmParameters = new [] { new SSMParameterConfigurations {
        Parameter = StringParameter.FromStringParameterAttributes(this, "Parameter", new StringParameterAttributes {
            ParameterName = "/imagebuilder/ami",
            ForceDynamicReference = true
        })
    }, new SSMParameterConfigurations {
        AmiAccount = "098765432109",
        DataType = ParameterDataType.TEXT,
        Parameter = StringParameter.FromStringParameterAttributes(this, "CrossAccountParameter", new StringParameterAttributes {
            ParameterName = "imagebuilder-prod-ami",
            ForceDynamicReference = true
        })
    } },
    // Optional - create a new launch template version with the distributed AMI ID
    LaunchTemplates = new [] { new LaunchTemplateConfiguration {
        LaunchTemplate = LaunchTemplate.FromLaunchTemplateAttributes(this, "LaunchTemplate", new LaunchTemplateAttributes {
            LaunchTemplateId = "lt-1234"
        }),
        SetDefaultVersion = true
    }, new LaunchTemplateConfiguration {
        AccountId = "123456789012",
        LaunchTemplate = LaunchTemplate.FromLaunchTemplateAttributes(this, "CrossAccountLaunchTemplate", new LaunchTemplateAttributes {
            LaunchTemplateId = "lt-5678"
        }),
        SetDefaultVersion = true
    } },
    // Optional - enable Fast Launch on an imported launch template
    FastLaunchConfigurations = new [] { new FastLaunchConfiguration {
        Enabled = true,
        LaunchTemplate = LaunchTemplate.FromLaunchTemplateAttributes(this, "FastLaunchLT", new LaunchTemplateAttributes {
            LaunchTemplateName = "fast-launch-lt"
        }),
        MaxParallelLaunches = 10,
        TargetSnapshotCount = 2
    } },
    // Optional - license configurations to apply to the AMI
    LicenseConfigurationArns = new [] { "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:

var ecrRepository = Repository.FromRepositoryName(this, "ECRRepository", "my-repo");
var imageBuilderRepository = Repository.FromEcr(ecrRepository);
Defining a container distribution

You can configure the container repositories as well as the description and tags applied to the distributed container images:

var ecrRepository = Repository.FromRepositoryName(this, "ECRRepository", "my-repo");
var containerRepository = Repository.FromEcr(ecrRepository);
var containerDistributionConfiguration = new DistributionConfiguration(this, "ContainerDistributionConfiguration");

containerDistributionConfiguration.AddContainerDistributions(new ContainerDistribution {
    ContainerRepository = containerRepository,
    ContainerDescription = "Test container image",
    ContainerTags = new [] { "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.

var workflow = new Workflow(this, "MyWorkflow", new WorkflowProps {
    WorkflowType = WorkflowType.BUILD,
    Data = WorkflowData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", WorkflowSchemaVersion.V1_0 },
        { "steps", new [] { new Dictionary<string, object> {
            { "name", "LaunchBuildInstance" },
            { "action", WorkflowAction.LAUNCH_INSTANCE },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                WaitFor = "ssmAgent"
            } }
        }, new Dictionary<string, object> {
            { "name", "ExecuteComponents" },
            { "action", WorkflowAction.EXECUTE_COMPONENTS },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        }, new Dictionary<string, object> {
            { "name", "CreateImage" },
            { "action", WorkflowAction.CREATE_IMAGE },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        }, new Dictionary<string, object> {
            { "name", "TerminateInstance" },
            { "action", WorkflowAction.TERMINATE_INSTANCE },
            { "onFailure", WorkflowOnFailure.CONTINUE },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        } } },
        { "outputs", new [] { new Dictionary<string, string> {
            { "name", "ImageId" },
            { "value", "$.stepOutputs.CreateImage.imageId" }
        } } }
    })
});
Workflow Data Sources
Inline Workflow Data

Use WorkflowData.fromInline() for existing YAML/JSON definitions:

var workflow = new Workflow(this, "InlineWorkflow", new WorkflowProps {
    WorkflowType = WorkflowType.TEST,
    Data = WorkflowData.FromInline(@"
    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:

var workflow = new Workflow(this, "JsonWorkflow", new WorkflowProps {
    WorkflowType = WorkflowType.BUILD,
    Data = WorkflowData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", WorkflowSchemaVersion.V1_0 },
        { "steps", new [] { new Dictionary<string, object> {
            { "name", "LaunchBuildInstance" },
            { "action", WorkflowAction.LAUNCH_INSTANCE },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                WaitFor = "ssmAgent"
            } }
        }, new Dictionary<string, object> {
            { "name", "ExecuteComponents" },
            { "action", WorkflowAction.EXECUTE_COMPONENTS },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        }, new Dictionary<string, object> {
            { "name", "CreateImage" },
            { "action", WorkflowAction.CREATE_IMAGE },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        }, new Dictionary<string, object> {
            { "name", "TerminateInstance" },
            { "action", WorkflowAction.TERMINATE_INSTANCE },
            { "onFailure", WorkflowOnFailure.CONTINUE },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        } } },
        { "outputs", new [] { new Dictionary<string, string> {
            { "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
var workflowFromAsset = new Workflow(this, "AssetWorkflow", new WorkflowProps {
    WorkflowType = WorkflowType.BUILD,
    Data = WorkflowData.FromAsset(this, "WorkflowAsset", "./my-workflow.yml")
});

// Reference an existing S3 object
var bucket = Bucket.FromBucketName(this, "WorkflowBucket", "my-workflows-bucket");
var workflowFromS3 = new Workflow(this, "S3Workflow", new WorkflowProps {
    WorkflowType = WorkflowType.BUILD,
    Data = WorkflowData.FromS3(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.

var workflow = new Workflow(this, "EncryptedWorkflow", new WorkflowProps {
    WorkflowType = WorkflowType.BUILD,
    KmsKey = new Key(this, "WorkflowKey"),
    Data = WorkflowData.FromJsonObject(new Dictionary<string, object> {
        { "schemaVersion", WorkflowSchemaVersion.V1_0 },
        { "steps", new [] { new Dictionary<string, object> {
            { "name", "LaunchBuildInstance" },
            { "action", WorkflowAction.LAUNCH_INSTANCE },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                WaitFor = "ssmAgent"
            } }
        }, new Dictionary<string, object> {
            { "name", "CreateImage" },
            { "action", WorkflowAction.CREATE_IMAGE },
            { "onFailure", WorkflowOnFailure.ABORT },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        }, new Dictionary<string, object> {
            { "name", "TerminateInstance" },
            { "action", WorkflowAction.TERMINATE_INSTANCE },
            { "onFailure", WorkflowOnFailure.CONTINUE },
            { "inputs", new Struct {
                InstanceId = "i-123"
            } }
        } } },
        { "outputs", new [] { new Dictionary<string, string> {
            { "name", "ImageId" },
            { "value", "$.stepOutputs.CreateImage.imageId" }
        } } }
    })
});
AWS-Managed Workflows

AWS provides a collection of workflows for common scenarios:

// Build workflows
var buildImageWorkflow = AmazonManagedWorkflow.BuildImage(this, "BuildImage");
var buildContainerWorkflow = AmazonManagedWorkflow.BuildContainer(this, "BuildContainer");

// Test workflows
var testImageWorkflow = AmazonManagedWorkflow.TestImage(this, "TestImage");
var testContainerWorkflow = AmazonManagedWorkflow.TestContainer(this, "TestContainer");

// Distribution workflows
var distributeContainerWorkflow = AmazonManagedWorkflow.DistributeContainer(this, "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:

var lifecyclePolicy = new LifecyclePolicy(this, "MyLifecyclePolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { AgeFilter = new LifecyclePolicyAgeFilter { Age = Duration.Days(30) } }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Environment", "development" } }
    }
});

Create a lifecycle policy to keep only the 10 most recent container images:

var containerLifecyclePolicy = new LifecyclePolicy(this, "ContainerLifecyclePolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.CONTAINER_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { CountFilter = new LifecyclePolicyCountFilter { Count = 10 } }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Application", "web-app" } }
    }
});
Lifecycle Policy Resource Selection
Tag-Based Resource Selection

Apply lifecycle policies to images with specific tags:

var tagBasedPolicy = new LifecyclePolicy(this, "TagBasedPolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { AgeFilter = new LifecyclePolicyAgeFilter { Age = Duration.Days(90) } }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> {
            { "Environment", "staging" },
            { "Team", "backend" }
        }
    }
});
Recipe-Based Resource Selection

Apply lifecycle policies to specific image or container recipes:

var imageRecipe = new ImageRecipe(this, "MyImageRecipe", new ImageRecipeProps {
    BaseImage = BaseImage.FromSsmParameterName("/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64")
});

var containerRecipe = new ContainerRecipe(this, "MyContainerRecipe", new ContainerRecipeProps {
    BaseImage = BaseContainerImage.FromDockerHub("amazonlinux", "latest"),
    TargetRepository = Repository.FromEcr(Repository.FromRepositoryName(this, "Repository", "my-container-repo"))
});

var recipeBasedPolicy = new LifecyclePolicy(this, "RecipeBasedPolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { CountFilter = new LifecyclePolicyCountFilter { Count = 5 } }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Recipes = new [] { imageRecipe, containerRecipe }
    }
});
Lifecycle Policy Rules
Age-Based Rules

Delete images older than a specific time period:

var ageBasedPolicy = new LifecyclePolicy(this, "AgeBasedPolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction {
            Type = LifecyclePolicyActionType.DELETE,
            IncludeAmis = true,
            IncludeSnapshots = true
        },
        Filter = new LifecyclePolicyFilter {
            AgeFilter = new LifecyclePolicyAgeFilter {
                Age = Duration.Days(60),
                RetainAtLeast = 3
            }
        }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Environment", "testing" } }
    }
});
Count-Based Rules

Keep only a specific number of the most recent images:

var countBasedPolicy = new LifecyclePolicy(this, "CountBasedPolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.CONTAINER_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { CountFilter = new LifecyclePolicyCountFilter { Count = 15 } }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Application", "microservice" } }
    }
});
Multiple Lifecycle Rules

Implement a graduated approach with multiple actions:

var graduatedPolicy = new LifecyclePolicy(this, "GraduatedPolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        // First: Deprecate images after 30 days
        Action = new LifecyclePolicyAction {
            Type = LifecyclePolicyActionType.DEPRECATE,
            IncludeAmis = true
        },
        Filter = new LifecyclePolicyFilter {
            AgeFilter = new LifecyclePolicyAgeFilter {
                Age = Duration.Days(30),
                RetainAtLeast = 5
            }
        }
    }, new LifecyclePolicyDetail {
        // Second: Disable images after 60 days
        Action = new LifecyclePolicyAction {
            Type = LifecyclePolicyActionType.DISABLE,
            IncludeAmis = true
        },
        Filter = new LifecyclePolicyFilter {
            AgeFilter = new LifecyclePolicyAgeFilter {
                Age = Duration.Days(60),
                RetainAtLeast = 3
            }
        }
    }, new LifecyclePolicyDetail {
        // Finally: Delete images after 90 days
        Action = new LifecyclePolicyAction {
            Type = LifecyclePolicyActionType.DELETE,
            IncludeAmis = true,
            IncludeSnapshots = true
        },
        Filter = new LifecyclePolicyFilter {
            AgeFilter = new LifecyclePolicyAgeFilter {
                Age = Duration.Days(90),
                RetainAtLeast = 1
            }
        }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Environment", "production" } }
    }
});
Lifecycle Policy Exclusion Rules
AMI Exclusion Rules

Exclude specific AMIs from lifecycle actions based on various criteria:

var excludeAmisPolicy = new LifecyclePolicy(this, "ExcludeAmisPolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { AgeFilter = new LifecyclePolicyAgeFilter { Age = Duration.Days(30) } },
        ExclusionRules = new LifecyclePolicyExclusionRules {
            AmiExclusionRules = new LifecyclePolicyAmiExclusionRules {
                IsPublic = true,  // Exclude public AMIs
                LastLaunched = Duration.Days(7),  // Exclude AMIs launched in last 7 days
                Regions = new [] { "us-west-2", "eu-west-1" },  // Exclude AMIs in specific regions
                SharedAccounts = new [] { "123456789012" },  // Exclude AMIs shared with specific accounts
                Tags = new Dictionary<string, string> {
                    { "Protected", "true" },
                    { "Environment", "production" }
                }
            }
        }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Team", "infrastructure" } }
    }
});
Image Exclusion Rules

Exclude Image Builder images with protective tags:

var excludeImagesPolicy = new LifecyclePolicy(this, "ExcludeImagesPolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.CONTAINER_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { CountFilter = new LifecyclePolicyCountFilter { Count = 20 } },
        ExclusionRules = new LifecyclePolicyExclusionRules {
            ImageExclusionRules = new LifecyclePolicyImageExclusionRules {
                Tags = new Dictionary<string, string> {
                    { "DoNotDelete", "true" },
                    { "Critical", "baseline" }
                }
            }
        }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Application", "frontend" } }
    }
});
Advanced Lifecycle Configuration
Custom Execution Roles

Provide your own IAM execution role with specific permissions:

var executionRole = new Role(this, "LifecycleExecutionRole", new RoleProps {
    AssumedBy = new ServicePrincipal("imagebuilder.amazonaws.com"),
    ManagedPolicies = new [] { ManagedPolicy.FromAwsManagedPolicyName("service-role/EC2ImageBuilderLifecycleExecutionPolicy") }
});

var customRolePolicy = new LifecyclePolicy(this, "CustomRolePolicy", new LifecyclePolicyProps {
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    ExecutionRole = executionRole,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { AgeFilter = new LifecyclePolicyAgeFilter { Age = Duration.Days(45) } }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Environment", "development" } }
    }
});
Lifecycle Policy Status

Control whether the lifecycle policy is active:

var disabledPolicy = new LifecyclePolicy(this, "DisabledPolicy", new LifecyclePolicyProps {
    LifecyclePolicyName = "my-disabled-policy",
    Description = "A lifecycle policy that is temporarily disabled",
    Status = LifecyclePolicyStatus.DISABLED,
    ResourceType = LifecyclePolicyResourceType.AMI_IMAGE,
    Details = new [] { new LifecyclePolicyDetail {
        Action = new LifecyclePolicyAction { Type = LifecyclePolicyActionType.DELETE },
        Filter = new LifecyclePolicyFilter { AgeFilter = new LifecyclePolicyAgeFilter { Age = Duration.Days(30) } }
    } },
    ResourceSelection = new LifecyclePolicyResourceSelection {
        Tags = new Dictionary<string, string> { { "Environment", "testing" } }
    },
    Tags = new Dictionary<string, string> {
        { "Owner", "DevOps" },
        { "CostCenter", "Engineering" }
    }
});
Importing Lifecycle Policies

Reference lifecycle policies created outside CDK:

// Import by name
var importedByName = LifecyclePolicy.FromLifecyclePolicyName(this, "ImportedByName", "existing-lifecycle-policy");

// Import by ARN
var importedByArn = LifecyclePolicy.FromLifecyclePolicyArn(this, "ImportedByArn", "arn:aws:imagebuilder:us-east-1:123456789012:lifecycle-policy/my-policy");

importedByName.GrantRead(lambdaRole);
importedByArn.Grant(lambdaRole, "imagebuilder:UpdateLifecyclePolicy");

Changes from Previous Version

No structural changes between v2.273.0-alpha.0 and v2.274.0-alpha.0.

Adoption Assessment

A verified publisher signal is available. Assess fit from the package's supported frameworks, license and dependency graph rather than popularity alone.

This version is marked prerelease. Validate its API and upgrade path before production use.Compatibility metadata lists 1 target framework; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.