Cara Mendapatkan Instance ID EC2 via Metadata: IMDSv2 vs IMDSv1
Saat menulis skrip otomasi yang berjalan di dalam EC2 — entah itu untuk self-registration ke load balancer, pengiriman log, atau bootstrap konfigurasi — kamu butuh Instance ID tanpa harus hardcode atau bergantung pada variabel eksternal. Instance Metadata Service (IMDS) adalah cara standarnya, tapi banyak skrip lama masih pakai IMDSv1 yang punya celah keamanan serius yang sering diabaikan sampai terjadi insiden nyata.
TL;DR: IMDSv1 vs IMDSv2 untuk Mengambil Instance ID
| Aspek | IMDSv1 | IMDSv2 |
|---|---|---|
| Mekanisme Auth | Tidak ada — request langsung | Session token berbasis TTL |
| Risiko SSRF | Tinggi — attacker bisa baca metadata via app rentan | Mitigasi signifikan — butuh PUT request terlebih dahulu |
| Perintah curl | Satu langkah, tanpa header tambahan | Dua langkah: ambil token, lalu ambil data |
| Rekomendasi AWS | Deprecated untuk deployment baru | Standar yang direkomendasikan |
| Enforcement | Bisa dinonaktifkan per instance | Bisa di-enforce via IMDSv2-only mode |
Bagaimana Instance Metadata Service Bekerja
IMDS adalah HTTP endpoint lokal yang hanya bisa diakses dari dalam instance itu sendiri, di alamat 169.254.169.254. Ini adalah link-local address — tidak routable ke luar instance, tidak melewati internet gateway, dan tidak bisa diakses dari instance lain meski berada di subnet yang sama.
Data yang tersedia mencakup Instance ID, AMI ID, tipe instance, availability zone, IAM role credentials, dan banyak lagi. Semua ini disajikan sebagai plain HTTP tanpa TLS — yang berarti keamanannya bergantung sepenuhnya pada siapa yang bisa membuat request ke alamat tersebut.
- IMDSv1 (kiri): Aplikasi atau skrip langsung mengirim GET request ke endpoint metadata. Tidak ada autentikasi. Jika ada celah SSRF di aplikasi, attacker bisa meminta aplikasi untuk fetch URL tersebut atas namanya.
- IMDSv2 (kanan): Sebelum bisa membaca metadata, client harus melakukan PUT request untuk mendapatkan session token. PUT request tidak bisa di-forward oleh sebagian besar proxy dan SSRF sederhana — ini yang menjadi lapisan pertahanannya.
- Token TTL: Token IMDSv2 punya masa berlaku yang kamu tentukan sendiri (dalam detik). Untuk skrip satu kali jalan, TTL pendek sudah cukup.
Mengapa IMDSv1 Berbahaya: Skenario SSRF Nyata
Serangan Server-Side Request Forgery (SSRF) terjadi ketika attacker bisa membuat server melakukan HTTP request ke URL yang mereka tentukan. Dengan IMDSv1, jika aplikasi web kamu punya endpoint yang menerima URL dan melakukan fetch — misalnya fitur 'preview link' atau webhook — attacker cukup mengirimkan http://169.254.169.254/latest/meta-data/iam/security-credentials/ sebagai target.
Hasilnya? Temporary credentials IAM role yang melekat pada instance tersebut, lengkap dengan AccessKeyId, SecretAccessKey, dan Token. Ini bukan skenario teoritis — insiden besar di industri cloud terjadi persis dengan pola ini.
IMDSv2 tidak menghilangkan SSRF, tapi memutus rantai eksploitasinya. Attacker masih bisa meminta aplikasimu fetch URL eksternal, tapi mereka tidak bisa minta aplikasimu melakukan PUT request untuk mendapatkan token terlebih dahulu — karena sebagian besar SSRF hanya bisa melakukan GET.
Satu detail yang sering terlewat: IMDSv2 juga menolak request yang mengandung header X-Forwarded-For. Ini secara eksplisit memblokir skenario di mana request melewati proxy layer sebelum sampai ke metadata endpoint.
Cara Mengambil Instance ID dengan IMDSv2
Berikut cara yang benar untuk mendapatkan Instance ID dari dalam instance EC2 menggunakan IMDSv2. Prosesnya dua langkah: ambil token sesi, lalu gunakan token tersebut untuk query metadata.
Menggunakan curl (Shell Script)
# Langkah 1: Ambil session token IMDSv2
# TTL diset 21600 detik (6 jam) — sesuaikan dengan kebutuhan skrip kamu
TOKEN=$(curl -s -X PUT \
'http://169.254.169.254/latest/api/token' \
-H 'X-aws-ec2-metadata-token-ttl-seconds: 21600')
# Langkah 2: Gunakan token untuk mengambil Instance ID
INSTANCE_ID=$(curl -s \
'http://169.254.169.254/latest/meta-data/instance-id' \
-H "X-aws-ec2-metadata-token: $TOKEN")
echo "Instance ID: $INSTANCE_ID"
Untuk skrip yang berjalan singkat, TTL 21600 detik lebih dari cukup. Jika skrip kamu berjalan lama atau dipanggil berulang kali, pertimbangkan untuk menyimpan token dan memeriksa apakah masih valid sebelum melakukan PUT lagi.
Menggunakan Python (boto3 tidak diperlukan)
import urllib.request
def get_instance_id():
# Langkah 1: Ambil IMDSv2 token
token_url = 'http://169.254.169.254/latest/api/token'
token_request = urllib.request.Request(
token_url,
method='PUT',
headers={'X-aws-ec2-metadata-token-ttl-seconds': '21600'}
)
with urllib.request.urlopen(token_request, timeout=2) as response:
token = response.read().decode('utf-8')
# Langkah 2: Ambil Instance ID menggunakan token
metadata_url = 'http://169.254.169.254/latest/meta-data/instance-id'
metadata_request = urllib.request.Request(
metadata_url,
headers={'X-aws-ec2-metadata-token': token}
)
with urllib.request.urlopen(metadata_request, timeout=2) as response:
return response.read().decode('utf-8')
instance_id = get_instance_id()
print(f'Instance ID: {instance_id}')
Perhatikan timeout=2 — ini penting. Jika skrip dijalankan di luar EC2 (misalnya saat testing lokal), tanpa timeout kamu akan menunggu lama sebelum request gagal.
Menggunakan AWS CLI (ec2-metadata helper)
Jika AWS CLI sudah terinstal di instance, ada cara alternatif menggunakan Instance Metadata Query Tool, tapi cara paling portabel tetap via curl atau HTTP langsung karena tidak bergantung pada versi CLI yang terinstal.
# AWS CLI v2 mendukung IMDSv2 secara otomatis
aws ec2 describe-instances \
--instance-ids $(curl -s \
-H "X-aws-ec2-metadata-token: $(curl -s -X PUT \
'http://169.254.169.254/latest/api/token' \
-H 'X-aws-ec2-metadata-token-ttl-seconds: 60')" \
'http://169.254.169.254/latest/meta-data/instance-id') \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text \
--region us-east-1
Meng-enforce IMDSv2: Menonaktifkan IMDSv1 di Instance
Menggunakan IMDSv2 di skrip saja tidak cukup jika IMDSv1 masih aktif — instance tetap rentan jika ada aplikasi lain yang berjalan di dalamnya yang masih pakai V1. Langkah yang benar adalah meng-enforce IMDSv2-only mode di level instance.
Saat Launch: Konfigurasi via AWS CLI
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t3.micro \
--metadata-options 'HttpTokens=required,HttpEndpoint=enabled' \
--region us-east-1 \
--count 1
Untuk Instance yang Sudah Berjalan
# Ganti INSTANCE_ID dengan ID instance target
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-endpoint enabled \
--region us-east-1
Parameter kunci di sini adalah --http-tokens required. Nilai required berarti semua request ke IMDS harus menyertakan token IMDSv2 yang valid — request IMDSv1 tanpa token akan ditolak dengan HTTP 401.
Verifikasi Status IMDS di Instance
aws ec2 describe-instances \
--instance-ids i-1234567890abcdef0 \
--query 'Reservations[0].Instances[0].MetadataOptions' \
--output json \
--region us-east-1
Output yang kamu inginkan:
{
"State": "applied",
"HttpTokens": "required",
"HttpEndpoint": "enabled",
"HttpPutResponseHopLimit": 1,
"InstanceMetadataTags": "disabled"
}
HttpPutResponseHopLimit: 1 adalah default yang penting — ini memastikan token PUT request tidak bisa di-forward lebih dari satu hop, memblokir skenario di mana container di dalam instance mencoba mengakses metadata host melalui network hop tambahan.
Meng-enforce IMDSv2 di Seluruh Akun via SCP atau IAM
Enforcement per-instance tidak skalabel untuk akun dengan ratusan instance. Pendekatan yang lebih kuat adalah menggunakan Service Control Policy (SCP) di AWS Organizations untuk mencegah launch instance baru tanpa IMDSv2-required, atau menggunakan AWS Config rule untuk mendeteksi instance yang masih mengizinkan IMDSv1.
🔽 Klik untuk melihat contoh SCP: Wajibkan IMDSv2 saat Launch
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireIMDSv2",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotEquals": {
"ec2:MetadataHttpTokens": "required"
}
}
}
]
}
SCP ini menolak ec2:RunInstances jika parameter MetadataHttpTokens tidak di-set ke required. Ini berlaku untuk semua principal di account yang terkena SCP tersebut, termasuk administrator — pastikan kamu sudah menguji di environment non-produksi terlebih dahulu.
Pengalaman Lapangan: Diagnosis yang Salah Arah
Ada satu pola kegagalan yang sering muncul saat migrasi dari IMDSv1 ke IMDSv2: skrip bootstrap yang berjalan di dalam container Docker di atas EC2 tiba-tiba gagal mengambil metadata setelah instance di-enforce ke IMDSv2-only.
Gejala yang terlihat: curl ke 169.254.169.254 timeout, bukan HTTP 401. Diagnosis pertama yang salah: firewall atau security group memblokir traffic. Padahal security group tidak mengontrol traffic ke link-local address.
Penyebab sebenarnya: HttpPutResponseHopLimit masih di nilai default 1. Ketika container melakukan PUT request untuk mendapatkan token, response dari IMDS harus melewati satu network hop tambahan (dari host ke container), sehingga hop limit terlampaui dan token tidak pernah sampai ke container.
Perbaikannya: naikkan hop limit ke 2 untuk instance yang menjalankan container.
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-endpoint enabled \
--http-put-response-hop-limit 2 \
--region us-east-1
Pelajarannya: timeout ke metadata endpoint di dalam container hampir selalu soal hop limit, bukan network policy.
- Hop Limit = 1 (default): PUT request dari container melewati virtual network interface host, dihitung sebagai satu hop. Response dari IMDS kembali ke host, tapi tidak bisa diteruskan ke container karena hop limit sudah habis.
- Hop Limit = 2: Response bisa melewati dua hop — dari IMDS ke host, lalu dari host ke container. Token berhasil diterima.
- Untuk container yang berjalan di dalam container (nested), hop limit mungkin perlu dinaikkan lebih jauh, tapi ini jarang diperlukan dan harus dipertimbangkan dari sisi keamanan.
Cara Mendapatkan Instance ID EC2: Ringkasan dan Langkah Selanjutnya
Mengambil Instance ID via IMDS adalah operasi sederhana, tapi pilihan antara IMDSv1 dan IMDSv2 punya implikasi keamanan yang signifikan. IMDSv2 bukan sekadar 'versi lebih baru' — ini adalah perubahan model keamanan fundamental yang memutus kelas serangan SSRF yang telah menyebabkan beberapa breach besar di industri.
Langkah konkret yang bisa kamu ambil sekarang:
- Audit semua skrip dan aplikasi yang berjalan di EC2 — cari penggunaan
169.254.169.254tanpa headerX-aws-ec2-metadata-token. - Enforce IMDSv2-only di semua instance yang ada menggunakan
modify-instance-metadata-options. - Terapkan SCP untuk mencegah instance baru diluncurkan tanpa IMDSv2-required.
- Jika menggunakan container di EC2, verifikasi
HttpPutResponseHopLimitsudah di-set ke nilai yang tepat. - Pantau dengan AWS Config rule
ec2-imdsv2-checkuntuk deteksi drift konfigurasi secara kontinu.
Referensi resmi: AWS EC2 Instance Metadata Service Documentation.
Glosarium
| Istilah | Penjelasan |
|---|---|
| IMDS | Instance Metadata Service — HTTP endpoint lokal di 169.254.169.254 yang menyediakan informasi tentang instance EC2 yang sedang berjalan. |
| IMDSv2 | Versi kedua IMDS yang menggunakan session-oriented authentication berbasis token PUT request sebelum bisa membaca metadata. |
| SSRF | Server-Side Request Forgery — serangan di mana attacker membuat server melakukan HTTP request ke URL yang mereka kendalikan, termasuk endpoint internal. |
| HttpPutResponseHopLimit | Parameter IMDS yang mengontrol berapa banyak network hop yang diizinkan untuk response token PUT request. Default 1, perlu dinaikkan untuk container. |
| Link-local address | Alamat IP (169.254.0.0/16) yang hanya valid dalam satu network segment dan tidak bisa di-route ke jaringan lain. |
Komentar
Posting Komentar