Control Improvements for Distribution of Approved AMIs

John Byrd
4 min readDec 5, 2020

Enforcing the use of approved and secured resources within AWS compute just got simpler. Thanks to a recent update by AWS, organizations can supplement their image creation process with additional guardrails. While the ability to restrict the creation and state of an EC2 down to the tags is not new, there was a gap in enforcing the use of tags on images for downstream reference of consumers — until now.

Addressing issues with images prior to their consumption by pipelines, developers, or engineers creates a checkpoint for analysis and remediation. Discovering a vulnerability or misconfiguration on a newly created machine implies the issue also exists with the image, which means all other machines created from that image will share this problem. Time spent remediating images provides exponentially more value than the same issue being addressed multiple times across multiple teams.

Thanks to the introduction of tag-on-creation support for AMIs, governance can be ensured from a couple of angles:

  1. Forcing images to be tagged at the time of creation.
  2. Preventing users from using AMIs that do not have tags designating them as approved.

To address the first point, the goal must be determined from the following outcomes:

  1. Require AMIs to be created with a specific Tag Key with no regard for the Tag Value used.
  2. Require AMIs to be created with a specific Tag Key and a specific Tag Value.
  3. Require AMIs to be created with a specific Tag Key and any value in the Tag Value.

Once the images are being created with specific tags, we will need to ensure that users are required to select AMIs that include the approved tagging model. (There is additional work to apply controls for ensuring the consumers being forced to pick from tagging images cannot, in fact, tag images with these values themselves, thereby bypassing what we are attempting to achieve here. These will not be included here.)

The IAM principal used by the producers of the images will need to have the ec2:CreateImage permission allowed. While adding conditions with an allow is possible, unless further controls are needed for this action, granting the action and then adding further restrictions provides a different approach to the guardrails. For the following examples, it will be assumed there is a policy granting the ec2:CreateImage action attached in cooperation with the IAM statements below.

1. Requiring AMIs to be created with a specific Tag Key with no regard for the Tag Value should more technically be described as “Denying the creation of images without the presence of a specific Tag Key.” This is done by adding a Deny statement for ec2:CreateImage with a condition that specifies resources where there is no Tag Key that matches the one identified.

{
"Sid": "TagRequirement",
"Effect": "Deny",
"Action": "ec2:CreateImage",
"Resource": [
"arn:aws:ec2:*:*:image/*",
"arn:aws:ec2:*:*:snapshot/*
],
"Condition": {
"StringNotEquals": {
"aws:TagKeys": "<Key1>"
}
}
}

2. Requiring AMIs to be created with a specific Tag Key and Value is accomplished by Denying the creation of images where the string representative of the Tag Key and its Value are not present in the API call.

{
"Sid": "TagRequirement",
"Effect": "Deny",
"Action": "ec2:CreateImage",
"Resource": [
"arn:aws:ec2:*:*:image/*",
"arn:aws:ec2:*:*:snapshot/*
],
"Condition": {
"StringNotEquals": {
"aws:RequestTag/<Key1>": "<Value1>"
}
}
}

3. The prevention of AMI creation with a specific Tag Key and a non-specific Tag Value can be accomplished using some RegEx quantifiers outlined in this AWS blog. Note that the use of "*" allows any value, including null, to be accepted. By adding the "?*", it ensures that at least 1 character must be present. If there is an expected naming convention being used, ? should be substituted for single characters and * should be used for variables that allow blank or undetermined number of characters. (Note that since we used these RegEx characters, we had to change the condition to StringNotLike away from StringNotEqual.)

{
"Sid": "TagRequirement",
"Effect": "Deny",
"Action": "ec2:CreateImage",
"Resource": [
"arn:aws:ec2:*:*:image/*",
"arn:aws:ec2:*:*:snapshot/*
],
"Condition": {
"StringNotLike": {
"aws:RequestTag/<Key1>": "?*"
}
}
}

Once the producers are creating images with expected tags, consumers can be limited using a similar method. When spinning up new EC2 instances, the ec2:RunInstances action can be conditioned with minor variations to the above examples.

Notice the global condition context key aws:RequestTag has been replaced with ec2:ResourceTag. This is because the context that we are now checking the tag is not the originating request; it’s the tag on the EC2 resource.

{
"Sid": "RequiresTags",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"ec2:ResourceTag/<Tag1>": "<Key1>"
}
}
}

Additionally, similar to the previous examples, the RegEx values require the StringNotLike condition and can use the wildcard (*) or individual character variable (?) to build the strings required for the organization’s standards.

{
"Sid": "RequiresTags",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "*",
"Condition": {
"StringNotLike": {
"ec2:ResourceTag/<Tag1>": "?*"
}
}
}

Taking these steps can move one step closer to controlling the ephemeral nature of the cloud. By including security scanning of these base AMIs, proactive steps can be taken to provide guardrails to reduce the level of effort required for remediation actions.

Where resources may pop in and out of existence, it becomes paramount for vulnerabilities and misconfigurations to get addressed before new nodes of compute are spun up for utilization.

It does appear that AWS keeps a list of resources that support tagging on creation. Approaches similar to the one outlined above should be able to be applied to many of these resources.

--

--

John Byrd

Modernizing companies’ AWS security and governance programs at scale.