Skip to content

Instantly share code, notes, and snippets.

@quiver
Last active March 14, 2024 16:42
Show Gist options
  • Star 49 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save quiver/87f93bc7df6da7049d41 to your computer and use it in GitHub Desktop.
Save quiver/87f93bc7df6da7049d41 to your computer and use it in GitHub Desktop.
retrieve EC2's region from instance metadata

Sometimes you want to retrieve EC2 insntances' region information.

You can query that information through instance metadata(169.254.169.254).

$ curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document
{
  "privateIp" : "172.31.2.15",
  "instanceId" : "i-12341ee8",
  "billingProducts" : null,
  "instanceType" : "t2.small",
  "accountId" : "1234567890",
  "pendingTime" : "2015-11-03T03:09:54Z",
  "imageId" : "ami-383c1956",
  "kernelId" : null,
  "ramdiskId" : null,
  "architecture" : "x86_64",
  "region" : "ap-northeast-1", # <- region
  "version" : "2010-08-31",
  "availabilityZone" : "ap-northeast-1c",
  "devpayProductCodes" : null
}

Response's JSON has a region key, so if you just want to get region, filter the key with jq.

$ sudo yum install -y jq
$ curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region
ap-northeast-1

Usecase : set aws-cli's region

Even if you launch an EC2 instance with IAM role, you can't run commands without supplying region info. Otherwise, you'll encounter errors as follows.

$ aws ec2 describe-vpcs
You must specify a region. You can also configure your region by running "aws configure".

Here's how to set aws-cli's region.

First, check the curren settings.

$ aws configure  list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************GVKA         iam-role
secret_key     ****************bll+         iam-role
    region                <not set>             None    None

region is not set.

Now pass metadata's region to aws configure set region command.

$ aws configure set region `curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region`
$ aws configure get region
ap-northeast-1
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************GVKA         iam-role
secret_key     ****************bll+         iam-role
    region           ap-northeast-1      config-file    ~/.aws/config
$ cat ~/.aws/config
[default]
region = ap-northeast-1

UserData

To configure API region, just add following code to you UserData.

#!/bin/bash
yum install -y jq
REGION=`curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq .region -r`
sudo -u ec2-user aws configure set region $REGION
@tomislacker
Copy link

I've also been frustrated by this and made myself a little native-Python workaround if someone else is interested: https://gist.github.com/tomislacker/da48e4023131a4ac8308b84fa6892b41

@yossale
Copy link

yossale commented Aug 6, 2017

Super useful! Thanks!

@georgechang0117
Copy link

Yes. It's useful. Thank you!

@adv4000
Copy link

adv4000 commented Aug 18, 2017

AWSAVZONE='curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone'
will give you Avalability Zone

AWSREGION=${AWSAVZONE::-1}
will strip last character from Availability Zone, and this will be your Region

@mduca
Copy link

mduca commented Sep 6, 2017

This was helpful thank you!

@nestorbolivar
Copy link

Cheers!!

I was Getting the Region from http://169.254.169.254/latest/meta-data/placement/availability-zone yet it's better to use curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region

@leonmax
Copy link

leonmax commented Sep 27, 2018

in case you don't want to install jq:
curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | grep region | cut -d" -f4

@SantoshKumarArjunan
Copy link

useful, thank you..

@carlosmarin
Copy link

In case someone was looking for the Windows way, here's the powershell form:

  $availability_zone = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/placement/availability-zone
  $region = $availability_zone.Substring(0,$availability_zone.Length-1)

@cc4i
Copy link

cc4i commented Sep 10, 2019

Awesome!

@doublenns
Copy link

doublenns commented Oct 18, 2019

I had to do the same thing recently, but for a completely different use case. Created a Python function that does the same thing:
https://gist.github.com/doublenns/7e3e4b72df4aaeccbeabf87ba767f44e

import requests
import sys
from requests.packages.urllib3 import Retry

def get_instance_region():
    instance_identity_url = "http://169.254.169.254/latest/dynamic/instance-identity/document"
    session = requests.Session()
    retries = Retry(total=3, backoff_factor=0.3)
    metadata_adapter = requests.adapters.HTTPAdapter(max_retries=retries)
    session.mount("http://169.254.169.254/", metadata_adapter)
    try:
        r = requests.get(instance_identity_url, timeout=(2, 5))
    except (requests.exceptions.ConnectTimeout, requests.exceptions.ConnectionError) as err:
        print("Connection to AWS EC2 Metadata timed out: " + str(err.__class__.__name__))
        print("Is this an EC2 instance? Is the AWS metadata endpoint blocked? (http://169.254.169.254/)")
        sys.exit(1)
    response_json = r.json()
    region = response_json.get("region")
    return(region)

From an EC2 instance:

>>> region = get_instance_region()
>>> print(region)
us-east-2

From system that isn't an EC2 instance:

>>> region = get_instance_region()
Connection to AWS EC2 Metadata timed out: ConnectTimeout
Is this an EC2 instance? Is the AWS metadata endpoint blocked? (http://169.254.169.254/) 

@kulswaroop
Copy link

I had to do the same thing recently, but for a completely different use case. Created a Python function that does the same thing:
https://gist.github.com/doublenns/7e3e4b72df4aaeccbeabf87ba767f44e

import requests
import sys
from requests.packages.urllib3 import Retry

def get_instance_region():
    instance_identity_url = "http://169.254.169.254/latest/dynamic/instance-identity/document"
    session = requests.Session()
    retries = Retry(total=3, backoff_factor=0.3)
    metadata_adapter = requests.adapters.HTTPAdapter(max_retries=retries)
    session.mount("http://169.254.169.254/", metadata_adapter)
    try:
        r = requests.get(instance_identity_url, timeout=(2, 5))
    except (requests.exceptions.ConnectTimeout, requests.exceptions.ConnectionError) as err:
        print("Connection to AWS EC2 Metadata timed out: " + str(err.__class__.__name__))
        print("Is this an EC2 instance? Is the AWS metadata endpoint blocked? (http://169.254.169.254/)")
        sys.exit(1)
    response_json = r.json()
    region = response_json.get("region")
    return(region)

From an EC2 instance:

>>> region = get_instance_region()
>>> print(region)
us-east-2

From system that isn't an EC2 instance:

>>> region = get_instance_region()
Connection to AWS EC2 Metadata timed out: ConnectTimeout
Is this an EC2 instance? Is the AWS metadata endpoint blocked? (http://169.254.169.254/) 

Thanks, it helped!

@doublenns
Copy link

Thanks, it helped!

Awesome. I'm glad!

@qingbozhou
Copy link

Now AWS provides a more convenient way for getting the region: http://169.254.169.254/latest/meta-data/placement/region

See https://forums.aws.amazon.com/thread.jspa?threadID=77228

@jbenninghoff
Copy link

There is a builtin command to get the ec2 metadata:
/opt/aws/bin/ec2-metadata -z
placement: us-west-2a

OR:

/opt/aws/bin/ec2-metadata -z |cut -d' ' -f2
us-west-2a

Many other options too, use --help to list them

@fadyWageehRack
Copy link

In case someone was looking for the Windows way, here's the powershell form:

  $availability_zone = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/placement/availability-zone
  $region = $availability_zone.Substring(0,$availability_zone.Length-1)

It can be easier and in one command:

Windows Powershell:
Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/placement/region

Linux:
curl -s http://169.254.169.254/latest/meta-data/placement/region

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment