

# Access instance metadata for an EC2 instance
<a name="instancedata-data-retrieval"></a>

You can access EC2 instance metadata from inside of the instance itself or from the EC2 console, API, SDKs, or the AWS CLI. To get the current instance metadata settings for an instance from the console or command line, see [Query instance metadata options for existing instances](#query-IMDS-existing-instances).

You can also modify user data for instances with an EBS root volume. The instance must be in the stopped state. For console directions, see [Update the instance user data](user-data.md#user-data-modify). For a Linux example that uses the AWS CLI, see [modify-instance-attribute](https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-instance-attribute.html). For a Windows example that uses the Tools for Windows PowerShell, see [User data and the Tools for Windows PowerShell](user-data.md#user-data-powershell).

**Note**  
You are not billed for HTTP requests used to retrieve instance metadata and user data.

## Instance metadata access considerations
<a name="imds-considerations"></a>

To avoid problems with instance metadata, consider the following.

**Instance launch failures due to IMDSv2 enforcement (`HttpTokensEnforced=enabled`)**  
Before enabling IMDSv2 enforcement, you need all your software on the instance to support IMDSv2, after which you can change the default to disable IMDSv1 (`httpTokens=required`), after which you can enable enforcement. For more information, [Transition to using Instance Metadata Service Version 2](instance-metadata-transition-to-version-2.md).

**Command format**  
The command format is different, depending on whether you use Instance Metadata Service Version 1 (IMDSv1) or Instance Metadata Service Version 2 (IMDSv2). By default, you can use both versions of the Instance Metadata Service. To require the use of IMDSv2, see [Use the Instance Metadata Service to access instance metadata](configuring-instance-metadata-service.md).

**If IMDSv2 is required, IMDSv1 does not work**  
If you use IMDSv1 and receive no response, it's likely that IMDSv2 is required. To check whether IMDSv2 is required, select the instance to view its details. The **IMDSv2** value indicates either **Required** (you must use IMDSv2) or **Optional** (you can use either IMDSv2 or IMDSv1). 

**(IMDSv2) Use /latest/api/token to retrieve the token**  
Issuing `PUT` requests to any version-specific path, for example `/2021-03-23/api/token`, results in the metadata service returning 403 Forbidden errors. This behavior is intended.

**Metadata version**  
To avoid having to update your code every time Amazon EC2 releases a new instance metadata build, we recommend that you use `latest` in the path, and not the version number.

**IPv6 support**  
To retrieve instance metadata using an IPv6 address, ensure that you enable and use the IPv6 address of the IMDS `[fd00:ec2::254]` instead of the IPv4 address `169.254.169.254`. The instance must be a [Nitro-based instance](instance-types.md#instance-hypervisor-type) launched in a [subnet that supports IPv6](https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html#subnet-ip-address-range).

**(Windows) Create custom AMIs using Windows Sysprep**  
To ensure that IMDS works when you launch an instance from a custom Windows AMI, the AMI must be a standardized image created with Windows Sysprep. Otherwise, the IMDS won't work. For more information, see [Create an Amazon EC2 AMI using Windows Sysprep](ami-create-win-sysprep.md).

**In a container environment, consider reconfiguration or increasing the hop limit to 2**  
The AWS SDKs use IMDSv2 calls by default. If the IMDSv2 call receives no response, some AWS SDKs retry the call and, if still unsuccessful, use IMDSv1. This can result in a delay, especially in a container environment. For those AWS SDKs that *require* IMDSv2, if the hop limit is 1 in a container environment, the call might not receive a response at all because going to the container is considered an additional network hop.  
To mitigate these issues in a container environment, consider changing the configuration to pass settings (such as the AWS Region) directly to the container, or consider increasing the hop limit to 2. For information about the hop limit impact, see [Add defense in depth against open firewalls, reverse proxies, and SSRF vulnerabilities with enhancements to the EC2 Instance Metadata Service](https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/). For information about changing the hop limit, see [Change the PUT response hop limit](configuring-IMDS-existing-instances.md#modify-PUT-response-hop-limit).

**Packets per second (PPS) limit**  
There is a 1024 packet per second (PPS) limit to services that use [link-local](using-instance-addressing.md#link-local-addresses) addresses. This limit includes the aggregate of [Route 53 Resolver DNS Queries](https://docs.aws.amazon.com/vpc/latest/userguide/AmazonDNS-concepts.html#vpc-dns-limits), Instance Metadata Service (IMDS) requests, [Amazon Time Service Network Time Protocol (NTP)](set-time.md) requests, and [Windows Licensing Service (for Microsoft Windows based instances)](https://aws.amazon.com/windows/resources/licensing/) requests. 

**Additional considerations for user data access**
+ User data is treated as opaque data: what you specify is what you get back upon retrieval. It is up to the instance to interpret and act on user data.
+ User data must be base64-encoded. Depending on the tool or SDK that you're using, the base64-encoding might be performed for you. For example:
  + The Amazon EC2 console can perform the base64-encoding for you or accept base64-encoded input.
  + [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration-changes.html#cliv2-migration-binaryparam) performs base64-encoding of binary parameters for you by default. AWS CLI version 1 performs the base64-encoding of the `--user-data` parameter for you.
  + The AWS SDK for Python (Boto3) performs base64-encoding of the `UserData` parameter for you.
+ User data is limited to 16 KB, in raw form, before it is base64-encoded. The size of a string of length *n* after base64-encoding is ceil(*n*/3)\$14.
+ User data must be base64-decoded when you retrieve it. If you retrieve the data using instance metadata or the console, it's decoded for you automatically.
+ If you stop an instance, modify its user data, and start the instance, the updated user data is not run automatically when you start the instance. With Windows instances, you can configure settings so that updated user data scripts are run one time when you start the instance or every time you reboot or start the instance.
+ User data is an instance attribute. If you create an AMI from an instance, the instance user data is not included in the AMI.

## Access instance metadata from within an EC2 instance
<a name="instancedata-inside-access"></a>

Because your instance metadata is available from your running instance, you do not need to use the Amazon EC2 console or the AWS CLI. This can be helpful when you're writing scripts to run from your instance. For example, you can access the local IP address of your instance from instance metadata to manage a connection to an external application.

All of the following are considered instance metadata, but they are accessed in different ways. Select the tab that represents the type of instance metadata you want to access to see more information.

------
#### [ Metadata ]

Instance metadata properties are divided into categories. For a description of each instance metadata category, see [Instance metadata categories](ec2-instance-metadata.md#instancedata-data-categories).

To access instance metadata properties from within a running instance, get the data from the following IPv4 or IPv6 URIs. These IP addresses are link-local addresses and are valid only from the instance. For more information, see [Link-local addresses](using-instance-addressing.md#link-local-addresses).

**IPv4**

```
http://169.254.169.254/latest/meta-data/
```

**IPv6**

```
http://[fd00:ec2::254]/latest/meta-data/
```

------
#### [ Dynamic data ]

To retrieve dynamic data from within a running instance, use one of the following URIs.

**IPv4**

```
http://169.254.169.254/latest/dynamic/
```

**IPv6**

```
http://[fd00:ec2::254]/latest/dynamic/
```

**Examples: Access with cURL**  
The following examples use `cURL` to retrieve the high-level instance identity categories.

*IMDSv2*

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/dynamic/instance-identity/
rsa2048
pkcs7
document
signature
dsa2048
```

*IMDSv1*

```
[ec2-user ~]$ curl http://169.254.169.254/latest/dynamic/instance-identity/
rsa2048
pkcs7
document
signature
dsa2048
```

**Examples: Access with PowerShell**  
The following examples use PowerShell to retrieve the high-level instance identity categories.

*IMDSv2*

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/dynamic/instance-identity/
document
rsa2048
pkcs7
signature
```

*IMDSv1*

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/dynamic/instance-identity/
document
rsa2048
pkcs7
signature
```

For more information about dynamic data and examples of how to retrieve it, see [Instance identity documents for Amazon EC2 instances](instance-identity-documents.md).

------
#### [ User data ]

To retrieve user data from an instance, use one of the following URIs. To retrieve user data using the IPv6 address, you must enable it, and the instance must be a [Nitro-based instance](instance-types.md#instance-hypervisor-type) in a subnet that supports IPv6.

**IPv4**

```
http://169.254.169.254/latest/user-data
```

**IPv6**

```
http://[fd00:ec2::254]/latest/user-data
```

A request for user data returns the data as it is (content type `application/octet-stream`). If the instance does not have any user data, the request returns `404 - Not Found`.

**Examples: Access with cURL to retrieve comma-separated text**  
The following examples use `cURL` to retrieve user data that was specified as comma-separated text.

*IMDSv2*

```
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/user-data
1234,john,reboot,true | 4512,richard, | 173,,,
```

*IMDSv1*

```
curl http://169.254.169.254/latest/user-data
1234,john,reboot,true | 4512,richard, | 173,,,
```

**Examples: Access with PowerShell to retrieve comma-separated text**  
The following examples use PowerShell to retrieve user data that was specified as comma-separated text.

*IMDSv2*

```
[string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/user-data
1234,john,reboot,true | 4512,richard, | 173,,,
```

*IMDSv1*

```
Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} `
-Method PUT -Uri http://169.254.169.254/latest/api/token} -Method GET -uri http://169.254.169.254/latest/user-data
1234,john,reboot,true | 4512,richard, | 173,,,
```

**Examples: Access with cURL to retrieve a script**  
The following examples use `cURL` to retrieve user data that was specified as a script.

*IMDSv2*

```
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/user-data
#!/bin/bash
yum update -y
service httpd start
chkconfig httpd on
```

*IMDSv1*

```
curl http://169.254.169.254/latest/user-data
#!/bin/bash
yum update -y
service httpd start
chkconfig httpd on
```

**Examples: Access with PowerShell to retrieve a script**  
The following examples use PowerShell to retrieve user data that was specified as a script.

*IMDSv2*

```
[string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/user-data
<powershell>
$file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm")
New-Item $file -ItemType file
</powershell>
<persist>true</persist>
```

*IMDSv1*

```
Invoke-RestMethod -uri http://169.254.169.254/latest/user-data
<powershell>
$file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm")
New-Item $file -ItemType file
</powershell>
<persist>true</persist>
```

------

## Query instance metadata options for existing instances
<a name="query-IMDS-existing-instances"></a>

You can query the instance metadata options for your existing instances.

------
#### [ Console ]

**To query the instance metadata options for an existing instance**

1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/).

1. In the navigation pane, choose **Instances**.

1. Select your instance and check the following fields:
   + **IMDSv2** – The value is either **Required** or **Optional**.
   + **Allow tags in instance metadata** – The value is either **Enabled** or **Disabled**.

1. With your instance selected, choose **Actions**, **Instance settings**, **Modify instance metadata options**.

   The dialog box displays whether the instance metadata service is enabled or disabled for the selected instance.

------
#### [ AWS CLI ]

**To query the instance metadata options for an existing instance**  
Use the [describe-instances](https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html) command.

```
aws ec2 describe-instances \
    --instance-id i-1234567898abcdef0 \
    --query 'Reservations[].Instances[].MetadataOptions'
```

------
#### [ PowerShell ]

**To query the instance metadata options for an existing instance using the Tools for PowerShell**  
Use the [Get-EC2Instance](https://docs.aws.amazon.com/powershell/latest/reference/items/Get-EC2Instance.html) cmdlet.

```
(Get-EC2Instance `
    -InstanceId i-1234567898abcdef0).Instances.MetadataOptions
```

------

## Responses and error messages
<a name="instance-metadata-returns"></a>

All instance metadata is returned as text (HTTP content type `text/plain`).

A request for a specific metadata resource returns the appropriate value, or a `404 - Not Found` HTTP error code if the resource is not available.

A request for a general metadata resource (the URI ends with a /) returns a list of available resources, or a `404 - Not Found` HTTP error code if there is no such resource. The list items are on separate lines, terminated by line feeds (ASCII 10).

If an IMDSv1 request receives no response, it's likely that IMDSv2 is required.

For requests made using IMDSv2, the following HTTP error codes can be returned:
+ `400 - Missing or Invalid Parameters` – The `PUT` request is not valid.
+ `401 - Unauthorized` – The `GET` request uses an invalid token. The recommended action is to generate a new token.
+ `403 - Forbidden` – The request is not allowed or the IMDS is turned off.
+ `404 - Not Found` – The resource is not available or there is no such resource.
+ `503` – The request could not be completed. Retry the request.

If the IMDS returns an error, **curl** prints the error message in the output and returns a success status code. The error message is stored in the `TOKEN` variable, which causes **curl** commands that use the token to fail. If you call **curl** with the **-f** option, it returns an error status code in the event of an HTTP server error. If you enable error handling, the shell can catch the error and stop the script.

## Query throttling
<a name="instancedata-throttling"></a>

We throttle queries to the IMDS on a per-instance basis, and we place limits on the number of simultaneous connections from an instance to the IMDS. 

If you're using the IMDS to retrieve AWS security credentials, avoid querying for credentials during every transaction or concurrently from a high number of threads or processes, as this might lead to throttling. Instead, we recommend that you cache the credentials until they start approaching their expiry time. For more information about IAM role and security credentials associated with the role, see [Retrieve security credentials from instance metadata](instance-metadata-security-credentials.md).

If you are throttled while accessing the IMDS, retry your query with an exponential backoff strategy.

# Use the Instance Metadata Service to access instance metadata
<a name="configuring-instance-metadata-service"></a>

You can access instance metadata from a running instance using one of the following methods:
+ Instance Metadata Service Version 2 (IMDSv2) – a session-oriented method

  For examples, see [Examples for IMDSv2](#instance-metadata-retrieval-examples).
+ Instance Metadata Service Version 1 (IMDSv1) – a request/response method

  For examples, see [Examples for IMDSv1](#instance-metadata-retrieval-examples-imdsv1).

By default, you can use either IMDSv1 or IMDSv2, or both.

You can configure the Instance Metadata Service (IMDS) on each instance to only accept IMDSv2 calls, which will cause IMDSv1 calls to fail. For information about how to configure your instance to use IMDSv2, see [Configure the Instance Metadata Service options](configuring-instance-metadata-options.md).

The `PUT` or `GET` headers are unique to IMDSv2. If these headers are present in the request, then the request is intended for IMDSv2. If no headers are present, it is assumed the request is intended for IMDSv1.

For an extensive review of IMDSv2, see [Add defense in depth against open firewalls, reverse proxies, and SSRF vulnerabilities with enhancements to the EC2 Instance Metadata Service](https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/).

**Topics**
+ [

## How Instance Metadata Service Version 2 works
](#instance-metadata-v2-how-it-works)
+ [

## Use a supported AWS SDK
](#use-a-supported-sdk-version-for-imdsv2)
+ [

## Examples for IMDSv2
](#instance-metadata-retrieval-examples)
+ [

## Examples for IMDSv1
](#instance-metadata-retrieval-examples-imdsv1)

## How Instance Metadata Service Version 2 works
<a name="instance-metadata-v2-how-it-works"></a>

IMDSv2 uses session-oriented requests. With session-oriented requests, you create a session token that defines the session duration, which can be a minimum of one second and a maximum of six hours. During the specified duration, you can use the same session token for subsequent requests. After the specified duration expires, you must create a new session token to use for future requests.

**Note**  
The examples in this section use the IPv4 address of the Instance Metadata Service (IMDS): `169.254.169.254`. If you are retrieving instance metadata for EC2 instances over the IPv6 address, ensure that you enable and use the IPv6 address instead: `[fd00:ec2::254]`. The IPv6 address of the IMDS is compatible with IMDSv2 commands. The IPv6 address is only accessible on [Nitro-based instances](instance-types.md#instance-hypervisor-type) in an [IPv6-supported subnet](https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html#subnet-ip-address-range) (dual stack or IPv6 only).

The following examples use a shell script and IMDSv2 to retrieve the top-level instance metadata items. Each example:
+ Creates a session token lasting six hours (21,600 seconds) using the `PUT` request
+ Stores the session token header in a variable named `TOKEN` (Linux instances) or `token` (Windows instances)
+ Requests the top-level metadata items using the token

### Linux example
<a name="how-imdsv2-works-example-linux"></a>

You can run two separate commands, or combine them.

**Separate commands**

First, generate a token using the following command.

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
```

Then, use the token to generate top-level metadata items using the following command.

```
[ec2-user ~]$ curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/
```

**Combined commands**

You can store the token and combine the commands. The following example combines the above two commands and stores the session token header in a variable named TOKEN.

**Note**  
If there is an error in creating the token, instead of a valid token, an error message is stored in the variable, and the command will not work.

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
	&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/
```

After you've created a token, you can reuse it until it expires. In the following example command, which gets the ID of the AMI used to launch the instance, the token that is stored in `$TOKEN` in the previous example is reused.

```
[ec2-user ~]$ curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/ami-id
```

### Windows example
<a name="how-imdsv2-works-example-windows"></a>

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/
```

After you've created a token, you can reuse it until it expires. In the following example command, which gets the ID of the AMI used to launch the instance, the token that is stored in `$token` in the previous example is reused.

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} `
	-Method GET -uri http://169.254.169.254/latest/meta-data/ami-id
```

When you use IMDSv2 to request instance metadata, the request must include the following:

1. Use a `PUT` request to initiate a session to the instance metadata service. The `PUT` request returns a token that must be included in subsequent `GET` requests to the instance metadata service. The token is required to access metadata using IMDSv2.

1. Include the token in all `GET` requests to the IMDS. When token usage is set to `required`, requests without a valid token or with an expired token receive a `401 - Unauthorized` HTTP error code.
   + The token is an instance-specific key. The token is not valid on other EC2 instances and will be rejected if you attempt to use it outside of the instance on which it was generated.
   + The `PUT` request must include a header that specifies the time to live (TTL) for the token, in seconds, up to a maximum of six hours (21,600 seconds). The token represents a logical session. The TTL specifies the length of time that the token is valid and, therefore, the duration of the session.
   + After a token expires, to continue accessing instance metadata, you must create a new session using another `PUT`.
   + You can choose to reuse a token or create a new token with every request. For a small number of requests, it might be easier to generate and immediately use a token each time you need to access the IMDS. But for efficiency, you can specify a longer duration for the token and reuse it rather than having to write a `PUT` request every time you need to request instance metadata. There is no practical limit on the number of concurrent tokens, each representing its own session. IMDSv2 is, however, still constrained by normal IMDS connection and throttling limits. For more information, see [Query throttling](instancedata-data-retrieval.md#instancedata-throttling).

HTTP `GET` and `HEAD` methods are allowed in IMDSv2 instance metadata requests. `PUT` requests are rejected if they contain an X-Forwarded-For header.

By default, the response to `PUT` requests has a response hop limit (time to live) of `1` at the IP protocol level. If you need a bigger hop limit, you can adjust it by using the [modify-instance-metadata-options](https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-instance-metadata-options.html) AWS CLI command. For example, you might need a bigger hop limit for backward compatibility with container services running on the instance. For more information, see [Modify instance metadata options for existing instances](configuring-IMDS-existing-instances.md).

## Use a supported AWS SDK
<a name="use-a-supported-sdk-version-for-imdsv2"></a>

To use IMDSv2, your EC2 instances must use an AWS SDK version that supports using IMDSv2. The latest versions of all the AWS SDKs support using IMDSv2.

**Important**  
We recommend that you to stay up to date with SDK releases to keep up with the latest features, security updates, and underlying dependencies. Continued use of an unsupported SDK version is not recommended and is done at your discretion. For more information, see the [AWS SDKs and Tools maintenance policy](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html) in the *AWS SDKs and Tools Reference Guide*.

The following are the minimum versions that support using IMDSv2:
+ [AWS CLI](https://github.com/aws/aws-cli) – 1.16.289
+ [AWS Tools for Windows PowerShell](https://github.com/aws/aws-tools-for-powershell) – 4.0.1.0
+ [AWS SDK for .NET](https://github.com/aws/aws-sdk-net) – 3.3.634.1
+ [AWS SDK for C\$1\$1](https://github.com/aws/aws-sdk-cpp) – 1.7.229
+ [AWS SDK for Go](https://github.com/aws/aws-sdk-go) – 1.25.38
+ [AWS SDK for Go v2](https://github.com/aws/aws-sdk-go-v2) – 0.19.0
+ [AWS SDK for Java](https://github.com/aws/aws-sdk-java) – 1.11.678
+ [AWS SDK for Java 2.x](https://github.com/aws/aws-sdk-java-v2) – 2.10.21
+ [AWS SDK for JavaScript in Node.js](https://github.com/aws/aws-sdk-js) – 2.722.0
+ [AWS SDK for Kotlin](https://github.com/awslabs/aws-sdk-kotlin) – 1.1.4
+ [AWS SDK for PHP](https://github.com/aws/aws-sdk-php) – 3.147.7
+ [AWS SDK for Python (Botocore)](https://github.com/boto/botocore) – 1.13.25
+ [AWS SDK for Python (Boto3)](https://github.com/boto/boto3) – 1.12.6
+ [AWS SDK for Ruby](https://github.com/aws/aws-sdk-ruby) – 3.79.0

## Examples for IMDSv2
<a name="instance-metadata-retrieval-examples"></a>

Run the following examples on your Amazon EC2 instance to retrieve the instance metadata for IMDSv2.

On Windows instances, you can use Windows PowerShell or you can install cURL or wget. If you install a third-party tool on a Windows instance, ensure that you read the accompanying documentation carefully, as the calls and the output might be different from what is described here.

**Topics**
+ [

### Get the available versions of the instance metadata
](#instance-metadata-ex-1)
+ [

### Get the top-level metadata items
](#instance-metadata-ex-2)
+ [

### Get the values for metadata items
](#instance-metadata-ex-2a)
+ [

### Get the list of available public keys
](#instance-metadata-ex-3)
+ [

### Show the formats in which public key 0 is available
](#instance-metadata-ex-4)
+ [

### Get public key 0 (in the OpenSSH key format)
](#instance-metadata-ex-5)
+ [

### Get the subnet ID for an instance
](#instance-metadata-ex-6)
+ [

### Get the instance tags for an instance
](#instance-metadata-ex-7)

### Get the available versions of the instance metadata
<a name="instance-metadata-ex-1"></a>

This example gets the available versions of the instance metadata. Each version refers to an instance metadata build when new instance metadata categories were released. The instance metadata build versions do not correlate with the Amazon EC2 API versions. The earlier versions are available to you in case you have scripts that rely on the structure and information present in a previous version.

------
#### [ cURL ]

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/
1.0
2007-01-19
2007-03-01
2007-08-29
2007-10-10
2007-12-15
2008-02-01
2008-09-01
2009-04-04
2011-01-01
2011-05-01
2012-01-12
2014-02-25
2014-11-05
2015-10-20
2016-04-19
...
latest
```

------
#### [ PowerShell ]

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/
1.0
2007-01-19
2007-03-01
2007-08-29
2007-10-10
2007-12-15
2008-02-01
2008-09-01
2009-04-04
2011-01-01
2011-05-01
2012-01-12
2014-02-25
2014-11-05
2015-10-20
2016-04-19
...
latest
```

------

### Get the top-level metadata items
<a name="instance-metadata-ex-2"></a>

This example gets the top-level metadata items. For more information about the items in the response, see [Instance metadata categories](ec2-instance-metadata.md#instancedata-data-categories).

Note that tags are included in this output only if you've allowed access. For more information, see [Enable access to tags in instance metadata](work-with-tags-in-IMDS.md#allow-access-to-tags-in-IMDS).

------
#### [ cURL ]

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/    
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
tags/
```

------
#### [ PowerShell ]

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
hostname
iam/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
tags/
```

------

### Get the values for metadata items
<a name="instance-metadata-ex-2a"></a>

These examples get the values of some of the top-level metadata items that were obtained in the preceding example. These requests use the stored token that was created using the command in the previous example. The token must not be expired.

------
#### [ cURL ]

```
[ec2-user ~]$ curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/ami-id
ami-0abcdef1234567890
```

```
[ec2-user ~]$ curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/reservation-id
r-0efghijk987654321
```

```
[ec2-user ~]$ curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-hostname
ip-10-251-50-12.ec2.internal
```

```
[ec2-user ~]$ curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname
ec2-203-0-113-25.compute-1.amazonaws.com
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/ami-id
ami-0abcdef1234567890
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/reservation-id
r-0efghijk987654321
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/local-hostname
ip-10-251-50-12.ec2.internal
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/public-hostname
ec2-203-0-113-25.compute-1.amazonaws.com
```

------

### Get the list of available public keys
<a name="instance-metadata-ex-3"></a>

This example gets the list of available public keys.

------
#### [ cURL ]

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-keys/
0=my-public-key
```

------
#### [ PowerShell ]

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/public-keys/
0=my-public-key
```

------

### Show the formats in which public key 0 is available
<a name="instance-metadata-ex-4"></a>

This example shows the formats in which public key 0 is available.

------
#### [ cURL ]

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-keys/0/
openssh-key
```

------
#### [ PowerShell ]

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
openssh-key
```

------

### Get public key 0 (in the OpenSSH key format)
<a name="instance-metadata-ex-5"></a>

This example gets public key 0 (in the OpenSSH key format).

------
#### [ cURL ]

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
ssh-rsa MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w0BAQUFADCBiDELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6
b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAd
BgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wHhcNMTEwNDI1MjA0NTIxWhcN
MTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYD
VQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25z
b2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFt
YXpvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ
21uUSfwfEvySWtC2XADZ4nB+BLYgVIk60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9T
rDHudUZg3qX4waLG5M43q7Wgc/MbQITxOUSQv7c7ugFFDzQGBzZswY6786m86gpE
Ibb3OhjZnzcvQAaRHhdlQWIMm2nrAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4
nUhVVxYUntneD9+h8Mg9q6q+auNKyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0Fkb
FFBjvSfpJIlJ00zbhNYS5f6GuoEDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTb
NYiytVbZPQUQ5Yaxu2jXnimvw3rrszlaEXAMPLE my-public-key
```

------
#### [ PowerShell ]

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
ssh-rsa MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w0BAQUFADCBiDELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6
b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAd
BgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wHhcNMTEwNDI1MjA0NTIxWhcN
MTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYD
VQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25z
b2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFt
YXpvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ
21uUSfwfEvySWtC2XADZ4nB+BLYgVIk60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9T
rDHudUZg3qX4waLG5M43q7Wgc/MbQITxOUSQv7c7ugFFDzQGBzZswY6786m86gpE
Ibb3OhjZnzcvQAaRHhdlQWIMm2nrAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4
nUhVVxYUntneD9+h8Mg9q6q+auNKyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0Fkb
FFBjvSfpJIlJ00zbhNYS5f6GuoEDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTb
NYiytVbZPQUQ5Yaxu2jXnimvw3rrszlaEXAMPLE my-public-key
```

------

### Get the subnet ID for an instance
<a name="instance-metadata-ex-6"></a>

This example gets the subnet ID for an instance.

------
#### [ cURL ]

```
[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/network/interfaces/macs/02:29:96:8f:6a:2d/subnet-id
subnet-be9b61d7
```

------
#### [ PowerShell ]

```
PS C:\> [string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
```

```
PS C:\> Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/network/interfaces/macs/02:29:96:8f:6a:2d/subnet-id
subnet-be9b61d7
```

------

### Get the instance tags for an instance
<a name="instance-metadata-ex-7"></a>

If access to instance tags in the instance metadata is turned on, you can get the tags for a instance from instance metadata. For more information, see [Retrieve tags from instance metadata](work-with-tags-in-IMDS.md#retrieve-tags-from-IMDS).

## Examples for IMDSv1
<a name="instance-metadata-retrieval-examples-imdsv1"></a>

Run the following examples on your Amazon EC2 instance to retrieve the instance metadata for IMDSv1.

On Windows instances, you can use Windows PowerShell or you can install cURL or wget. If you install a third-party tool on a Windows instance, ensure that you read the accompanying documentation carefully, as the calls and the output might be different from what is described here.

**Topics**
+ [

### Get the available versions of the instance metadata
](#instance-metadata-ex-1-imdsv1)
+ [

### Get the top-level metadata items
](#instance-metadata-ex-2-imdsv1)
+ [

### Get the values for metadata items
](#instance-metadata-ex-2a-imdsv1)
+ [

### Get the list of available public keys
](#instance-metadata-ex-3-imdsv1)
+ [

### Show the formats in which public key 0 is available
](#instance-metadata-ex-4-imdsv1)
+ [

### Get public key 0 (in the OpenSSH key format)
](#instance-metadata-ex-5-imdsv1)
+ [

### Get the subnet ID for an instance
](#instance-metadata-ex-6-imdsv1)
+ [

### Get the instance tags for an instance
](#instance-metadata-ex-7-imdsv1)

### Get the available versions of the instance metadata
<a name="instance-metadata-ex-1-imdsv1"></a>

This example gets the available versions of the instance metadata. Each version refers to an instance metadata build when new instance metadata categories were released. The instance metadata build versions do not correlate with the Amazon EC2 API versions. The earlier versions are available to you in case you have scripts that rely on the structure and information present in a previous version.

------
#### [ cURL ]

```
[ec2-user ~]$ curl http://169.254.169.254/
1.0
2007-01-19
2007-03-01
2007-08-29
2007-10-10
2007-12-15
2008-02-01
2008-09-01
2009-04-04
2011-01-01
2011-05-01
2012-01-12
2014-02-25
2014-11-05
2015-10-20
2016-04-19
...
latest
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/
1.0
2007-01-19
2007-03-01
2007-08-29
2007-10-10
2007-12-15
2008-02-01
2008-09-01
2009-04-04
2011-01-01
2011-05-01
2012-01-12
2014-02-25
2014-11-05
2015-10-20
2016-04-19
...
latest
```

------

### Get the top-level metadata items
<a name="instance-metadata-ex-2-imdsv1"></a>

This example gets the top-level metadata items. For more information about the items in the response, see [Instance metadata categories](ec2-instance-metadata.md#instancedata-data-categories).

Note that tags are included in this output only if you've allowed access. For more information, see [Enable access to tags in instance metadata](work-with-tags-in-IMDS.md#allow-access-to-tags-in-IMDS).

------
#### [ cURL ]

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/    
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
instance-action
instance-id
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
tags/
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/    
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
hostname
iam/
instance-action
instance-id
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
tags/
```

------

### Get the values for metadata items
<a name="instance-metadata-ex-2a-imdsv1"></a>

These examples get the values of some of the top-level metadata items that were obtained in the previous example.

------
#### [ cURL ]

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/ami-id
ami-0abcdef1234567890
```

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/reservation-id
r-0efghijk987654321
```

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/local-hostname
ip-10-251-50-12.ec2.internal
```

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/public-hostname
ec2-203-0-113-25.compute-1.amazonaws.com
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/ami-id
ami-0abcdef1234567890
```

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/reservation-id
r-0efghijk987654321
```

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/local-hostname
ip-10-251-50-12.ec2.internal
```

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/public-hostname
ec2-203-0-113-25.compute-1.amazonaws.com
```

------

### Get the list of available public keys
<a name="instance-metadata-ex-3-imdsv1"></a>

This example gets the list of available public keys.

------
#### [ cURL ]

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/public-keys/
0=my-public-key
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/public-keys/ 0=my-public-key
```

------

### Show the formats in which public key 0 is available
<a name="instance-metadata-ex-4-imdsv1"></a>

This example shows the formats in which public key 0 is available.

------
#### [ cURL ]

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/public-keys/0/
openssh-key
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
openssh-key
```

------

### Get public key 0 (in the OpenSSH key format)
<a name="instance-metadata-ex-5-imdsv1"></a>

This example gets public key 0 (in the OpenSSH key format).

------
#### [ cURL ]

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
ssh-rsa MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w0BAQUFADCBiDELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6
b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAd
BgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wHhcNMTEwNDI1MjA0NTIxWhcN
MTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYD
VQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25z
b2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFt
YXpvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ
21uUSfwfEvySWtC2XADZ4nB+BLYgVIk60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9T
rDHudUZg3qX4waLG5M43q7Wgc/MbQITxOUSQv7c7ugFFDzQGBzZswY6786m86gpE
Ibb3OhjZnzcvQAaRHhdlQWIMm2nrAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4
nUhVVxYUntneD9+h8Mg9q6q+auNKyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0Fkb
FFBjvSfpJIlJ00zbhNYS5f6GuoEDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTb
NYiytVbZPQUQ5Yaxu2jXnimvw3rrszlaEXAMPLE my-public-key
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
ssh-rsa MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w0BAQUFADCBiDELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6
b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAd
BgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wHhcNMTEwNDI1MjA0NTIxWhcN
MTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYD
VQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25z
b2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFt
YXpvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ
21uUSfwfEvySWtC2XADZ4nB+BLYgVIk60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9T
rDHudUZg3qX4waLG5M43q7Wgc/MbQITxOUSQv7c7ugFFDzQGBzZswY6786m86gpE
Ibb3OhjZnzcvQAaRHhdlQWIMm2nrAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4
nUhVVxYUntneD9+h8Mg9q6q+auNKyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0Fkb
FFBjvSfpJIlJ00zbhNYS5f6GuoEDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTb
NYiytVbZPQUQ5Yaxu2jXnimvw3rrszlaEXAMPLE my-public-key
```

------

### Get the subnet ID for an instance
<a name="instance-metadata-ex-6-imdsv1"></a>

This example gets the subnet ID for an instance.

------
#### [ cURL ]

```
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/02:29:96:8f:6a:2d/subnet-id
subnet-be9b61d7
```

------
#### [ PowerShell ]

```
PS C:\> Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/network/interfaces/macs/02:29:96:8f:6a:2d/subnet-id
subnet-be9b61d7
```

------

### Get the instance tags for an instance
<a name="instance-metadata-ex-7-imdsv1"></a>

If access to instance tags in the instance metadata is turned on, you can get the tags for a instance from instance metadata. For more information, see [Retrieve tags from instance metadata](work-with-tags-in-IMDS.md#retrieve-tags-from-IMDS).

# Transition to using Instance Metadata Service Version 2
<a name="instance-metadata-transition-to-version-2"></a>

If you want to configure your instances to only accept Instance Metadata Service Version 2 (IMDSv2) calls, we recommend that you use the following tools and transition path.

**Topics**
+ [

## Tools for transitioning to IMDSv2
](#tools-for-transitioning-to-imdsv2)
+ [

## Recommended path to requiring IMDSv2
](#recommended-path-for-requiring-imdsv2)

## Tools for transitioning to IMDSv2
<a name="tools-for-transitioning-to-imdsv2"></a>

The following tools can help you identify, monitor, and manage the transition of your software from IMDSv1 to IMDSv2. For the instructions on how to use these tools, see [Recommended path to requiring IMDSv2](#recommended-path-for-requiring-imdsv2).

**AWS software**  
The latest versions of the AWS CLI and AWS SDKs support IMDSv2. To use IMDSv2, update your EC2 instances to use the latest versions. For the minimum AWS SDK versions that support IMDSv2, see [Use a supported AWS SDK](configuring-instance-metadata-service.md#use-a-supported-sdk-version-for-imdsv2).  
All Amazon Linux 2 and Amazon Linux 2023 software packages support IMDSv2. Amazon Linux 2023 disables IMDSv1 by default.

**IMDS Packet Analyzer**  
IMDS Packet Analyzer is an open-source tool that identifies and logs IMDSv1 calls during your instance’s boot phase and runtime operations. By analyzing these logs, you can precisely identify the software making IMDSv1 calls on your instances and determine what needs to be updated to support IMDSv2 only on your instances. You can run IMDS Packet Analyzer from a command line or install it as a service. For more information, see [AWS ImdsPacketAnalyzer](https://github.com/aws/aws-imds-packet-analyzer) on *GitHub*.

**CloudWatch**  
CloudWatch provides the following two metrics for monitoring your instances:  
`MetadataNoToken` – IMDSv2 uses token-backed sessions, while IMDSv1 does not. The `MetadataNoToken` metric tracks the number of calls to the Instance Metadata Service (IMDS) that are using IMDSv1. By tracking this metric to zero, you can determine if and when all of your software has been upgraded to use IMDSv2.  
`MetadataNoTokenRejected` – After you've disabled IMDSv1, you can use the `MetadataNoTokenRejected` metric to track the number of times an IMDSv1 call was attempted and rejected. By tracking this metric, you can ascertain whether your software needs to be updated to use IMDSv2.  
For each EC2 instance, these metrics are mutually exclusive. When IMDSv1 is enabled (`httpTokens = optional`), only `MetadataNoToken` emits. When IMDSv1 is disabled (`httpTokens = required`), only `MetadataNoTokenRejected` emits. For when to use these metrics, see [Recommended path to requiring IMDSv2](#recommended-path-for-requiring-imdsv2).  
For more information, see [Instance metrics](viewing_metrics_with_cloudwatch.md#ec2-cloudwatch-metrics).

**Launch APIs**  
**New instances:** Use the [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) API to launch new instances that require the use of IMDSv2. For more information, see [Configure instance metadata options for new instances](configuring-IMDS-new-instances.md).  
**Existing instances:** Use the [ModifyInstanceMetadataOptions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyInstanceMetadataOptions.html) API to require the use of IMDSv2 on existing instances. For more information, see [Modify instance metadata options for existing instances](configuring-IMDS-existing-instances.md).  
**New instances launched by Auto Scaling groups:** To require the use of IMDSv2 on all new instances launched by Auto Scaling groups, your Auto Scaling groups can use either a launch template or a launch configuration. When you [create a launch template](https://docs.aws.amazon.com/cli/latest/reference/ec2/create-launch-template.html) or [create a launch configuration](https://docs.aws.amazon.com/cli/latest/reference/autoscaling/create-launch-configuration.html), you must configure the `MetadataOptions` parameters to require the use of IMDSv2. The Auto Scaling group launches new instances using the new launch template or launch configuration, but existing instances are not affected.   
**Existing instances in an Auto Scaling group:** Use the [ModifyInstanceMetadataOptions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyInstanceMetadataOptions.html) API to require the use of IMDSv2 on existing instances, or terminate the instances and the Auto Scaling group will launch new replacement instances with the instance metadata options settings that are defined in the new launch template or launch configuration.

**AMIs**  
AMIs configured with the `ImdsSupport` parameter set to `v2.0` will launch instances that require IMDSv2 by default. Amazon Linux 2023 is configured with `ImdsSupport = v2.0`.  
**New AMIs:** Use the [register-image](https://docs.aws.amazon.com/cli/latest/reference/ec2/register-image.html) CLI command to set the `ImdsSupport` parameter to `v2.0` when creating a new AMI.  
**Existing AMIs:** Use the [modify-image-attribute](https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-image-attribute.html) CLI command to set the `ImdsSupport` parameter to `v2.0` when modifying an existing AMI.  
For more information, see [Configure the AMI](configuring-IMDS-new-instances.md#configure-IMDS-new-instances-ami-configuration).

**Account-level controls**  
You can configure default values for all the instance metadata options at the account level. The default values are automatically applied when you launch an instance. For more information. see [Set IMDSv2 as the default for the account](configuring-IMDS-new-instances.md#set-imdsv2-account-defaults).  
You can also enforce the requirement to use IMDSv2 at the account level. When IMDSv2 enforcement is enabled:  
+ **New instances:** Instances configured to launch with IMDSv1 enabled will fail to launch
+ **Existing instances with IMDSv1 disabled:** Attempts to enable IMDSv1 on existing instances will be prevented.
+ **Existing instances with IMDSv1 enabled:** Existing instances with IMDSv1 already enabled will not be affected.
For more information, see [Enforce IMDSv2 at the account level](configuring-IMDS-new-instances.md#enforce-imdsv2-at-the-account-level).

**IAM policies and SCPs**  
You can use an IAM policy or AWS Organizations service control policy (SCP) to control users as follows:  
+ Can't launch an instance using the [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) API unless the instance is configured to use IMDSv2.
+ Can't modify an existing instance using the [ModifyInstanceMetadataOptions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyInstanceMetadataOptions.html) API to re-enable IMDSv1.
The IAM policy or SCP must contain the following IAM condition keys:  
+ `ec2:MetadataHttpEndpoint`
+ `ec2:MetadataHttpPutResponseHopLimit`
+ `ec2:MetadataHttpTokens`
If a parameter in the API or CLI call doesn't match the state specified in the policy that contains the condition key, the API or CLI call fails with an `UnauthorizedOperation` response.  
Furthermore, you can choose an additional layer of protection to enforce the change from IMDSv1 to IMDSv2. At the access management layer with respect to the APIs called via EC2 Role credentials, you can use a condition key in either IAM policies or AWS Organizations service control policies (SCPs). Specifically, by using the condition key `ec2:RoleDelivery` with a value of `2.0` in your IAM policies, API calls made with EC2 Role credentials obtained from IMDSv1 will receive an `UnauthorizedOperation` response. The same thing can be achieved more broadly with that condition required by an SCP. This ensures that credentials delivered via IMDSv1 cannot actually be used to call APIs because any API calls not matching the specified condition will receive an `UnauthorizedOperation` error.  
For example IAM policies, see [Work with instance metadata](ExamplePolicies_EC2.md#iam-example-instance-metadata). For more information on SCPs, see [Service control policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html) in the *AWS Organizations User Guide*.

**Declarative Policies**  
Use Declarative Policies (a feature of AWS Organizations) to centrally set IMDS account defaults, including IMDSv2 enforcement, across your organization. For an example policy, see the **Instance Metadata** tab in the [Supported declarative policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_declarative_syntax.html#declarative-policy-examples) section in the *AWS Organizations User Guide*.

## Recommended path to requiring IMDSv2
<a name="recommended-path-for-requiring-imdsv2"></a>

**Topics**
+ [

### Step 1: Identify instances with IMDSv2=optional and audit IMDSv1 usage
](#path-step-1)
+ [

### Step 2: Update software to IMDSv2
](#path-step-2)
+ [

### Step 3: Require IMDSv2 on instances
](#path-step-3)
+ [

### Step 4: Set IMDSv2=required as the default
](#path-step-4)
+ [

### Step 5: Enforce instances to require IMDSv2
](#path-step-5)

### Step 1: Identify instances with IMDSv2=optional and audit IMDSv1 usage
<a name="path-step-1"></a>

To assess your IMDSv2 migration scope, identify instances that are configured to allow either IMDSv1 or IMDSv2, and audit IMDSv1 calls.

1. **Identify instances that are configured to allow either IMDSv1 or IMDSv2:**

------
#### [ Amazon EC2 console ]

   1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/).

   1. In the navigation pane, choose **Instances**.

   1. To see only the instances that are configured to allow IMDSv1 or IMDSv2, add the filter **IMDSv2 = optional**.

   1. Alternatively, to see whether IMDSv2 is **optional** or **required** for all instances, open the **Preferences** window (gear icon), toggle on **IMDSv2**, and choose **Confirm**. This adds the **IMDSv2** column to the **Instances** table.

------
#### [ AWS CLI ]

   Use the [describe-instances](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/modify-instance-metadata-options.html) command and filter by `metadata-options.http-tokens = optional`, as follows:

   ```
   aws ec2 describe-instances --filters "Name=metadata-options.http-tokens,Values=optional" --query "Reservations[*].Instances[*].[InstanceId]" --output text
   ```

------

1. **Audit IMDSv1 calls on each instance:**

   Use the CloudWatch metric `MetadataNoToken`. This metric shows the number of IMDSv1 calls to the IMDS on your instances. For more information, see [Instance metrics](https://docs.aws.amazon.com/en_us/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html#ec2-cloudwatch-metrics).

1. **Identify software on your instances making IMDSv1 calls:**

   Use the open source [IMDS Packet Analyzer](https://github.com/aws/aws-imds-packet-analyzer) to identify and log IMDSv1 calls during your instance’s boot phase and runtime operations. Use this information to identify the software to update to get your instances ready to use IMDSv2 only. You can run IMDS Packet Analyzer from a command line or install it as a service.

### Step 2: Update software to IMDSv2
<a name="path-step-2"></a>

Update all SDKs, CLIs, and software that use Role credentials on your instances to IMDSv2-compatible versions. For more information about updating the CLI, see [Installing or updating to the latest version of the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) in the *AWS Command Line Interface User Guide*.

### Step 3: Require IMDSv2 on instances
<a name="path-step-3"></a>

After confirming zero IMDSv1 calls through the `MetadataNoToken` metric, configure your existing instances to require IMDSv2. Also, configure all new instances to require IMDSv2. In other words, disable IMDSv1 on all existing and new instances.

1. **Configure existing instances to require IMDSv2:**

------
#### [ Amazon EC2 console ]

   1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/).

   1. In the navigation pane, choose **Instances**.

   1. Select your instance.

   1. Choose **Actions**, **Instance settings**, **Modify instance metadata options**.

   1. For **IMDSv2**, choose **Required**.

   1. Choose **Save**.

------
#### [ AWS CLI ]

   Use the [modify-instance-metadata-options](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/modify-instance-metadata-options.html) CLI command to specify that only IMDSv2 is to be used. 

------
**Note**  
You can modify this setting on running instances. The change takes effect immediately without needing an instance restart.

   For more information, see [Require the use of IMDSv2](configuring-IMDS-existing-instances.md#modify-require-IMDSv2).

1. **Monitor for issues after disabling IMDSv1:**

   1. Track the number of times an IMDSv1 call was attempted and rejected with the `MetadataNoTokenRejected` CloudWatch metric.

   1. If the `MetadataNoTokenRejected` metric records IMDSv1 calls on an instance that is experiencing software issues, this indicates that the software requires updating to use IMDSv2.

1. **Configure new instances to require IMDSv2:**

------
#### [ Amazon EC2 console ]

   1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/).

   1. Follow the steps to [launch an instance](ec2-launch-instance-wizard.md).

   1. Expand **Advanced details**, and for **Metadata version**, choose **V2 only (token required)**.

   1. In the **Summary panel**, review your instance configuration, and then choose **Launch instance**.

      For more information, see [Configure the instance at launch](configuring-IMDS-new-instances.md#configure-IMDS-new-instances-instance-settings).

------
#### [ AWS CLI ]

   AWS CLI: Use the [run-instances](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/run-instances.html) command and specify that IMDSv2 is required.

------

### Step 4: Set IMDSv2=required as the default
<a name="path-step-4"></a>

You can set IMDSv2=required as the default configuration at either the account or organization level. This ensures that all newly launched instances are automatically configured to require IMDSv2.

1. **Set account-level default:**

------
#### [ Amazon EC2 console ]

   1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/).

   1. In the navigation pane, choose **Dashboard**.

   1. On the **Account attributes** card, under **Settings**, choose **Data protection and security**.

   1. Under **IMDS defaults**, choose **Manage**.

   1. For **Instance metadata service **, choose **Enabled**.

   1. For **Metadata version**, choose to **V2 only (token required)**.

   1. Choose **Update**.

------
#### [ AWS CLI ]

   Use the [modify-instance-metadata-defaults](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/modify-instance-metadata-defaults.html) CLI command and specify `--http-tokens required` and `--http-put-response-hop-limit 2`.

------

   For more information, see [Set IMDSv2 as the default for the account](configuring-IMDS-new-instances.md#set-imdsv2-account-defaults).

1. **Alternatively, set organization-level default using a Declarative Policy:**

   Use a Declarative Policy to set the organization default for IMDSv2 to required. For an example policy, see the **Instance Metadata** tab in the [Supported declarative policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_declarative_syntax.html#declarative-policy-examples) section in the *AWS Organizations User Guide*.

### Step 5: Enforce instances to require IMDSv2
<a name="path-step-5"></a>

Once you’ve confirmed that there is no dependency on IMDSv1 on any of your instances, we recommend that you enforce IMDSv2 on all new instances.

Use one of the following options to enforce IMDSv2:

1. **Enforce IMDSv2 with an account property**

   You can enforce the use of IMDSv2 at the account level for each AWS Region. When enforced, instances can only launch if they're configured to require IMDSv2. This enforcement applies regardless of how the instance or AMI is configured. For more information, see [Enforce IMDSv2 at the account level](configuring-IMDS-new-instances.md#enforce-imdsv2-at-the-account-level). To apply this setting at an organization level, set a Declarative Policy. For an example policy, see the **Instance Metadata** tab in the [Supported declarative policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_declarative_syntax.html#declarative-policy-examples) section in the *AWS Organizations User Guide*.

   To prevent a reversal of enforcement, you should use an IAM policy to prevent access to the [ModifyInstanceMetadataDefaults](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyInstanceMetadataDefaults.html) API. For more information, see [Use an IAM policy](configuring-IMDS-new-instances.md#configure-IMDS-new-instances-iam-policy).
**Note**  
This setting does not change the IMDS version of existing instances, but blocks enabling IMDSv1 on existing instances that currently have IMDSv1 disabled.
**Warning**  
If IMDSv2 enforcement is enabled and `httpTokens` is not set to `required` in either the instance configuration at launch, the account settings, or the AMI configuration, the instance launch will fail. For troubleshooting information, see [Launching an IMDSv1-enabled instance fails](troubleshooting-launch.md#launching-an-imdsv1-enabled-instance-fails).

1. **Alternatively, enforce IMDSv2 by using the following IAM or SCP condition keys:**
   + `ec2:MetadataHttpTokens`
   + `ec2:MetadataHttpPutResponseHopLimit`
   + `ec2:MetadataHttpEndpoint`

   These condition keys control the use of the [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) and the [ModifyInstanceMetadataOptions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyInstanceMetadataOptions.html) APIs and corresponding CLIs. If a policy is created, and a parameter in the API call does not match the state specified in the policy using the condition key, the API or CLI call fails with an `UnauthorizedOperation` response.

   For example IAM policies, see [Work with instance metadata](ExamplePolicies_EC2.md#iam-example-instance-metadata).

# Limit access to the Instance Metadata Service
<a name="instance-metadata-limiting-access"></a>

You can consider using local firewall rules to disable access from some or all processes to the Instance Metadata Service (IMDS).

For [Nitro-based instances](instance-types.md#instance-hypervisor-type), the IMDS can be reached from your own network when a network appliance within your VPC, such as a virtual router, forwards packets to the IMDS address, and the default [source/destination check](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_NAT_Instance.html#EIP_Disable_SrcDestCheck) on the instance is disabled. To prevent a source from outside your VPC reaching the IMDS, we recommend that you modify the configuration of the network appliance to drop packets with the destination IPv4 address of the IMDS `169.254.169.254` and, if you enabled the IPv6 endpoint, the IPv6 address of the IMDS `[fd00:ec2::254]`.

## Limit IMDS access for Linux instances
<a name="instance-metadata-limiting-access-linux"></a>

**Using iptables to limit access**

The following example uses Linux iptables and its `owner` module to prevent the Apache webserver (based on its default installation user ID of `apache`) from accessing 169.254.169.254. It uses a *deny rule* to reject all instance metadata requests (whether IMDSv1 or IMDSv2) from any process running as that user.

```
$ sudo iptables --append OUTPUT --proto tcp --destination 169.254.169.254 --match owner --uid-owner apache --jump REJECT
```

Or, you can consider only allowing access to particular users or groups, by using *allow rules*. Allow rules might be easier to manage from a security perspective, because they require you to make a decision about what software needs access to instance metadata. If you use *allow rules*, it's less likely you will accidentally allow software to access the metadata service (that you did not intend to have access) if you later change the software or configuration on an instance. You can also combine group usage with allow rules, so that you can add and remove users from a permitted group without needing to change the firewall rule.

The following example prevents access to the IMDS by all processes, except for processes running in the user account `trustworthy-user`.

```
$ sudo iptables --append OUTPUT --proto tcp --destination 169.254.169.254 --match owner ! --uid-owner trustworthy-user --jump REJECT
```

**Note**  
To use local firewall rules, you need to adapt the preceding example commands to suit your needs. 
By default, iptables rules are not persistent across system reboots. They can be made to be persistent by using OS features, not described here.
The iptables `owner` module only matches group membership if the group is the primary group of a given local user. Other groups are not matched.

**Using PF or IPFW to limit access**

If you are using FreeBSD or OpenBSD, you can also consider using PF or IPFW. The following examples limit access to the IMDS to just the root user.

**PF**

```
$ block out inet proto tcp from any to 169.254.169.254
```

```
$ pass out inet proto tcp from any to 169.254.169.254 user root
```

**IPFW**

```
$ allow tcp from any to 169.254.169.254 uid root
```

```
$ deny tcp from any to 169.254.169.254
```

**Note**  
The order of the PF and IPFW commands matter. PF defaults to last matching rule and IPFW defaults to first matching rule.

## Limit IMDS access for Windows instances
<a name="instance-metadata-limiting-access-windows"></a>

**Using Windows firewall to limit access**

The following PowerShell example uses the built-in Windows firewall to prevent the Internet Information Server webserver (based on its default installation user ID of `NT AUTHORITY\IUSR`) from accessing 169.254.169.254. It uses a *deny rule* to reject all instance metadata requests (whether IMDSv1 or IMDSv2) from any process running as that user.

```
PS C:\> $blockPrincipal = New-Object -TypeName System.Security.Principal.NTAccount ("NT AUTHORITY\IUSR")
PS C:\> $BlockPrincipalSID = $blockPrincipal.Translate([System.Security.Principal.SecurityIdentifier]).Value
PS C:\> $BlockPrincipalSDDL = "D:(A;;CC;;;$BlockPrincipalSID)"
PS C:\> New-NetFirewallRule -DisplayName "Block metadata service from IIS" -Action block -Direction out `
-Protocol TCP -RemoteAddress 169.254.169.254 -LocalUser $BlockPrincipalSDDL
```

Or, you can consider only allowing access to particular users or groups, by using *allow rules*. Allow rules might be easier to manage from a security perspective, because they require you to make a decision about what software needs access to instance metadata. If you use *allow rules*, it's less likely you will accidentally allow software to access the metadata service (that you did not intend to have access) if you later change the software or configuration on an instance. You can also combine group usage with allow rules, so that you can add and remove users from a permitted group without needing to change the firewall rule.

The following example prevents access to instance metadata by all processes running as an OS group specified in the variable `blockPrincipal` (in this example, the Windows group `Everyone`), except for processes specified in `exceptionPrincipal` (in this example, a group called `trustworthy-users`). You must specify both deny and allow principals because Windows Firewall, unlike the `! --uid-owner trustworthy-user` rule in Linux iptables, does not provide a shortcut mechanism to allow only a particular principal (user or group) by denying all the others.

```
PS C:\> $blockPrincipal = New-Object -TypeName System.Security.Principal.NTAccount ("Everyone")
PS C:\> $BlockPrincipalSID = $blockPrincipal.Translate([System.Security.Principal.SecurityIdentifier]).Value
PS C:\> $exceptionPrincipal = New-Object -TypeName System.Security.Principal.NTAccount ("trustworthy-users")
PS C:\> $ExceptionPrincipalSID = $exceptionPrincipal.Translate([System.Security.Principal.SecurityIdentifier]).Value
PS C:\> $PrincipalSDDL = "O:LSD:(D;;CC;;;$ExceptionPrincipalSID)(A;;CC;;;$BlockPrincipalSID)"
PS C:\> New-NetFirewallRule -DisplayName "Block metadata service for $($blockPrincipal.Value), exception: $($exceptionPrincipal.Value)" -Action block -Direction out `
-Protocol TCP -RemoteAddress 169.254.169.254 -LocalUser $PrincipalSDDL
```

**Note**  
To use local firewall rules, you need to adapt the preceding example commands to suit your needs. 

**Using netsh rules to limit access**

You can consider blocking all software using `netsh` rules, but those are much less flexible.

```
C:\> netsh advfirewall firewall add rule name="Block metadata service altogether" dir=out protocol=TCP remoteip=169.254.169.254 action=block
```

**Note**  
To use local firewall rules, you need to adapt the preceding example commands to suit your needs. 
`netsh` rules must be set from an elevated command prompt, and can’t be set to deny or allow particular principals.