169.254.169.254는 AWS 것이 아니다 — 멀티 클라우드 IMDS 보안 전수조사

이군·2026년 4월 22일

보안 문서, 블로그, CTF 라이트업, 심지어 벤더 교육 자료까지 — 클라우드 메타데이터 이야기는 대부분 AWS 케이스로 끝난다.
“EC2 안에서 curl 169.254.169.254/latest/meta-data/... 때리면 크리덴셜 나오잖아? 그래서 IMDSv2 써야지” 하고 끝.

그런데 실제 운영 환경은 AWS만 있는 게 아니다. GCP, Azure, OCI, Alibaba, IBM Cloud, Tencent, DigitalOcean — 전부 자체 메타데이터 서비스(IMDS)를 제공하고, 각자 보안 설계가 다르며, 각자 다른 공격 표면이 있다.

이번 포스팅은 “왜 169.254.169.254인가”부터 각 CSP별 IMDS 인증 방식의 차이, SSRF 방어 수준 비교, 그리고 Kubernetes 환경에서 추가로 신경 써야 할 것까지 한 번에 정리한다.


1. 왜 하필 169.254.169.254인가

먼저 IP 자체부터. 169.254.0.0/16은 IETF가 RFC 3927에서 정의한 link-local address 대역이다. 링크 로컬이라는 말 그대로 같은 L2 세그먼트 내에서만 유효하고, 라우팅되지 않는다 — 인스턴스 외부에서는 절대로 이 IP에 도달할 수 없다는 뜻이다. 이 특성은 메타데이터 서비스가 호스트 VM 내부에서만 호출 가능해야 한다는 요구사항과 맞아떨어진다.

그래서 AWS가 EC2 메타데이터 서비스를 169.254.169.254에 올렸고, 이후 거의 모든 CSP가 관례로 같은 주소를 따라간다. 예외는 Alibaba Cloud 하나. 자세한 건 아래 표에서.

169.254.0.0/16 → link-local, non-routable
    └─ 169.254.169.254 → de-facto cloud metadata endpoint

2. 클라우드 7사 IMDS 엔드포인트 전수조사

먼저 한눈에 볼 수 있게 표로 정리했다.

CSP엔드포인트 IPDNS인증 방식보안 버전 기본값
AWS EC2169.254.169.254 + IPv6 fd00:ec2::254IMDSv2: PUT /latest/api/token → 토큰 헤더계정/리전 레벨 기본값 설정 API는 2024-03, 새로 출시되는 인스턴스 타입만 IMDSv2-only 기본
GCP Compute Engine169.254.169.254metadata.google.internalMetadata-Flavor: Google 헤더 필수 (v1) / v0.1·v1beta12020-09-30 셧다운설계 시점부터 헤더 필수
Azure VM169.254.169.254Metadata: true 헤더 + ?api-version=... 필수설계 시점부터 헤더 필수
Oracle Cloud (OCI)169.254.169.254v2: Authorization: Bearer Oracle 헤더IMDSv2 권고, v1 비활성화 가능
Alibaba Cloud ECS100.100.100.200 (유일한 예외)보안 강화 모드: PUT /latest/api/tokenX-aliyun-ecs-metadata-token구버전 인스턴스는 기본 비활성
IBM Cloud VPC169.254.169.254토큰 필수기본 비활성, 명시적 활성화 필요
Tencent Cloud169.254.169.254metadata.tencentyun.com
DigitalOcean169.254.169.254— (v1-only 형태)

2.1 AWS — IMDSv2 (PUT 토큰 방식)

AWS는 2019년 Capital One 사건 이후 IMDSv2를 발표했다. 핵심은 세션 토큰을 PUT으로 받아온다는 점이다.

# 1) 세션 토큰 발급 (PUT 요청 + TTL 헤더)
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 3600")

# 2) 토큰으로 메타데이터 조회
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/

왜 PUT인가? 대부분의 SSRF 취약점은 GET만 보낼 수 있고, 커스텀 헤더를 주입할 수 없다. PUT + 커스텀 헤더 + TTL 조합이 SSRF 공격 표면을 한 번에 막는다.

IPv6 엔드포인트도 있다 — fd00:ec2::254. 듀얼스택 VPC에서 필요할 수 있으니 방화벽 규칙 작성 시 잊지 말 것.

2.2 GCP — 헤더 기반 방어 (처음부터)

GCP는 “뒤늦게 추가”가 아니라 설계 시점부터 커스텀 헤더를 강제했다. 다만 초기에는 헤더를 요구하지 않는 레거시 엔드포인트 v0.1v1beta1이 공존했고, 이게 오래된 SSRF PoC/CTF 라이트업에서 자주 등장하는 바이패스 경로였다. 이 두 엔드포인트는 2020년 9월 30일부로 완전히 셧다운되었고, 현재 유효한 API는 computeMetadata/v1/만 남았다 — 즉 현재 GCP에서는 Metadata-Flavor: Google 헤더 없이 메타데이터에 접근할 방법이 공식적으로 없다.

curl -s -H "Metadata-Flavor: Google" \
  "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"

헤더가 없으면 요청은 거부된다. 단순 SSRF(GET + 헤더 주입 불가)로는 이 헤더를 만들어낼 수 없기 때문에 기본 방어선이 된다. 경로는 /computeMetadata/v1/로 AWS와 다르고, 프로젝트 단위 메타데이터(project/)까지 노출된다는 점도 알아두자.

참고로 Terraform google_compute_instance에서 metadata = { disable-legacy-endpoints = "true" }를 설정하라는 권고는 과거 레거시 엔드포인트가 살아있던 시절의 유물이다. 지금은 엔드포인트 자체가 없으니 설정해도/안 해도 동작은 같지만, 컴플라이언스 스캐너(Aqua AVD-GCP-0048 등)가 이 플래그를 본다. 조직 정책상 명시적으로 true로 두는 편이 무난하다.

2.3 Azure — 헤더 + API 버전

Azure도 설계 시점부터 헤더와 API 버전을 강제한다.

curl -s -H "Metadata: true" --noproxy "*" \
  "http://169.254.169.254/metadata/instance?api-version=2021-02-01"

포인트:

  • Metadata: true 헤더 필수
  • api-version 쿼리 파라미터 필수
  • 프록시를 타면 안 됨 (--noproxy "*")
  • 경로는 /metadata/instance, /metadata/identity/oauth2/token

스케줄 이벤트, 로드밸런서 메타데이터 같은 Azure 특화 정보도 IMDS에서 받을 수 있다.

2.4 Oracle Cloud — v1 deprecated, v2는 Bearer 토큰

OCI는 두 버전을 지원한다. v1은 인증 없음, v2는 정적 Bearer 토큰이다.

# IMDSv2
curl -H "Authorization: Bearer Oracle" -L \
  http://169.254.169.254/opc/v2/instance/

흥미로운 점: Authorization: Bearer Oracle토큰 값이 고정 문자열 “Oracle”이다. 동적 토큰이 아니다. 그럼에도 SSRF 방어 효과는 있다. SSRF가 이 헤더를 주입할 수 없다면 요청은 차단되기 때문. 경로는 /opc/v2/ 프리픽스가 특징. Oracle은 v1을 비활성화하라고 공식 권고한다.

2.5 Alibaba Cloud — 유일한 예외 100.100.100.200

6개 CSP가 같은 IP를 쓰는데 알리바바만 다르다. Link-local이 아닌 100.100.100.200.

# 일반 모드 (인증 없음, v1과 유사)
curl http://100.100.100.200/latest/meta-data/

# 보안 강화 모드 (IMDSv2와 동일한 설계)
TOKEN=$(curl -s -X PUT "http://100.100.100.200/latest/api/token" \
  -H "X-aliyun-ecs-metadata-token-ttl-seconds: 21600")
curl -H "X-aliyun-ecs-metadata-token: $TOKEN" \
  http://100.100.100.200/latest/meta-data/instance-id

알리바바 공식 문서도 SSRF를 명시적으로 언급한다. 공격자가 http://100.100.100.200/latest/meta-data/를 애플리케이션에 주입해 RAM role 크리덴셜을 탈취하는 시나리오를 전제로, 보안 강화 모드를 기본으로 쓰라고 한다. AWS IMDSv2와 설계는 거의 동일하다.

2.6 IBM Cloud VPC — 기본 비활성화

IBM Cloud VPC의 Virtual Server IMDS는 기본적으로 꺼져 있다. 켜더라도 토큰이 필수다. 아마 이 중에서 가장 보수적인 기본값.

2.7 Tencent / DigitalOcean

Tencent Cloud는 metadata.tencentyun.com이라는 별도 DNS를 제공한다. DigitalOcean은 AWS IMDSv1에 가까운 단순한 GET 기반 — Project Discovery의 리서치에서도 반복적으로 언급되는, 상대적으로 SSRF에 약한 타깃이다.


3. 그래서 뭐가 위험한가 — Capital One, 2019

이 주제를 다루면서 Capital One 사건을 빠뜨릴 수는 없다. 요약하면:

  • 공격 벡터: 오픈소스 WAF(ModSecurity)의 미스컨피그로 SSRF 가능
  • 타깃: EC2에 붙은 ISRM-WAF-Role IAM 역할 (S3 전방위 권한)
  • 경로:
  1. SSRF로 http://169.254.169.254/latest/meta-data/iam/security-credentials/ISRM-WAF-Role 요청
  2. 임시 크리덴셜 획득 (당시 IMDSv1만 존재)
  3. S3 버킷 목록 조회 및 약 30GB 데이터 탈취
  • 피해: 미국인 약 1억 명 + 캐나다인 600만 명 개인정보 유출, $80M 과징금

이게 AWS가 IMDSv2를 발표한 직접적 이유다. 그리고 이 사건 이후에도 — 놀랍게도 — 2022년 시점에 EC2 인스턴스의 약 93%가 여전히 IMDSv1을 허용하고 있었다는 리서치가 있다. AWS의 기본값 정책 타임라인을 정리하면:

  • 2019-11: IMDSv2 출시
  • 2023-03: Amazon Linux 2023 AMI가 IMDSv2-only로 출시
  • 2023-11: 콘솔 Quick Start 런치 경로에서 IMDSv2-only 적용
  • 2024-03-25: ModifyInstanceMetadataDefaults API 출시 — 리전 단위로 IMDSv2-only 기본값을 걸 수 있게 됨
  • 2024년 중반: 새로 출시되는 인스턴스 타입은 IMDSv2-only 기본

여기서 자주 오해하는 포인트: 기존에 이미 존재하는 인스턴스 타입(m5, c5, r5 등)을 지금 새로 띄우면 기본은 여전히 IMDSv1 허용이다. 계정/리전 레벨 defaults를 명시적으로 걸거나, Launch Template/SCP로 강제해야 한다. 2025년 3월에는 GreyNoise가 SSRF 관련 10개 CVE에 대해 약 400개 IP가 동시다발적으로 익스플로잇을 시도하는 캠페인을 관측했다. SSRF는 사라진 공격이 아니다. 계속 현역이다.


4. Kubernetes/EKS 환경 — IMDSv2만으로는 부족하다

운영 환경이 대부분 컨테이너인 분들에게 특히 중요한 부분이다. IMDSv2를 켠다고 Pod의 크리덴셜 탈취가 막히지는 않는다.

4.1 문제의 본질

EKS에서 워커 노드는 EC2이고, 노드에는 인스턴스 프로파일(IAM 역할)이 붙어있다. 컨테이너는 호스트에서 돌아가는 그냥 프로세스이므로, Pod 안에서 169.254.169.254로 요청을 보내면 호스트 노드의 IMDS에 도달한다. SSRF든 RCE든 Pod 레벨 취약점 하나면 워커 노드의 IAM 역할을 통째로 탈취할 수 있다.

4.2 http-put-response-hop-limit — 다들 놓치는 설정

IMDSv2는 응답 패킷에 TTL 같은 개념인 hop limit을 둔다. 기본값은 플랫폼마다 다르다:

  • EC2 일반 인스턴스 기본: 1
  • EKS eksctl/관리형 노드그룹 기본: 2 (Pod에서 IMDS 접근 가능하도록)

즉 EKS는 “Pod가 IMDS에 접근할 수 있도록” 의도적으로 hop limit을 2로 올려놓는다. 편의성 때문이지만 공격자에게도 같은 경로가 열린다.

방어 옵션:

aws ec2 modify-instance-metadata-options \
  --instance-id i-xxxxx \
  --http-tokens required \
  --http-put-response-hop-limit 1 \
  --http-endpoint enabled

HttpTokens=required + HttpPutResponseHopLimit=1 두 개를 같이 설정해야 한다. Hop limit만 1로 하고 토큰을 optional로 두면 Pod가 IMDSv1을 그대로 쓸 수 있다.

4.3 그런데 hop limit=1로 하면 뭐가 깨지나

  • EBS CSI 드라이버: EC2 인스턴스 ID를 IMDS에서 가져오는 경우가 있음
  • AWS Load Balancer Controller: VPC ID 조회
  • 구버전 aws-node DaemonSet: 일부 경로에서 IMDS 의존

해결책은 노드 IAM 역할 → Pod IAM 역할 이전:

  • IRSA (IAM Roles for Service Accounts): OIDC 기반, 성숙한 패턴
  • EKS Pod Identity: 2023년 말 GA, 최근 권장. 단 Pod Identity Agent가 IMDS를 프록시하므로 hop limit을 2로 두어야 함 (Agent 1 hop + 컨테이너 1 hop)

4.4 hostNetwork: true 함정

Hop limit을 1로 걸어도 hostNetwork: true로 뜬 Pod는 호스트 네트워크 네임스페이스를 공유하므로 IMDS에 그대로 접근 가능하다. OPA/Gatekeeper 또는 Pod Security Standards의 restricted 프로파일로 hostNetwork를 막자.

# 이런 Pod는 여전히 IMDS 접근 가능 — 막아야 함
apiVersion: v1
kind: Pod
metadata:
  name: sneaky-imds-access
spec:
  hostNetwork: true   # ← 여기
  containers:
  - name: aws-cli
    image: amazon/aws-cli:latest

5. 실전 방어 체크리스트

CSP별로 “일단 이것만이라도” 수준의 최소한을 정리한다.

AWS

  • 리전 단위 IMDSv2-only 기본값 설정 (aws ec2 modify-instance-metadata-defaults --http-tokens required)
  • SCP로 ec2:RunInstancesec2:MetadataHttpTokens = "required" 조건 강제 (우회 방지)
  • MetadataNoToken CloudWatch 메트릭으로 IMDSv1 호출 잔존 여부 모니터링, 0 확인 후 MetadataNoTokenRejected로 전환
  • EKS 워커 노드는 Launch Template에서 http_tokens = "required", http_put_response_hop_limit 정책에 맞춰 설정
  • IRSA 또는 EKS Pod Identity로 노드 IAM 역할 의존 제거
  • GuardDuty CredentialAccess:IAMUser/InstanceCredentialExfiltration finding 모니터링

GCP

  • GKE에서 Workload Identity Federation for GKE 사용 (노드 기본 서비스 계정 의존 제거)
  • GKE Metadata Concealment는 deprecated — 여전히 쓰고 있다면 Workload Identity Federation으로 마이그레이션 (두 기능은 호환 불가)
  • 조직 정책으로 Compute Engine 기본 서비스 계정 자동 부여 비활성화 (iam.automaticIamGrantsForDefaultServiceAccounts)
  • VM의 access scope 의존 줄이고 서비스 계정 단위 IAM role 사용 (과거 access scope 기반 관행 탈피)
  • 애플리케이션이 Metadata-Flavor 헤더를 꼭 필요한 코드 경로에서만 호출하도록 통제 (SSRF 방어 기본 레이어가 이 헤더임)

Azure

  • Managed Identity(System/User-assigned) 사용
  • AKS에서 Workload Identity 전환 (kiam/aad-pod-identity 패턴은 deprecated)
  • NSG로 egress 169.254.169.254 제한이 필요하면 신중히 — Azure 내부 서비스 다수가 의존함

OCI

  • IMDSv2 강제, v1 비활성화 (InstanceOptions.areLegacyImdsEndpointsDisabled = true)
  • Instance Principal 사용 (IAM dynamic group)

Alibaba Cloud

  • ECS 인스턴스 메타데이터를 보안 강화 모드로 전환
  • ModifyImageAttribute로 AMI의 Features.ImdsSupport = v2 설정
  • 구버전 Alibaba Credentials SDK 업그레이드 (Java >= 0.3.10, Node.js >= 2.3.1 등)

공통 — 애플리케이션 레이어

  • 애플리케이션의 URL 파라미터/프록시 기능이 있다면 인그레스/이그레스에서 metadata IP 차단
  • WAF 룰에 169.254.169.254, 100.100.100.200, metadata.google.internal, metadata.tencentyun.com 패턴 추가
  • 리눅스 호스트의 iptables로 비인가 사용자의 metadata IP 접근 차단
# 예: root만 IMDS 접근 가능하도록
iptables -A OUTPUT -m owner --uid-owner root -d 169.254.169.254 -j ACCEPT
iptables -A OUTPUT -d 169.254.169.254 -j DROP

6. 정리 — 핵심 3가지

  1. 169.254.169.254는 AWS의 것이 아니라 관례다. 6개 메이저 CSP가 같은 IP를 쓰고, 알리바바만 100.100.100.200을 쓴다. 멀티 클라우드 환경에서 WAF/프록시/SSRF 필터 룰 쓸 때 전부 다 넣어야 한다.
  2. 인증 설계는 CSP마다 다르다. AWS/알리바바는 PUT 토큰, GCP/Azure는 고정 커스텀 헤더, OCI는 정적 Bearer. GCP는 과거 헤더가 필요 없는 레거시 엔드포인트(v0.1/v1beta1)가 있었지만 2020년에 셧다운되어 현재는 v1만 유효하다. SSRF 방어 효과가 가장 약한 건 여전히 IMDSv1을 허용하는 AWS/알리바바 구성과, 헤더 보호가 없는 DigitalOcean. 가장 보수적인 기본값은 IBM Cloud (기본 비활성).
  3. K8s 환경에서는 IMDSv2만으로 안 끝난다. hop limit 1 + hostNetwork: false 강제 + IRSA/Pod Identity/Workload Identity 삼종 세트가 실질적 방어선이다. “AWS는 IMDSv2 썼으니 안전”이라는 말은 EKS 운영자에게 거짓말이다.

Capital One이 $80M을 낸 지 7년이 지났다. SSRF는 여전히 현역이고, 공격자는 계속 이 패턴을 스캔하고 있다. 운영하는 모든 클라우드의 메타데이터 엔드포인트를 지금 점검하자 — 이 글 읽고 브라우저 닫기 전에.


참고 자료

profile
이군의 보안, 그리고 생각을 다룹니다.

0개의 댓글