Search code examples
amazon-web-servicesdevopsaws-cliamazon-imagebuilderaws-imagelifecycle

How to tag Images output by AWS Image Builder Pipeline to include the Image in a Lifecycle Policy


The AWS Image Builder Lifecycle will automatically deprecate, disable and delete Images and their associated AMIs and Snapshots based on a set of rules. This keeps the list of available images current and reduces costs by cleaning up obsolete AMIs and Snapshots.

https://docs.aws.amazon.com/imagebuilder/latest/userguide/manage-image-lifecycles.html

The Lifecycle Policy allows the scope of Images under management to be determined via a list of Image Recipe Versions or via a tag on the output Images. In my case we have a number of pipelines and continually changing recipe versions. It is not practical to use Recipe versions as the scope - tags would be easier to manage.

The issue is that AWS don't allow tagging of Images via the console, one needs to use the CLI. The Image Pipeline runs on a schedule, but it doesn't currently have a configuration to add tags to Images it produces, it only tags the AMIs and Snapshots.

What is the simplest way to automatically tag Images output by Image Pipeline so that they can be included in a Lifecycle Policy?


Solution

  • Based on this answer How to dynamically tag an AMI created by an EC2 Image Builder I have found a relatively simple solution. The difference is that we need to tag the Image, not the AMI. The Images need a ImageLifecyle=true tag added after they are created.

    I wrote a test component that is invoked during an Image recipe after an AMI is built to tag the Image using the aws imagebuilder tag-resource CLI command.

    The component looks like this:

        name: Tag Image to enrol in Lifecycle Management
        description: This component will enroll the Image Builder Image into Lifecycle Management by adding a tag to the Image
        schemaVersion: 1.0
        
        phases:
          - name: test
            steps:
              - name: 'applytag'
                action: ExecuteBash
                inputs:
                  commands:
                    - |
                      TOKEN=$(curl -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 900" http://169.254.169.254/latest/api/token)
                      AMI=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/ami-id)
                      IMAGE_VERSION_ARN=$(aws ec2 describe-images --filters Name=image-id,Values=$AMI --region ${AWS::Region} --query "Images[].Tags[?Key=='Ec2ImageBuilderArn'].Value" --output text)
                      aws imagebuilder tag-resource --resource-arn $IMAGE_VERSION_ARN --tags "ImageLifecyle=true" --region ${AWS::Region}
                      echo "Tagged $IMAGE_VERSION_ARN with ImageLifecycle=true"
    

    The component needs to be included in the Image Recipe and the ImageTestsConfiguration enabled in the Image Pipeline.

    This causes an EC2 instance to be instantiated using the new AMI, which runs the commands to obtain the AMI, then the Image and finally tag it with the Lifecycle Policy tag.

    Finally the EC2 Instance Profile (IAM Role) used by the Infrastructure Configuration also needs to include a policy allowing ec2:DescribeImages and imagebuilder:TagResource.