1. 개요
IMDS(Instance Metadata Service)는 EC2 인스턴스가 자기 정보를 읽어 오는 서비스다. 인스턴스 안에서 링크 로컬 주소 169.254.169.254 로 요청하면 인스턴스 ID, 네트워크 정보, 그리고 인스턴스에 붙은 IAM 역할의 임시 자격 증명을 돌려준다.
# IMDSv2 — 세션 토큰을 먼저 받고 그 토큰으로 읽는다
TOKEN=$(curl -s -X PUT http://169.254.169.254/latest/api/token \
-H "X-aws-ec2-metadata-token-ttl-seconds: 60")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/
인스턴스 안의 AWS SDK 는 이 경로로 자격 증명을 받아 쓴다. 그래서 인스턴스 안에서 이 주소에 닿는 프로그램은 누구든 그 인스턴스의 AWS 권한을 쓸 수 있다.
2. 버전
| IMDSv1 | IMDSv2 | |
|---|---|---|
| 요청 | GET 한 번 | PUT 으로 세션 토큰을 받은 뒤 그 토큰으로 GET |
| SSRF 에 대한 내성 | 약함. URL 만 조작하면 읽힌다 | 강함. 임의의 PUT 과 헤더를 만들어야 한다 |
| 강제 | — | http_tokens = "required" 로 v1 을 끈다 |
웹 앱이 사용자 입력 URL 로 요청을 보내는 SSRF 취약점이 있으면, IMDSv1 에서는 그 앱을 통해 자격 증명이 새어 나간다. IMDSv2 를 강제하면 이 경로가 대부분 막힌다.
3. hop limit
hop limit 은 IMDSv2 토큰 응답(PUT 의 응답) 패킷의 TTL 이다. 패킷이 네트워크 장비를 하나 지날 때마다 TTL 이 1 줄어, 0 이 되면 버려진다.
| hop limit | 결과 |
|---|---|
| 1 | 인스턴스 자신만 토큰을 받는다. 컨테이너(브리지·veth 를 한 번 더 지남)는 받지 못한다 |
| 2 | 인스턴스 위의 컨테이너도 토큰을 받는다 |
쿠버네티스 노드에서 hop limit 1 은 일반 Pod 가 노드의 IAM 역할을 쓰지 못하게 막는다. hostNetwork: true 인 Pod 는 노드와 같은 네트워크를 쓰므로 막히지 않는다.
# Terraform launch template
metadata_options {
http_endpoint = "enabled"
http_tokens = "required" # IMDSv2 강제
http_put_response_hop_limit = 1 # Pod 차단
}
4. 컨테이너에서의 위험
| 경로 | 결과 |
|---|---|
| Pod 가 IMDS 에 닿음 | 노드 역할로 ECR 이미지 받기, EC2 정보 조회 등 노드 권한 사용 |
| 컨테이너 탈출 | 노드 자체가 되므로 hop limit 과 상관없이 IMDS 를 쓴다 |
hop limit 은 첫 번째 경로만 막는다. 두 번째는 gVisor 같은 샌드박스가 맡는다. 여러 팀의 코드가 한 노드에서 도는 클러스터에서는 두 겹을 함께 쓰고, 네트워크 정책으로 169.254.169.254 를 한 번 더 막는다.
5. Pod 가 AWS 권한이 필요할 때
노드 역할을 Pod 에 나눠 주는 대신, Pod 마다 따로 권한을 준다.
| 방식 | 원리 |
|---|---|
| IRSA | ServiceAccount 토큰(OIDC)으로 IAM 역할을 직접 받는다 |
| EKS Pod Identity | 노드의 에이전트가 ServiceAccount 에 연결된 역할의 자격 증명을 준다 |
이 방식을 쓰면 노드의 hop limit 을 1 로 두고도 필요한 Pod 만 AWS 를 쓸 수 있다.
6. 확인 명령
# 인스턴스 설정 확인
aws ec2 describe-instances --instance-ids i-0123456789abcdef0 \
--query 'Reservations[].Instances[].MetadataOptions'
# Pod 안에서 막혔는지 확인 (응답이 없어야 정상)
wget -q -T 3 -O- http://169.254.169.254/latest/meta-data/ || echo blocked
7. 관련 문서
- gVisor — 컨테이너 탈출 경로를 줄이는 샌드박스
- Cilium — 메타데이터 주소를 정책으로 막고 차단을 기록
- Subnet — 링크 로컬 대역
169.254.0.0/16 - IRSA (예정) — ServiceAccount 로 IAM 역할을 받는 방식