Tried enforcing the use of approved AMIs with the new Amazon EC2 feature AMI Watermarks
This page has been translated by machine translation. View original
Introduction
On June 24, 2026, the AMI Watermarks feature was added to Amazon EC2.
Previously, tracking AMI provenance relied solely on naming conventions and tags, making it difficult to understand the relationship with the original AMI after copies and derivations. AMI Watermarks is a feature that solves this problem. It embeds structured identifiers in private AMIs and automatically carries them over during copies and derivations.
Here is a summary of the key points of the feature.
| Item | Details |
|---|---|
| WatermarkKey format | AccountID:WatermarkName (AccountID is automatically assigned) |
| Propagation | Automatically inherited by CopyImage and CreateImage |
| Limit | Maximum 5 per AMI |
| Target | Private AMIs only (cannot be assigned to public AMIs) |
| Cost | No additional charge |
| Regions | All regions (including China and GovCloud) |
Basic Watermark Operations
The verification environment is as follows.
- Region: ap-northeast-1
- CLI: aws-cli/2.35.11
Assigning
Since watermarks can only be assigned to private AMIs, first copy a public AMI to create a private AMI.
aws ec2 copy-image \
--source-image-id ami-0bc1ef7af11bba977 \
--source-region ap-northeast-1 \
--region ap-northeast-1 \
--name "watermark-test"
{
"ImageId": "ami-0496605161386a315"
}
After the AMI becomes available, assign a watermark.
aws ec2 attach-image-watermark \
--image-id ami-0496605161386a315 \
--watermark-name "my-approved-ami" \
--region ap-northeast-1
{
"WatermarkKey": "123456789012:my-approved-ami"
}
The WatermarkKey is generated in a format with the account ID automatically prepended.
Verifying
You can check it in the ImageWatermarks field of describe-images.
aws ec2 describe-images --image-ids ami-0496605161386a315 --region ap-northeast-1
"ImageWatermarks": [
{
"WatermarkKey": "123456789012:my-approved-ami",
"SourceImageRegion": "ap-northeast-1",
"SourceImageId": "ami-0496605161386a315",
"SourceImageCreationTime": "2026-06-24T23:22:04.976000+00:00",
"WatermarkCreationTime": "2026-06-24T23:23:15.914000+00:00"
}
]
Deleting
You can delete a watermark with detach-image-watermark. Since the AMI used earlier will be used in subsequent verifications, this was confirmed with a separate test AMI.
aws ec2 detach-image-watermark \
--image-id ami-094676932a70ae1b1 \
--watermark-key "123456789012:my-approved-ami" \
--region ap-northeast-1
{
"Return": true
}
After deletion, the ImageWatermarks field became empty in describe-images. Note that according to the documentation, watermarks already propagated to derived AMIs are not affected when deleted from the source AMI.
Filtering
You can search across AMIs with a specific watermark using the image-watermark-key filter.
aws ec2 describe-images \
--filters "Name=image-watermark-key,Values=123456789012:my-approved-ami" \
--region ap-northeast-1
Verifying Propagation to Derived AMIs
I launched an instance from a watermarked AMI and created a new AMI from that instance using create-image.
# Launch instance
aws ec2 run-instances \
--image-id ami-094676932a70ae1b1 \
--instance-type t4g.nano \
--subnet-id subnet-0123456789abcdef0 \
--no-associate-public-ip-address \
--region ap-northeast-1
# Create AMI
aws ec2 create-image \
--instance-id i-0abc1234def567890 \
--name "watermark-derived-test" \
--no-reboot \
--region ap-northeast-1
When I checked the watermarks of the derived AMI (ami-03df64fb303906bfb), all five watermarks from the source AMI had been inherited. The SourceImageId of each watermark points to the source AMI (ami-094676932a70ae1b1), and the timestamps are also preserved as-is. I was able to confirm that watermarks are reliably propagated through CreateImage derivation.
All 5 outputs (click to expand)
[
{
"WatermarkKey": "123456789012:test-wm-1",
"SourceImageRegion": "ap-northeast-1",
"SourceImageId": "ami-094676932a70ae1b1",
"SourceImageCreationTime": "2026-06-24T23:30:43.576000+00:00",
"WatermarkCreationTime": "2026-06-24T23:33:26.234000+00:00"
},
{
"WatermarkKey": "123456789012:test-wm-2",
"SourceImageRegion": "ap-northeast-1",
"SourceImageId": "ami-094676932a70ae1b1",
"SourceImageCreationTime": "2026-06-24T23:30:43.576000+00:00",
"WatermarkCreationTime": "2026-06-24T23:33:26.875000+00:00"
},
{
"WatermarkKey": "123456789012:test-wm-3",
"SourceImageRegion": "ap-northeast-1",
"SourceImageId": "ami-094676932a70ae1b1",
"SourceImageCreationTime": "2026-06-24T23:30:43.576000+00:00",
"WatermarkCreationTime": "2026-06-24T23:33:27.649000+00:00"
},
{
"WatermarkKey": "123456789012:test-wm-4",
"SourceImageRegion": "ap-northeast-1",
"SourceImageId": "ami-094676932a70ae1b1",
"SourceImageCreationTime": "2026-06-24T23:30:43.576000+00:00",
"WatermarkCreationTime": "2026-06-24T23:33:28.434000+00:00"
},
{
"WatermarkKey": "123456789012:test-wm-5",
"SourceImageRegion": "ap-northeast-1",
"SourceImageId": "ami-094676932a70ae1b1",
"SourceImageCreationTime": "2026-06-24T23:30:43.576000+00:00",
"WatermarkCreationTime": "2026-06-24T23:33:29.139000+00:00"
}
]
Limit Testing
I assigned watermarks consecutively to a single AMI to verify the limit.
for i in 1 2 3 4 5 6; do
echo "--- Attach watermark-$i ---"
aws ec2 attach-image-watermark \
--image-id ami-094676932a70ae1b1 \
--watermark-name "test-wm-$i" \
--region ap-northeast-1
done
The 1st through 5th were assigned successfully, but the 6th produced the following error.
An error occurred (ResourceLimitExceeded) when calling the AttachImageWatermark operation:
Can't attach the watermark because the image already has the maximum number of watermarks (5).
Detach unused watermarks, and try again.
As stated in the documentation, the limit is 5 per AMI.
Verifying That Impersonation Is Not Possible
I attempted to assign a watermark by specifying a string resembling another account ID containing a colon (:).
aws ec2 attach-image-watermark \
--image-id ami-0b685cdf524897143 \
--watermark-name "999999999999:prod-baseline" \
--region ap-northeast-1
An error occurred (InvalidParameter) when calling the AttachImageWatermark operation:
The watermark name isn't valid. The name must be 3-128 characters and can contain only
letters (A-Z, a-z), numbers (0-9), spaces, and the following characters: () [] . / - ' @ _.
Since colons are not allowed characters, an error occurred. When a valid name is specified, the server automatically prepends the current account ID as the prefix of the WatermarkKey.
aws ec2 attach-image-watermark \
--image-id ami-0b685cdf524897143 \
--watermark-name "prod-baseline" \
--region ap-northeast-1
{
"WatermarkKey": "123456789012:prod-baseline"
}
Since the account ID portion of the WatermarkKey cannot be specified by the user, it is not possible to newly assign a watermark claiming to be from a different account ID.
Enforcing Governance Through Integration with Allowed AMIs
Verification in audit mode
First, I set the ImageWatermarks condition in audit mode and checked the allowed status of AMIs.
# Enable audit mode
aws ec2 enable-allowed-images-settings \
--allowed-images-settings-state audit-mode \
--region ap-northeast-1
# Set watermark condition
aws ec2 replace-image-criteria-in-allowed-images-settings \
--image-criteria '[{"ImageWatermarks":[{"WatermarkKey":"123456789012:my-approved-ami"}]}]' \
--region ap-northeast-1
{
"State": "audit-mode",
"ImageCriteria": [
{
"ImageWatermarks": [
{
"WatermarkKey": "123456789012:my-approved-ami"
}
]
}
],
"ManagedBy": "account"
}
In audit mode, the ImageAllowed flag is added to AMIs, but no launch restrictions are applied.
# AMI with watermark
aws ec2 describe-images --image-ids ami-0496605161386a315 \
--query 'Images[0].ImageAllowed' --output text
# → true
# AMI without watermark (public)
aws ec2 describe-images --image-ids ami-0bc1ef7af11bba977 \
--query 'Images[0].ImageAllowed' --output text
# → false
Launch restriction testing with enabled
I switched to enabled and verified actual launch permissions.
aws ec2 enable-allowed-images-settings \
--allowed-images-settings-state enabled \
--region ap-northeast-1
Result of attempting to launch with an AMI without a watermark:
aws ec2 run-instances \
--image-id ami-0bc1ef7af11bba977 \
--instance-type t4g.nano \
--subnet-id subnet-0123456789abcdef0 \
--region ap-northeast-1
An error occurred (InvalidAMIID.NotFound) when calling the RunInstances operation:
The image id '[ami-0bc1ef7af11bba977]' does not exist
For AMIs that are not allowed, RunInstances returns InvalidAMIID.NotFound (the same error as a non-existent AMI), and the launch is rejected.
Result of launching with a watermarked AMI:
aws ec2 run-instances \
--image-id ami-0496605161386a315 \
--instance-type t4g.nano \
--subnet-id subnet-0123456789abcdef0 \
--region ap-northeast-1
{
"InstanceId": "i-0def4567abc890123",
"State": "pending"
}
The instance launched successfully from the watermarked AMI.
After verification, Allowed AMIs was returned to disabled.
Wildcard Support
According to the documentation, the WatermarkKey specified in the ImageWatermarks condition of Allowed AMIs supports wildcards (*, ?).
{
"ImageWatermarks": [
{
"WatermarkKey": "111122223333:prod-*",
"MaximumDaysSinceWatermarkCreated": 90
}
]
}
With this configuration, only AMIs with a watermark starting with prod- assigned by account 111122223333 are permitted. In addition, a condition that the WatermarkCreationTime is within 90 days is also applied, allowing automatic restriction of the use of older AMIs. By standardizing naming conventions across the organization, flexible filtering becomes possible.
Operational Design Patterns
Based on the verification results so far, I will organize a configuration for incorporating AMI Watermarks into organizational governance.
┌─────────────────────────────────────────────────────┐
│ AMI Build Account (111122223333) │
│ - Create AMI with EC2 Image Builder │
│ - Assign watermark after creation │
│ - Deny DetachImageWatermark via IAM/SCP │
└──────────────────────┬──────────────────────────────┘
│ AMI sharing or copying
▼
┌─────────────────────────────────────────────────────┐
│ Workload Account │
│ Allowed AMIs (enabled): │
│ WatermarkKey: "111122223333:golden-*" │
│ → Can only launch from AMIs with this watermark │
└─────────────────────────────────────────────────────┘
Impersonation prevention: Since the account ID portion of WatermarkKey is automatically assigned server-side, accounts other than the build account cannot create watermarks containing that account ID. By making the full key including the account ID a condition on the Allowed AMIs side, you can restrict to only AMIs that have watermarks assigned by the approved account.
Deletion prevention: The AMI owner can delete watermarks, but doing so will cause the Allowed AMIs condition to no longer be met, preventing instance launches. By setting SCP to Deny ec2:DetachImageWatermark within the build account, deletion due to operational errors or insider threats can also be prevented.
Usable in a single account: Allowed AMIs can be configured directly in each account. Furthermore, using Declarative Policies allows bulk application to all accounts under an Organization, and it is also possible to prohibit configuration changes on the account side.
Summary
AMI Watermarks is a mechanism that automatically carries over provenance information even after AMI copies and derivations. Combined with Allowed AMIs, you can implement governance that allows instance launches only from AMIs carrying watermarks approved by the organization. Due to the design where the account ID is automatically assigned server-side, it is not possible to newly assign a watermark claiming to be from a different account ID. Since there are no additional charges, it is an easy-to-adopt feature as a foundation for AMI governance.



