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
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())