- Published on
EKS Pod STS AssumeRole 타임아웃 - NAT·PrivateLink·DNS
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버리스처럼 보이는 EKS Pod의 AssumeRole 타임아웃은 실제로는 매우 “네트워크적인” 장애인 경우가 많습니다. 특히 프라이빗 서브넷에 있는 워커 노드, NAT 게이트웨이 장애/미구성, STS PrivateLink(Interface VPC Endpoint) 도입 시 DNS/라우팅 꼬임, CoreDNS는 정상인데 특정 도메인만 간헐 실패 같은 상황이 겹치면, 애플리케이션 로그에는 그저 context deadline exceeded 혹은 i/o timeout 정도만 남고 원인 추적이 어려워집니다.
이 글에서는 EKS Pod에서 STS AssumeRole이 타임아웃될 때의 대표 원인을 (1) IRSA/인증 문제 vs (2) 네트워크 경로 문제로 먼저 분리하고, 그 다음 NAT / PrivateLink / DNS / 보안그룹 / NACL / 라우팅 관점에서 빠르게 좁혀가는 실전 진단 루틴을 제공합니다.
> 참고로, AccessDenied는 네트워크가 아니라 권한/신뢰정책 이슈일 확률이 높습니다. 이 케이스는 아래 글을 먼저 확인하는 편이 빠릅니다: EKS IRSA 설정했는데 STS AccessDenied 뜰 때
증상 패턴: “AssumeRole이 느리다/가끔 죽는다”가 의미하는 것
Pod에서 STS 호출이 타임아웃될 때 흔히 보이는 로그/에러는 다음과 같습니다.
- AWS SDK (Go/Java/Python 공통)
context deadline exceededdial tcp ...: i/o timeoutrequest canceled while waiting for connection
aws sts get-caller-identity도 간헐 실패- 특정 노드/특정 AZ에서만 재현
- 배포 직후(노드 스케일아웃 직후)만 재현
여기서 중요한 포인트는:
- 항상 실패면 라우팅/엔드포인트/보안그룹이 잘못된 경우가 많고,
- 간헐 실패면 DNS, NAT 포트 고갈, 특정 AZ의 NAT/엔드포인트 장애, 노드별 egress 차이(서브넷/라우트테이블) 가능성이 큽니다.
1단계: “IRSA 문제”와 “네트워크 문제”를 먼저 분리
IRSA가 정상인데 네트워크가 막히면 STS 호출 자체가 안 나가서 타임아웃이 납니다. 반대로 네트워크는 정상인데 IRSA가 깨지면 보통 타임아웃이 아니라 403/AccessDenied가 납니다.
Pod 안에서 가장 먼저 확인할 것 3가지
아래는 Pod 내부에서 실행하는 것을 권장합니다(디버그 컨테이너/ephemeral container 활용).
# 1) STS 엔드포인트 DNS 해석이 되는가?
nslookup sts.ap-northeast-2.amazonaws.com
# 2) TCP 연결이 되는가? (443)
# curl이 없다면 busybox/wget, 또는 openssl s_client 사용
curl -sv --connect-timeout 2 https://sts.ap-northeast-2.amazonaws.com/ >/dev/null
# 3) 실제 STS API 호출 (IRSA 사용 시)
aws sts get-caller-identity --region ap-northeast-2
nslookup이 실패하면 DNS/CoreDNS/VPC DNS 축 문제nslookup은 되는데curl이 timeout이면 라우팅/NAT/PrivateLink SG/NACL 문제curl은 되는데aws sts ...만 실패하면 IRSA/OIDC/토큰/시계오차 가능성(단, 이 글의 초점은 타임아웃이므로 네트워크 쪽을 더 의심)
IRSA 기본 점검 체크리스트가 필요하면 아래 글도 함께 보세요: EKS Pod에서 AWS SDK 자격증명 못찾음 해결 가이드
2단계: NAT 경로 문제 — “프라이빗 서브넷인데 NAT가 없다/죽었다”
가장 흔한 구조는:
- EKS 노드가 Private Subnet
- STS는 기본적으로 Public AWS Endpoint
- 따라서 Pod egress는 NAT Gateway 또는 STS PrivateLink가 필요
NAT 미구성/라우팅 오류의 전형적인 징후
curl https://sts...가 timeout- 같은 클러스터라도 Public Subnet 노드에서는 성공
- 특정 AZ의 노드만 실패(해당 AZ NAT 라우트가 빠졌거나 NAT 장애)
확인 포인트
노드가 속한 서브넷의 라우트 테이블에서
0.0.0.0/0 -> nat-xxxx존재 여부NAT Gateway 상태(
Available) 및 AZ 매핑NAT로 나가는 보안 정책
- NACL에서 ephemeral port(1024-65535) 아웃바운드/인바운드 허용 여부
- 노드 SG egress가 443을 막고 있지 않은지
NAT 포트 고갈(간헐 타임아웃)의 가능성
트래픽이 많은 워크로드(대량 외부 API 호출, 대량 STS 호출, 짧은 커넥션 반복)가 있으면 NAT의 SNAT 포트가 고갈되어 간헐적인 연결 지연/실패가 나타날 수 있습니다.
실무에서의 완화책:
- STS 호출을 과도하게 반복하지 않도록 SDK 캐시/자격증명 리프레시 주기 확인
- NAT Gateway를 AZ별로 두고 서브넷 라우팅을 분산
- 필요 시 egress 전용 VPC/프록시 도입
- 가능하면 STS를 PrivateLink로 전환(다만 아래의 DNS/엔드포인트 설계가 중요)
3단계: STS PrivateLink(Interface VPC Endpoint) — “있는데도 타임아웃”
STS를 PrivateLink로 붙이면 NAT 없이도 STS를 프라이빗하게 호출할 수 있습니다. 하지만 설정이 어긋나면 오히려 DNS는 되는데 연결이 안 되는 상태가 만들어집니다.
PrivateLink에서 자주 터지는 포인트
1) VPC Endpoint의 Security Group 인바운드 누락
Interface Endpoint는 ENI로 붙고, Endpoint SG가 443 인바운드를 허용해야 합니다.
- 소스: 워커 노드 SG 또는 Pod ENI SG(보안그룹 for pods 사용 시)
- 대상: STS VPC Endpoint SG
- 포트: TCP 443
2) Endpoint가 생성된 서브넷/AZ와 노드의 AZ 불일치
Interface Endpoint는 “서브넷 단위”로 ENI가 생성됩니다.
- 노드가 있는 AZ의 서브넷에 Endpoint ENI가 없으면, 트래픽이 다른 AZ로 가며 지연/실패가 날 수 있습니다.
- 베스트 프랙티스: 클러스터 노드가 존재하는 모든 AZ에 Endpoint를 배치
3) Private DNS 설정과 DNS 해석 경로
STS Endpoint를 만들 때 Private DNS를 활성화하면 sts.<region>.amazonaws.com이 VPC 내부에서 Endpoint의 프라이빗 IP로 해석됩니다.
- Private DNS를 켰는데도 Public IP로 해석된다면:
- VPC의
enableDnsHostnames,enableDnsSupport확인 - CoreDNS가 VPC DNS로 포워딩하는지 확인
- VPC의
다만, CoreDNS는 정상인데 DNS가 간헐 실패하는 케이스도 실제로 많습니다. 이 경우는 아래 글의 체크리스트가 그대로 도움이 됩니다: EKS에서 CoreDNS 정상인데 DNS가 간헐 실패할 때
Pod에서 “PrivateLink로 붙었는지” 확인하는 법
# STS 도메인이 어떤 IP로 해석되는지 확인
getent hosts sts.ap-northeast-2.amazonaws.com
# 해석된 IP로 443 연결이 되는지 확인
# (IP가 10.x/172.16-31/192.168 대역이면 PrivateLink일 가능성이 큼)
IP=$(getent hosts sts.ap-northeast-2.amazonaws.com | awk '{print $1}' | head -n1)
curl -sv --connect-timeout 2 https://$IP/ -H 'Host: sts.ap-northeast-2.amazonaws.com' >/dev/null
- PrivateLink를 쓰는 경우 SNI/Host 헤더가 중요할 수 있어 위처럼
Host를 명시하면 진단에 도움이 됩니다.
4단계: DNS 문제 — “AssumeRole timeout처럼 보이는 DNS 지연/실패”
STS 호출은 보통 다음 순서로 진행됩니다.
sts.<region>.amazonaws.comDNS 쿼리- TCP/TLS 핸드셰이크
- API 요청
이 중 1번이 간헐적으로 느려지면 애플리케이션은 STS 자체가 느린 것처럼 보입니다.
Pod에서 DNS 지연을 수치로 확인
# dig가 없다면 dnsutils 설치된 디버그 파드 사용 권장
# 예: kubectl run -it --rm dns --image=registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3 -- bash
dig +tries=1 +time=1 sts.ap-northeast-2.amazonaws.com
dig +tries=1 +time=1 sts.ap-northeast-2.amazonaws.com @kube-dns.kube-system.svc.cluster.local
추가로 확인할 것:
- CoreDNS 로그에서
SERVFAIL,timeout빈도 - NodeLocal DNSCache 사용 여부(있다면 상태/메트릭)
- VPC Resolver(169.254.169.253)로의 네트워크 경로
5단계: “특정 노드에서만” 타임아웃 — 서브넷/라우트/보안그룹 편차
EKS에서 STS 타임아웃이 특정 노드에서만 발생하면 거의 항상 다음 중 하나입니다.
- 노드가 붙은 서브넷의 라우트 테이블이 다른 노드와 다름
- 특정 AZ에만 NAT/Endpoint가 없거나 장애
- 보안그룹 for pods(ENI trunking) 사용 시 Pod SG가 egress를 막음
- NACL이 특정 서브넷에서만 더 엄격함
노드별로 재현을 고정시키는 방법
# 문제가 의심되는 노드에만 파드를 띄워 테스트
kubectl run sts-test \
--image=amazon/aws-cli:2.15.0 \
--restart=Never \
--overrides='{
"spec": {
"nodeSelector": {"kubernetes.io/hostname": "ip-10-0-12-34.ap-northeast-2.compute.internal"},
"containers": [{
"name": "aws",
"image": "amazon/aws-cli:2.15.0",
"command": ["sh","-lc"],
"args": ["for i in $(seq 1 20); do date; aws sts get-caller-identity --region ap-northeast-2 || true; sleep 1; done"]
}]
}
}'
이렇게 노드를 고정하면 “클러스터는 되는데 일부 노드만 안 됨”을 빠르게 증명할 수 있고, 네트워크 팀/클라우드 팀과 협업할 때도 근거가 명확해집니다.
6단계: 애플리케이션/SDK 관점의 타임아웃 튜닝(원인 규명 후 보완)
네트워크 원인을 해결하는 게 우선이지만, 운영 안정성을 위해 SDK 타임아웃/재시도 정책도 함께 보완하는 것이 좋습니다.
(예시) Python boto3에서 STS 타임아웃/재시도 설정
import boto3
from botocore.config import Config
config = Config(
connect_timeout=2,
read_timeout=5,
retries={"max_attempts": 5, "mode": "standard"},
)
sts = boto3.client("sts", region_name="ap-northeast-2", config=config)
print(sts.get_caller_identity())
- 타임아웃을 무작정 크게 하면 장애 감지가 늦어지고, HPA/KEDA 스케일링이나 워커 스레드 점유로 2차 장애가 날 수 있습니다.
- 반대로 너무 작으면 일시적인 DNS 지연에도 실패가 늘어납니다.
실전 체크리스트 요약(원인별 “가장 잘 먹히는” 확인)
NAT 문제 의심
- 프라이빗 서브넷 + STS Public Endpoint 사용
curl https://sts...timeout- 특정 AZ에서만 재현
확인: 라우트테이블 0.0.0.0/0 -> NAT, NAT 상태, NACL ephemeral port
PrivateLink 문제 의심
- STS Interface Endpoint 생성 후부터 장애
- DNS는 프라이빗 IP로 해석되는데 연결 timeout
확인: Endpoint SG 443 인바운드, 모든 AZ에 Endpoint ENI 존재, Private DNS/VPC DNS 설정
DNS 문제 의심
- 간헐 실패 + 재시도하면 성공
- STS뿐 아니라 외부 도메인도 가끔 느림
확인: dig 지연, CoreDNS/NodeLocal DNSCache, VPC Resolver 경로
마무리: “AssumeRole timeout”은 대개 STS가 아니라 네트워크다
EKS에서 STS AssumeRole 타임아웃은 IRSA를 먼저 떠올리기 쉽지만, 실제로는 (1) NAT 경로, (2) STS PrivateLink 설계/보안그룹, (3) DNS 안정성이 원인인 경우가 매우 많습니다.
가장 빠른 접근은 다음 순서입니다.
- Pod 내부에서
nslookup -> curl -> aws sts로 레이어를 분리 - 노드 고정 배포로 “특정 노드/AZ만” 여부를 확정
- NAT 또는 PrivateLink 중 현재 설계에 맞는 경로를 끝까지 점검
- 간헐 장애면 DNS와 NAT 포트 고갈까지 의심
이 루틴으로 보면, 로그에 context deadline exceeded만 남는 난감한 케이스도 보통 30~60분 안에 네트워크 레벨 원인을 특정할 수 있습니다.