pythonamazon-web-servicesbashamazon-ec2

Get metadata from an aws ec2-flask instance


I need to build an html that has a certain title, my name, and then the following metadata of the instance itself: Instance ID, Availability Zone, Private IPv4 Address, and Subnet ID.

I have to host this program in a docker repository by doing an ssh to the instance.

I think that everyting works proporly, but after executing some comands in the bash and finaly running the program, it gets stuck.

Here is the python program:

from flask import Flask
from ec2_metadata import ec2_metadata

app = Flask(__name__)

@app.route('/')
def get_instance_metadata():
    instance_id = ec2_metadata.instance_id
    availability_zone = ec2_metadata.availability_zone
    private_ip = ec2_metadata.private_ipv4
    subnet_id = ec2_metadata.network_interfaces[ec2_metadata.mac]['subnet-id']
    
    return f"""
    <html>
        <body>
            <h1>EC2 Metadata</h1>
            <p><strong>Instance ID:</strong> {instance_id}</p>
            <p><strong>Availability Zone:</strong> {availability_zone}</p>
            <p><strong>Private IP:</strong> {private_ip}</p>
            <p><strong>Subnet ID:</strong> {subnet_id}</p>
        </body>
    </html>
    """


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

and here are the steps I followed in bash until I got the error mentioned above

sudo yum update

sudo yum install docker

sudo systemctl start docker

sudo systemctl enable docker

sudo systemctl status docker

mkdir flask_docker

nano flask_docker/app.py

nano flask_docker/requirements.txt
# the requirements are:
# Flask==1.1.2
# Werkzeug==1.0.1
# Jinja2==2.11.3
# MarkupSafe==1.1.1
# itsdangerous==1.1.0
# click==7.1.2
# ec2-metadata==0.13
# requests==2.26.0

nano flask_docker/Dockerfile
# inside this file I did this:
# syntax=docker/dockerfile:1.4
# FROM python:3.8-alpine

# WORKDIR /app

# COPY requirements.txt requirements.txt

# RUN pip3 install -r requirements.txt

# COPY . .

# CMD ["python3", "app.py"]

sudo docker build -t flask_container .

sudo docker images

sudo docker run -p 5000:5000 -d flask_container

sudo docker ps

netstat -tulnp

curl http://127.0.0.1:5000
# HERE IS WHERE I FOUND THE PROBLEM

Solution

  • Could you share the ec2_metadata code?

    Based on the issue, it’s likely that either there’s a core logic error or your EC2 instance is using IMDSv2, while the code might be trying to fetch the metadata using the IMDSv1 approach.

    this is how to get the metadata with python using IMDSv1

    import requests
    
    def get_metadata_v1():
        url = "http://169.254.169.254/latest/meta-data/"
        try:
            response = requests.get(url, timeout=2)
            response.raise_for_status()
            return response.text
        except requests.exceptions.RequestException as e:
            print(f"Failed to fetch metadata using IMDSv1: {e}")
            return None
    
    print(get_metadata_v1())
    

    and this is how to get it using IMDSv2

    import requests
    
    def get_metadata_v2():
        base_url = "http://169.254.169.254/latest/meta-data/"
        token_url = "http://169.254.169.254/latest/api/token"
        
        try:
            # Step 1: Get the token
            token_response = requests.put(
                token_url, headers={"X-aws-ec2-metadata-token-ttl-seconds": "21600"}, timeout=2
            )
            token_response.raise_for_status()
            token = token_response.text
    
            # Step 2: Use the token to fetch metadata
            metadata_response = requests.get(
                base_url, headers={"X-aws-ec2-metadata-token": token}, timeout=2
            )
            metadata_response.raise_for_status()
            return metadata_response.text
        except requests.exceptions.RequestException as e:
            print(f"Failed to fetch metadata using IMDSv2: {e}")
            return None
    
    print(get_metadata_v2())