# EC2 IAM Condition Keys - ec2:MetadataHttpTokens vs ec2:Attribute/HttpTokens

Today I learned about the difference between the two very similar AWS IAM condition keys for EC2: ec2:MetadataHttpTokens and ec2:Attribute/HttpTokens.

My mission was to create a service control policy (opens new window) (SCP) to prevent new EC2 instances that don't require IMDSv2 from being created, as well as to prevent anyone from modifying an existing EC2 instance to allow IMDSv1.

EC2 instances have an attribute, HttpTokens, which can either be "optional" (both IMDSv1 and IMDSv2 calls would be allowed) or "required" (only IMDSv2 calls would be allowed).

I copied the following SCP from the Get the full benefits of IMDSv2 and disable IMDSv1 across your AWS infrastructure (opens new window) article:

{
    "Version": "2012-10-17",
    "Statement": [
       {
            "Sid": "RequireImdsV2",
            "Effect": "Deny",
            "Action": "ec2:RunInstances",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringNotEquals": {
                    "ec2:MetadataHttpTokens": "required"
                }
            }
        }
    ]
} 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

The SCP uses the ec2:MetadataHttpTokens (opens new window) condition key to prevent new instances from being created where HttpTokens is not set to required. I thought I could easily modify it to also prevent existing instances from being modified to have HttpTokens to be set to optional. I simply added the ec2:ModifyInstanceMetadataOptions action to the policy:







 










{
    "Version": "2012-10-17",
    "Statement": [
       {
            "Sid": "RequireImdsV2",
            "Effect": "Deny",
            "Action": ["ec2:RunInstances", "ec2:ModifyInstanceMetadataOptions"]
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringNotEquals": {
                    "ec2:MetadataHttpTokens": "required"
                }
            }
        }
    ]
} 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

However, when I tested the above policy, it allowed me to modify instances with IMDSv2 set to required to have IMDSv2 "optional" and it denied me from modifying instances with IMDSv2 "optional" to "required"... exactly the opposite of what I wanted to achieve.

I was stumped. I thought that condition keys would apply to the new value being set.

That is, until I came upon the "Deny opt-out of IMDSv2 " (opens new window) section of the EC2 example policies documentation. I saw that the example SCP used the ec2:Attribute/HttpTokens condition key instead of ec2:MetadataHttpTokens. After looking up the ec2:Attribute/${AttributeName} (opens new window) condition key, it all started to make sense.

The ec2:Attribute/${AttributeName} key's description is: "Filters access by an attribute being set on a resource" (emphasis mine).

In other words: in the case of modifications, the ec2:Attribute/HttpTokens condition key will be compared against the new HttpTokens value that is being set (or that you're attempting to set), while the ec2:MetadataHttpTokens key will be compared to the instance's existing HttpTokens value.

This is confusing because in the case of creations, there is no existing instance and thus the ec2:MetadataHttpTokens will apply to the HttpTokens value that is being set on the new instance.

I ended up with the following SCP that combines the two SCPs from the AWS documentation mentioned above:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "RequireImdsV2",
            "Effect": "Deny",
            "Action": "ec2:RunInstances",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringNotEquals": {
                    "ec2:MetadataHttpTokens": "required"
                }
            }
        },
        {
            "Sid": "DenyImdsV2OptOut",
            "Effect": "Deny",
            "Action": "ec2:ModifyInstanceMetadataOptions",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringNotEquals": {
                    "ec2:Attribute/HttpTokens": "required"
                }
            }
        }
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

Newsletter

If you'd like to subscribe to my blog, please enter your details below. You can unsubscribe at any time.

Powered by Buttondown.

Last Updated: 11/20/2023, 10:04:51 AM