Repository: cloud-custodian/cloud-custodian

Issue:
Feature Request: Allow remediation on Instance Metadata Service Version v1, switch to v2 and disable v1
After talking with @kapilt on Gitter inquiring about the possibility of filtering and acting on Instance Metadata Service Version version 1 versus version 2 for EC2 instances, he mentioned that notification would be possible but not remediation.

Raising the issue to have Instance Metadata Service v1 disabled as part of remediation.

Reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html




Discussion:

Resolving patch:
diff --git a/c7n/resources/ec2.py b/c7n/resources/ec2.py
--- a/c7n/resources/ec2.py
+++ b/c7n/resources/ec2.py
@@ -1056,6 +1056,86 @@ def disable_monitoring(self, client, resources):
                 raise
 
 
+@EC2.action_registry.register('set-metadata-access')
+class SetMetadataServerAccess(BaseAction):
+    """Set instance metadata server access for an instance.
+
+    :example:
+
+    Require instances to use IMDSv2
+
+    .. code-block:: yaml
+
+       policies:
+         - name: ec2-require-imdsv2
+           resource: ec2
+           filters:
+             - MetadataOptions.HttpsToken: optional
+           actions:
+             - type: set-metadata-access
+               tokens: required
+
+    :example:
+
+    Disable metadata server access
+
+    .. code-block: yaml
+
+       policies:
+         - name: ec2-disable-imds
+           resource: ec2
+           filters:
+             - MetadataOptions.HttpEndpoint: enabled
+           actions:
+             - type: set-metadata-access
+               endpoint: disabled
+
+    Reference: https://amzn.to/2XOuxpQ
+    """
+
+    AllowedValues = {
+        'HttpEndpoint': ['enabled', 'disabled'],
+        'HttpTokens': ['required', 'optional'],
+        'HttpPutResponseHopLimit': list(range(1, 65))
+    }
+
+    schema = type_schema(
+        'set-metadata-access',
+        anyOf=[{'required': ['endpoint']},
+               {'required': ['tokens']},
+               {'required': ['hop-limit']}],
+        **{'endpoint': {'enum': AllowedValues['HttpEndpoint']},
+           'tokens': {'enum': AllowedValues['HttpTokens']},
+           'hop-limit': {'type': 'integer', 'minimum': 1, 'maximum': 64}}
+    )
+    permissions = ('ec2:ModifyInstanceMetadataOptions',)
+
+    def get_params(self):
+        return filter_empty({
+            'HttpEndpoint': self.data.get('endpoint'),
+            'HttpTokens': self.data.get('tokens'),
+            'HttpPutResponseHopLimit': self.data.get('hop-limit')})
+
+    def process(self, resources):
+        params = self.get_params()
+        for k, v in params.items():
+            allowed_values = list(self.AllowedValues[k])
+            allowed_values.remove(v)
+            resources = self.filter_resources(
+                resources, 'MetadataOptions.%s' % k, allowed_values)
+
+        if not resources:
+            return
+
+        client = utils.local_session(self.manager.session_factory).client('ec2')
+        for r in resources:
+            self.manager.retry(
+                client.modify_instance_metadata_options,
+                ignore_err_codes=('InvalidInstanceId.NotFound',),
+                InstanceId=r['InstanceId'],
+                **params)
+
+
 @EC2.action_registry.register("post-finding")
 class InstanceFinding(PostFinding):
 


Test patch:
diff --git a/tests/data/placebo/test_ec2_set_md_access/ec2.DescribeInstances_1.json b/tests/data/placebo/test_ec2_set_md_access/ec2.DescribeInstances_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ec2_set_md_access/ec2.DescribeInstances_1.json
@@ -0,0 +1,340 @@
+{
+    "status_code": 200,
+    "data": {
+        "Reservations": [
+            {
+                "Groups": [],
+                "Instances": [
+                    {
+                        "AmiLaunchIndex": 0,
+                        "ImageId": "ami-0323c3dd2da7fb37d",
+                        "InstanceId": "i-009cd50243eefcb38",
+                        "InstanceType": "t2.micro",
+                        "KeyName": "dozekeez",
+                        "LaunchTime": {
+                            "__class__": "datetime",
+                            "year": 2020,
+                            "month": 5,
+                            "day": 3,
+                            "hour": 17,
+                            "minute": 31,
+                            "second": 32,
+                            "microsecond": 0
+                        },
+                        "Monitoring": {
+                            "State": "disabled"
+                        },
+			"Tags": [
+                            {
+				"Key": "Dev",
+				"Value": "Test"
+                            }
+			],			
+                        "Placement": {
+                            "AvailabilityZone": "us-east-1d",
+                            "GroupName": "",
+                            "Tenancy": "default"
+                        },
+                        "PrivateDnsName": "ip-172-31-55-117.ec2.internal",
+                        "PrivateIpAddress": "172.31.55.117",
+                        "ProductCodes": [],
+                        "PublicDnsName": "ec2-52-90-87-240.compute-1.amazonaws.com",
+                        "PublicIpAddress": "52.90.87.240",
+                        "State": {
+                            "Code": 16,
+                            "Name": "running"
+                        },
+                        "StateTransitionReason": "",
+                        "SubnetId": "subnet-3a334610",
+                        "VpcId": "vpc-d2d616b5",
+                        "Architecture": "x86_64",
+                        "BlockDeviceMappings": [
+                            {
+                                "DeviceName": "/dev/xvda",
+                                "Ebs": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 3,
+                                        "hour": 17,
+                                        "minute": 31,
+                                        "second": 33,
+                                        "microsecond": 0
+                                    },
+                                    "DeleteOnTermination": true,
+                                    "Status": "attached",
+                                    "VolumeId": "vol-061da3482cc00a22a"
+                                }
+                            }
+                        ],
+                        "ClientToken": "",
+                        "EbsOptimized": false,
+                        "EnaSupport": true,
+                        "Hypervisor": "xen",
+                        "NetworkInterfaces": [
+                            {
+                                "Association": {
+                                    "IpOwnerId": "amazon",
+                                    "PublicDnsName": "ec2-52-90-87-240.compute-1.amazonaws.com",
+                                    "PublicIp": "52.90.87.240"
+                                },
+                                "Attachment": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 3,
+                                        "hour": 17,
+                                        "minute": 31,
+                                        "second": 32,
+                                        "microsecond": 0
+                                    },
+                                    "AttachmentId": "eni-attach-09bf039d93d18ebd2",
+                                    "DeleteOnTermination": true,
+                                    "DeviceIndex": 0,
+                                    "Status": "attached"
+                                },
+                                "Description": "",
+                                "Groups": [
+                                    {
+                                        "GroupName": "launch-wizard-18",
+                                        "GroupId": "sg-01778fcdc18e0a11e"
+                                    }
+                                ],
+                                "Ipv6Addresses": [],
+                                "MacAddress": "12:98:4f:b1:31:d5",
+                                "NetworkInterfaceId": "eni-018c43a385b1cea9d",
+                                "OwnerId": "644160558196",
+                                "PrivateDnsName": "ip-172-31-55-117.ec2.internal",
+                                "PrivateIpAddress": "172.31.55.117",
+                                "PrivateIpAddresses": [
+                                    {
+                                        "Association": {
+                                            "IpOwnerId": "amazon",
+                                            "PublicDnsName": "ec2-52-90-87-240.compute-1.amazonaws.com",
+                                            "PublicIp": "52.90.87.240"
+                                        },
+                                        "Primary": true,
+                                        "PrivateDnsName": "ip-172-31-55-117.ec2.internal",
+                                        "PrivateIpAddress": "172.31.55.117"
+                                    }
+                                ],
+                                "SourceDestCheck": true,
+                                "Status": "in-use",
+                                "SubnetId": "subnet-3a334610",
+                                "VpcId": "vpc-d2d616b5",
+                                "InterfaceType": "interface"
+                            }
+                        ],
+                        "RootDeviceName": "/dev/xvda",
+                        "RootDeviceType": "ebs",
+                        "SecurityGroups": [
+                            {
+                                "GroupName": "launch-wizard-18",
+                                "GroupId": "sg-01778fcdc18e0a11e"
+                            }
+                        ],
+                        "SourceDestCheck": true,
+                        "VirtualizationType": "hvm",
+                        "CpuOptions": {
+                            "CoreCount": 1,
+                            "ThreadsPerCore": 1
+                        },
+                        "CapacityReservationSpecification": {
+                            "CapacityReservationPreference": "open"
+                        },
+                        "HibernationOptions": {
+                            "Configured": false
+                        },
+                        "MetadataOptions": {
+                            "State": "pending",
+                            "HttpTokens": "optional",
+                            "HttpPutResponseHopLimit": 1,
+                            "HttpEndpoint": "enabled"
+                        }
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "ReservationId": "r-0af0b0716f7aaf616"
+            },
+            {
+                "Groups": [],
+                "Instances": [
+                    {
+                        "AmiLaunchIndex": 0,
+                        "ImageId": "ami-04bfee437f38a691e",
+                        "InstanceId": "i-04e252315a3b7940a",
+                        "InstanceType": "t1.micro",
+                        "LaunchTime": {
+                            "__class__": "datetime",
+                            "year": 2020,
+                            "month": 5,
+                            "day": 12,
+                            "hour": 15,
+                            "minute": 20,
+                            "second": 18,
+                            "microsecond": 0
+                        },
+                        "Monitoring": {
+                            "State": "disabled"
+                        },
+                        "Placement": {
+                            "AvailabilityZone": "us-east-1d",
+                            "GroupName": "",
+                            "Tenancy": "default"
+                        },
+                        "PrivateDnsName": "ip-172-31-48-115.ec2.internal",
+                        "PrivateIpAddress": "172.31.48.115",
+                        "ProductCodes": [],
+                        "PublicDnsName": "ec2-3-83-13-206.compute-1.amazonaws.com",
+                        "PublicIpAddress": "3.83.13.206",
+                        "State": {
+                            "Code": 16,
+                            "Name": "running"
+                        },
+                        "StateTransitionReason": "",
+                        "SubnetId": "subnet-3a334610",
+                        "VpcId": "vpc-d2d616b5",
+                        "Architecture": "x86_64",
+                        "BlockDeviceMappings": [
+                            {
+                                "DeviceName": "/dev/xvda",
+                                "Ebs": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 12,
+                                        "hour": 15,
+                                        "minute": 20,
+                                        "second": 19,
+                                        "microsecond": 0
+                                    },
+                                    "DeleteOnTermination": true,
+                                    "Status": "attached",
+                                    "VolumeId": "vol-0efbdeecbfe23f9fd"
+                                }
+                            }
+                        ],
+                        "ClientToken": "fleet-b8fccd75-0bff-2f71-041a-0baa5e00f3ab-0",
+                        "EbsOptimized": false,
+                        "EnaSupport": true,
+                        "Hypervisor": "xen",
+                        "NetworkInterfaces": [
+                            {
+                                "Association": {
+                                    "IpOwnerId": "amazon",
+                                    "PublicDnsName": "ec2-3-83-13-206.compute-1.amazonaws.com",
+                                    "PublicIp": "3.83.13.206"
+                                },
+                                "Attachment": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 12,
+                                        "hour": 15,
+                                        "minute": 20,
+                                        "second": 18,
+                                        "microsecond": 0
+                                    },
+                                    "AttachmentId": "eni-attach-010bca1f4114b20d9",
+                                    "DeleteOnTermination": true,
+                                    "DeviceIndex": 0,
+                                    "Status": "attached"
+                                },
+                                "Description": "",
+                                "Groups": [
+                                    {
+                                        "GroupName": "task-p-4374",
+                                        "GroupId": "sg-02ec691909b2a4753"
+                                    }
+                                ],
+                                "Ipv6Addresses": [],
+                                "MacAddress": "12:35:50:6b:cd:7b",
+                                "NetworkInterfaceId": "eni-05c6b4ae8e95d3612",
+                                "OwnerId": "644160558196",
+                                "PrivateDnsName": "ip-172-31-48-115.ec2.internal",
+                                "PrivateIpAddress": "172.31.48.115",
+                                "PrivateIpAddresses": [
+                                    {
+                                        "Association": {
+                                            "IpOwnerId": "amazon",
+                                            "PublicDnsName": "ec2-3-83-13-206.compute-1.amazonaws.com",
+                                            "PublicIp": "3.83.13.206"
+                                        },
+                                        "Primary": true,
+                                        "PrivateDnsName": "ip-172-31-48-115.ec2.internal",
+                                        "PrivateIpAddress": "172.31.48.115"
+                                    }
+                                ],
+                                "SourceDestCheck": true,
+                                "Status": "in-use",
+                                "SubnetId": "subnet-3a334610",
+                                "VpcId": "vpc-d2d616b5",
+                                "InterfaceType": "interface"
+                            }
+                        ],
+                        "RootDeviceName": "/dev/xvda",
+                        "RootDeviceType": "ebs",
+                        "SecurityGroups": [
+                            {
+                                "GroupName": "task-p-4374",
+                                "GroupId": "sg-02ec691909b2a4753"
+                            }
+                        ],
+                        "SourceDestCheck": true,
+                        "Tags": [
+                            {
+                                "Key": "Owner",
+                                "Value": "test"
+                            },
+                            {
+                                "Key": "aws:ec2launchtemplate:version",
+                                "Value": "4"
+                            },
+                            {
+                                "Key": "aws:ec2:fleet-id",
+                                "Value": "fleet-b8fccd75-0bff-2f71-041a-0baa5e00f3ab"
+                            },
+                            {
+                                "Key": "Env",
+                                "Value": "App"
+                            },
+                            {
+                                "Key": "aws:autoscaling:groupName",
+                                "Value": "devx"
+                            },
+                            {
+                                "Key": "aws:ec2launchtemplate:id",
+                                "Value": "lt-0877401c93c294001"
+                            }
+                        ],
+                        "VirtualizationType": "hvm",
+                        "CpuOptions": {
+                            "CoreCount": 1,
+                            "ThreadsPerCore": 1
+                        },
+                        "CapacityReservationSpecification": {
+                            "CapacityReservationPreference": "open"
+                        },
+                        "HibernationOptions": {
+                            "Configured": false
+                        },
+                        "MetadataOptions": {
+                            "State": "applied",
+                            "HttpTokens": "required",
+                            "HttpPutResponseHopLimit": 1,
+                            "HttpEndpoint": "enabled"
+                        }
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "RequesterId": "644160558196",
+                "ReservationId": "r-0cffe771d127eda82"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_ec2_set_md_access/ec2.DescribeInstances_2.json b/tests/data/placebo/test_ec2_set_md_access/ec2.DescribeInstances_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ec2_set_md_access/ec2.DescribeInstances_2.json
@@ -0,0 +1,334 @@
+{
+    "status_code": 200,
+    "data": {
+        "Reservations": [
+            {
+                "Groups": [],
+                "Instances": [
+                    {
+                        "AmiLaunchIndex": 0,
+                        "ImageId": "ami-0323c3dd2da7fb37d",
+                        "InstanceId": "i-009cd50243eefcb38",
+                        "InstanceType": "t2.micro",
+                        "KeyName": "dozekeez",
+                        "LaunchTime": {
+                            "__class__": "datetime",
+                            "year": 2020,
+                            "month": 5,
+                            "day": 3,
+                            "hour": 17,
+                            "minute": 31,
+                            "second": 32,
+                            "microsecond": 0
+                        },
+                        "Monitoring": {
+                            "State": "disabled"
+                        },
+                        "Placement": {
+                            "AvailabilityZone": "us-east-1d",
+                            "GroupName": "",
+                            "Tenancy": "default"
+                        },
+                        "PrivateDnsName": "ip-172-31-55-117.ec2.internal",
+                        "PrivateIpAddress": "172.31.55.117",
+                        "ProductCodes": [],
+                        "PublicDnsName": "ec2-52-90-87-240.compute-1.amazonaws.com",
+                        "PublicIpAddress": "52.90.87.240",
+                        "State": {
+                            "Code": 16,
+                            "Name": "running"
+                        },
+                        "StateTransitionReason": "",
+                        "SubnetId": "subnet-3a334610",
+                        "VpcId": "vpc-d2d616b5",
+                        "Architecture": "x86_64",
+                        "BlockDeviceMappings": [
+                            {
+                                "DeviceName": "/dev/xvda",
+                                "Ebs": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 3,
+                                        "hour": 17,
+                                        "minute": 31,
+                                        "second": 33,
+                                        "microsecond": 0
+                                    },
+                                    "DeleteOnTermination": true,
+                                    "Status": "attached",
+                                    "VolumeId": "vol-061da3482cc00a22a"
+                                }
+                            }
+                        ],
+                        "ClientToken": "",
+                        "EbsOptimized": false,
+                        "EnaSupport": true,
+                        "Hypervisor": "xen",
+                        "NetworkInterfaces": [
+                            {
+                                "Association": {
+                                    "IpOwnerId": "amazon",
+                                    "PublicDnsName": "ec2-52-90-87-240.compute-1.amazonaws.com",
+                                    "PublicIp": "52.90.87.240"
+                                },
+                                "Attachment": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 3,
+                                        "hour": 17,
+                                        "minute": 31,
+                                        "second": 32,
+                                        "microsecond": 0
+                                    },
+                                    "AttachmentId": "eni-attach-09bf039d93d18ebd2",
+                                    "DeleteOnTermination": true,
+                                    "DeviceIndex": 0,
+                                    "Status": "attached"
+                                },
+                                "Description": "",
+                                "Groups": [
+                                    {
+                                        "GroupName": "launch-wizard-18",
+                                        "GroupId": "sg-01778fcdc18e0a11e"
+                                    }
+                                ],
+                                "Ipv6Addresses": [],
+                                "MacAddress": "12:98:4f:b1:31:d5",
+                                "NetworkInterfaceId": "eni-018c43a385b1cea9d",
+                                "OwnerId": "644160558196",
+                                "PrivateDnsName": "ip-172-31-55-117.ec2.internal",
+                                "PrivateIpAddress": "172.31.55.117",
+                                "PrivateIpAddresses": [
+                                    {
+                                        "Association": {
+                                            "IpOwnerId": "amazon",
+                                            "PublicDnsName": "ec2-52-90-87-240.compute-1.amazonaws.com",
+                                            "PublicIp": "52.90.87.240"
+                                        },
+                                        "Primary": true,
+                                        "PrivateDnsName": "ip-172-31-55-117.ec2.internal",
+                                        "PrivateIpAddress": "172.31.55.117"
+                                    }
+                                ],
+                                "SourceDestCheck": true,
+                                "Status": "in-use",
+                                "SubnetId": "subnet-3a334610",
+                                "VpcId": "vpc-d2d616b5",
+                                "InterfaceType": "interface"
+                            }
+                        ],
+                        "RootDeviceName": "/dev/xvda",
+                        "RootDeviceType": "ebs",
+                        "SecurityGroups": [
+                            {
+                                "GroupName": "launch-wizard-18",
+                                "GroupId": "sg-01778fcdc18e0a11e"
+                            }
+                        ],
+                        "SourceDestCheck": true,
+                        "VirtualizationType": "hvm",
+                        "CpuOptions": {
+                            "CoreCount": 1,
+                            "ThreadsPerCore": 1
+                        },
+                        "CapacityReservationSpecification": {
+                            "CapacityReservationPreference": "open"
+                        },
+                        "HibernationOptions": {
+                            "Configured": false
+                        },
+                        "MetadataOptions": {
+                            "State": "pending",
+                            "HttpTokens": "required",
+                            "HttpPutResponseHopLimit": 1,
+                            "HttpEndpoint": "enabled"
+                        }
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "ReservationId": "r-0af0b0716f7aaf616"
+            },
+            {
+                "Groups": [],
+                "Instances": [
+                    {
+                        "AmiLaunchIndex": 0,
+                        "ImageId": "ami-04bfee437f38a691e",
+                        "InstanceId": "i-04e252315a3b7940a",
+                        "InstanceType": "t1.micro",
+                        "LaunchTime": {
+                            "__class__": "datetime",
+                            "year": 2020,
+                            "month": 5,
+                            "day": 12,
+                            "hour": 15,
+                            "minute": 20,
+                            "second": 18,
+                            "microsecond": 0
+                        },
+                        "Monitoring": {
+                            "State": "disabled"
+                        },
+                        "Placement": {
+                            "AvailabilityZone": "us-east-1d",
+                            "GroupName": "",
+                            "Tenancy": "default"
+                        },
+                        "PrivateDnsName": "ip-172-31-48-115.ec2.internal",
+                        "PrivateIpAddress": "172.31.48.115",
+                        "ProductCodes": [],
+                        "PublicDnsName": "ec2-3-83-13-206.compute-1.amazonaws.com",
+                        "PublicIpAddress": "3.83.13.206",
+                        "State": {
+                            "Code": 16,
+                            "Name": "running"
+                        },
+                        "StateTransitionReason": "",
+                        "SubnetId": "subnet-3a334610",
+                        "VpcId": "vpc-d2d616b5",
+                        "Architecture": "x86_64",
+                        "BlockDeviceMappings": [
+                            {
+                                "DeviceName": "/dev/xvda",
+                                "Ebs": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 12,
+                                        "hour": 15,
+                                        "minute": 20,
+                                        "second": 19,
+                                        "microsecond": 0
+                                    },
+                                    "DeleteOnTermination": true,
+                                    "Status": "attached",
+                                    "VolumeId": "vol-0efbdeecbfe23f9fd"
+                                }
+                            }
+                        ],
+                        "ClientToken": "fleet-b8fccd75-0bff-2f71-041a-0baa5e00f3ab-0",
+                        "EbsOptimized": false,
+                        "EnaSupport": true,
+                        "Hypervisor": "xen",
+                        "NetworkInterfaces": [
+                            {
+                                "Association": {
+                                    "IpOwnerId": "amazon",
+                                    "PublicDnsName": "ec2-3-83-13-206.compute-1.amazonaws.com",
+                                    "PublicIp": "3.83.13.206"
+                                },
+                                "Attachment": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2020,
+                                        "month": 5,
+                                        "day": 12,
+                                        "hour": 15,
+                                        "minute": 20,
+                                        "second": 18,
+                                        "microsecond": 0
+                                    },
+                                    "AttachmentId": "eni-attach-010bca1f4114b20d9",
+                                    "DeleteOnTermination": true,
+                                    "DeviceIndex": 0,
+                                    "Status": "attached"
+                                },
+                                "Description": "",
+                                "Groups": [
+                                    {
+                                        "GroupName": "task-p-4374",
+                                        "GroupId": "sg-02ec691909b2a4753"
+                                    }
+                                ],
+                                "Ipv6Addresses": [],
+                                "MacAddress": "12:35:50:6b:cd:7b",
+                                "NetworkInterfaceId": "eni-05c6b4ae8e95d3612",
+                                "OwnerId": "644160558196",
+                                "PrivateDnsName": "ip-172-31-48-115.ec2.internal",
+                                "PrivateIpAddress": "172.31.48.115",
+                                "PrivateIpAddresses": [
+                                    {
+                                        "Association": {
+                                            "IpOwnerId": "amazon",
+                                            "PublicDnsName": "ec2-3-83-13-206.compute-1.amazonaws.com",
+                                            "PublicIp": "3.83.13.206"
+                                        },
+                                        "Primary": true,
+                                        "PrivateDnsName": "ip-172-31-48-115.ec2.internal",
+                                        "PrivateIpAddress": "172.31.48.115"
+                                    }
+                                ],
+                                "SourceDestCheck": true,
+                                "Status": "in-use",
+                                "SubnetId": "subnet-3a334610",
+                                "VpcId": "vpc-d2d616b5",
+                                "InterfaceType": "interface"
+                            }
+                        ],
+                        "RootDeviceName": "/dev/xvda",
+                        "RootDeviceType": "ebs",
+                        "SecurityGroups": [
+                            {
+                                "GroupName": "task-p-4374",
+                                "GroupId": "sg-02ec691909b2a4753"
+                            }
+                        ],
+                        "SourceDestCheck": true,
+                        "Tags": [
+                            {
+                                "Key": "Owner",
+                                "Value": "test"
+                            },
+                            {
+                                "Key": "aws:ec2launchtemplate:version",
+                                "Value": "4"
+                            },
+                            {
+                                "Key": "aws:ec2:fleet-id",
+                                "Value": "fleet-b8fccd75-0bff-2f71-041a-0baa5e00f3ab"
+                            },
+                            {
+                                "Key": "Env",
+                                "Value": "App"
+                            },
+                            {
+                                "Key": "aws:autoscaling:groupName",
+                                "Value": "devx"
+                            },
+                            {
+                                "Key": "aws:ec2launchtemplate:id",
+                                "Value": "lt-0877401c93c294001"
+                            }
+                        ],
+                        "VirtualizationType": "hvm",
+                        "CpuOptions": {
+                            "CoreCount": 1,
+                            "ThreadsPerCore": 1
+                        },
+                        "CapacityReservationSpecification": {
+                            "CapacityReservationPreference": "open"
+                        },
+                        "HibernationOptions": {
+                            "Configured": false
+                        },
+                        "MetadataOptions": {
+                            "State": "applied",
+                            "HttpTokens": "required",
+                            "HttpPutResponseHopLimit": 1,
+                            "HttpEndpoint": "enabled"
+                        }
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "RequesterId": "644160558196",
+                "ReservationId": "r-0cffe771d127eda82"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ec2_set_md_access/ec2.ModifyInstanceMetadataOptions_1.json b/tests/data/placebo/test_ec2_set_md_access/ec2.ModifyInstanceMetadataOptions_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ec2_set_md_access/ec2.ModifyInstanceMetadataOptions_1.json
@@ -0,0 +1,13 @@
+{
+    "status_code": 200,
+    "data": {
+        "InstanceId": "i-009cd50243eefcb38",
+        "InstanceMetadataOptions": {
+            "State": "pending",
+            "HttpTokens": "required",
+            "HttpPutResponseHopLimit": 1,
+            "HttpEndpoint": "enabled"
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/test_ec2.py b/tests/test_ec2.py
--- a/tests/test_ec2.py
+++ b/tests/test_ec2.py
@@ -108,6 +108,43 @@ def test_attr_filter(self):
         )
 
 
+class TestSetMetadata(BaseTest):
+
+    def test_set_metadata_server(self):
+        output = self.capture_logging('custodian.actions')
+        session_factory = self.replay_flight_data('test_ec2_set_md_access')
+        policy = self.load_policy({
+            'name': 'ec2-imds-access',
+            'resource': 'aws.ec2',
+            'actions': [
+                {'type': 'set-metadata-access',
+                 'tokens': 'required'},
+            ]},
+            session_factory=session_factory)
+        resources = policy.run()
+        if self.recording:
+            time.sleep(2)
+        results = session_factory().client('ec2').describe_instances(
+            InstanceIds=[r['InstanceId'] for r in resources])
+        self.assertJmes('[0].MetadataOptions.HttpTokens', resources, 'optional')
+        self.assertJmes(
+            'Reservations[].Instances[].MetadataOptions',
+            results,
+            [{'HttpEndpoint': 'enabled',
+              'HttpPutResponseHopLimit': 1,
+              'HttpTokens': 'required',
+              'State': 'pending'},
+             {'HttpEndpoint': 'enabled',
+              'HttpPutResponseHopLimit': 1,
+              'HttpTokens': 'required',
+              'State': 'applied'}])
+        self.assertEqual(len(resources), 2)
+        self.assertEqual(
+            output.getvalue(),
+            ('set-metadata-access implicitly filtered 1 of 2 resources '
+             'key:MetadataOptions.HttpTokens on optional\n'))
+
+
 class TestMetricFilter(BaseTest):
 
     def test_metric_filter(self):