- Published on
EKS IRSA에서 AssumeRoleWithWebIdentity 0s 타임아웃 해결
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
EKS에서 IRSA(IAM Roles for Service Accounts)를 붙인 파드가 AWS API를 호출할 때, 내부적으로는 STS의 AssumeRoleWithWebIdentity를 호출해 임시 자격 증명을 발급받습니다. 정상이라면 수십~수백 ms 내에 끝나지만, 현장에서는 로그에 AssumeRoleWithWebIdentity가 “0s timeout”처럼 보이며 즉시 실패하는 경우가 있습니다.
이 증상은 진짜로 0초 타임아웃이 걸렸다기보다, 대개 아래 중 하나로 인해 요청이 STS까지 도달하지 못했거나(네트워크/라우팅), TLS 핸드셰이크 전에 끊겼거나, 잘못된 엔드포인트/리전으로 즉시 실패하는 상황에서 자주 발생합니다.
이 글은 “권한(AccessDenied) 문제”가 아니라 연결/엔드포인트/환경변수/SDK 동작 관점에서, 빠르게 원인을 좁히고 확실하게 고치는 체크리스트를 제공합니다.
관련해서 파드에서 DNS는 되는데 HTTPS만 실패하는 네트워크 계열 이슈는 아래 글도 함께 보면 진단 속도가 빨라집니다.
증상 패턴 정리: “0s 타임아웃”이 의미하는 것
다음과 같은 로그/에러가 관찰됩니다.
- 애플리케이션 로그(예: boto3/botocore)
Connect timeout on endpoint URL: "https://sts.<region>.amazonaws.com/"Read timeout on endpoint URL...SSLError혹은EOF occurred in violation of protocol
- AWS SDK가 재시도를 거의 못 하고 즉시 실패(= 0초처럼 보임)
- 동일 파드에서 DNS 조회는 되는데
curl https://sts...가 실패 - 노드/서브넷/네임스페이스/특정 워크로드에서만 재현
핵심은 IRSA 자체(신뢰 정책, SA 어노테이션)가 맞아도 STS에 연결이 안 되면 AssumeRoleWithWebIdentity가 실패한다는 점입니다.
1) IRSA 구성 자체를 먼저 30초만에 확인(권한이 아니라 “연결 문제” 전제)
연결 문제를 파기 전에, IRSA가 정상 구성인지 최소 확인을 해두면 디버깅이 단순해집니다.
ServiceAccount 어노테이션
kubectl -n <ns> get sa <sa-name> -o yaml | yq '.metadata.annotations'
다음이 있어야 합니다.
eks.amazonaws.com/role-arn: arn:aws:iam::<account>:role/<role>
파드 환경 변수
IRSA가 적용된 파드에는 보통 아래가 주입됩니다.
AWS_ROLE_ARNAWS_WEB_IDENTITY_TOKEN_FILE
kubectl -n <ns> exec -it <pod> -- sh -lc 'env | egrep "AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE|AWS_REGION|AWS_DEFAULT_REGION"'
토큰 파일도 실제로 존재해야 합니다.
kubectl -n <ns> exec -it <pod> -- sh -lc 'ls -l $AWS_WEB_IDENTITY_TOKEN_FILE && head -c 20 $AWS_WEB_IDENTITY_TOKEN_FILE && echo'
여기까지가 정상인데도 “0s 타임아웃”이면, 거의 확실히 네트워크/엔드포인트 문제로 넘어갑니다.
2) STS 엔드포인트 연결성부터 확인: 파드에서 curl로 재현
파드에서 STS로 HTTPS 요청이 가능한지 확인합니다.
kubectl -n <ns> exec -it <pod> -- sh -lc '
apk add --no-cache curl 2>/dev/null || true
curl -sv --connect-timeout 3 https://sts.${AWS_REGION:-ap-northeast-2}.amazonaws.com/ 2>&1 | tail -n +1
'
결과 해석
Could not resolve host: DNS 문제Connection timed out: 라우팅/NACL/SecurityGroup/프록시/엔드포인트 문제SSL관련: MTU/프록시/TLS 중간장비/CA 번들 문제
특히 “DNS는 되는데 HTTPS만 실패”는 NAT, 라우팅 테이블, NACL, MTU(특히 1500/9001 혼재), VPC CNI SNAT에서 자주 터집니다. 이 케이스는 위 내부 링크 글의 체크리스트가 그대로 적용됩니다.
3) 가장 흔한 원인: 프라이빗 서브넷인데 NAT/STS VPC 엔드포인트가 없다
EKS 노드가 프라이빗 서브넷에 있고, 인터넷 egress가 NAT로 나가야 하는데 NAT가 없거나 라우팅이 깨지면 STS에 못 나갑니다.
확인 1: 노드가 있는 서브넷 라우팅
- 프라이빗 서브넷 라우팅 테이블에
0.0.0.0/0 -> nat-...가 있는지 - NAT Gateway가 실제로 같은 AZ에 있는지(교차 AZ도 되긴 하지만 비용/병목/장애 포인트)
확인 2: STS를 VPC 엔드포인트로 붙였는지
조직 정책상 인터넷 egress를 막는 경우, STS를 Interface VPC Endpoint(PrivateLink) 로 붙여야 합니다.
- 서비스:
com.amazonaws.<region>.sts - 타입: Interface
- 서브넷: 워커 노드가 있는 서브넷들
- 보안그룹: 노드/파드에서 443 인바운드 허용
- Private DNS: 활성화 권장
엔드포인트를 만들었다면, 파드에서 DNS가 STS를 사설 IP로 해석하는지 확인합니다.
kubectl -n <ns> exec -it <pod> -- sh -lc '
nslookup sts.${AWS_REGION:-ap-northeast-2}.amazonaws.com || true
'
사설 IP로 떨어지는데도 연결이 안 되면, 거의 항상 엔드포인트 SG/NACL 문제입니다.
4) “0s”처럼 보이게 만드는 SDK 설정: 프록시/리전/타임아웃
네트워크가 정상인데도 즉시 실패한다면, 애플리케이션 컨테이너의 환경변수/SDK 설정이 STS 호출을 망가뜨리는 경우가 있습니다.
(1) 잘못된 리전 또는 STS 엔드포인트 강제
IRSA는 기본적으로 STS 글로벌/리전 엔드포인트를 사용합니다. 그런데 다음이 섞이면 이상 증상이 납니다.
AWS_REGION,AWS_DEFAULT_REGION이 비어 있거나 엉뚱한 값AWS_STS_REGIONAL_ENDPOINTS=regional설정 + 리전 미설정- 커스텀
AWS_ENDPOINT_URL류를 STS에까지 적용
권장: 파드에 리전을 명시하거나, 노드의 IMDS/SDK가 올바르게 리전을 잡도록 합니다.
env:
- name: AWS_REGION
value: ap-northeast-2
- name: AWS_STS_REGIONAL_ENDPOINTS
value: regional
(2) HTTP(S)_PROXY가 STS까지 가로채는 경우
기업망/프록시 환경에서 HTTPS_PROXY가 설정되어 있으면, STS 호출이 프록시로 향했다가 즉시 끊기며 “0s”처럼 보일 수 있습니다.
파드에서 확인:
kubectl -n <ns> exec -it <pod> -- sh -lc 'env | egrep -i "https?_proxy|no_proxy"'
해결:
NO_PROXY에sts.<region>.amazonaws.com,.amazonaws.com,169.254.169.254등을 추가- 또는 해당 워크로드에서 프록시 환경변수를 제거
(3) SDK 타임아웃이 너무 공격적(0~수십 ms)
간혹 공통 라이브러리에서 AWS SDK 타임아웃을 극단적으로 줄여둔 경우가 있습니다.
Python(boto3/botocore) 예시
import boto3
from botocore.config import Config
cfg = Config(
connect_timeout=3,
read_timeout=10,
retries={"max_attempts": 5, "mode": "standard"},
)
sts = boto3.client("sts", config=cfg, region_name="ap-northeast-2")
print(sts.get_caller_identity())
Node.js(AWS SDK v3) 예시
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
const client = new STSClient({
region: process.env.AWS_REGION || "ap-northeast-2",
requestHandler: new NodeHttpHandler({
connectionTimeout: 3000,
socketTimeout: 10000,
}),
maxAttempts: 5,
});
const out = await client.send(new GetCallerIdentityCommand({}));
console.log(out);
타임아웃/재시도 설계 자체가 필요하다면, HTTP 클라이언트 관점의 재시도 패턴은 아래 글의 프레임을 그대로 가져와도 좋습니다.
5) MTU/경로 문제: TLS 핸드셰이크에서 끊기는 케이스
curl -v https://sts...에서 ClientHello 이후 멈추거나, SSL_ERROR_SYSCALL, EOF로 떨어지면 MTU/경로 문제를 의심합니다.
EKS에서 자주 나오는 패턴:
- 노드 ENI MTU(예: 9001) vs 경로상 장비/터널 MTU(예: 1500) 불일치
- 특정 서브넷/특정 AZ만 문제
- DNS/HTTP(작은 패킷)는 되지만 HTTPS/TLS(큰 패킷, fragmentation 필요)는 실패
이 경우는 원인과 해결이 네트워크 레이어에 있으므로, 아래 글의 “DNS OK, HTTPS Fail” 섹션대로 SNAT, NACL, MTU, 경로 MTU discovery를 집중 점검하는 것이 빠릅니다.
6) VPC 엔드포인트를 쓴다면: Endpoint SG/NACL/Private DNS 3종 세트
STS Interface Endpoint를 붙였는데도 타임아웃이면, 대부분 아래 중 하나입니다.
(1) Endpoint 보안그룹 인바운드 443 누락
Interface Endpoint는 ENI이므로 SG가 붙습니다. 파드/노드가 속한 SG(또는 CIDR)에서 443 인바운드 허용이 필요합니다.
- 인바운드: TCP 443 from node SG(권장) 또는 VPC CIDR
- 아웃바운드: 기본 허용이면 보통 OK
(2) NACL이 에페메럴 포트를 막음
NACL에서 아웃바운드 443만 열어두고, 응답 트래픽(에페메럴 포트)을 막아버리면 “연결 시도만 하다 타임아웃”이 납니다.
- 아웃바운드: 443 + ephemeral(1024-65535)
- 인바운드: ephemeral 허용
(3) Private DNS 미설정
Private DNS가 꺼져 있으면 sts.<region>.amazonaws.com이 퍼블릭으로 해석되어 NAT로 나가려다 실패할 수 있습니다.
7) 빠른 진단용 원라이너: 파드에서 STS 호출을 최소로 재현
앱 코드가 복잡하면, 파드 안에서 AWS CLI로 바로 재현하는 게 빠릅니다.
kubectl -n <ns> exec -it <pod> -- sh -lc '
aws --version || true
aws sts get-caller-identity --region ${AWS_REGION:-ap-northeast-2} --debug 2>&1 | tail -n 80
'
여기서 --debug 로그에
- 어떤 endpoint로 붙는지
- 프록시를 타는지
- connect/read timeout이 어디서 나는지
가 그대로 드러납니다.
8) “AccessDenied가 아닌데 STS가 안 된다”를 팀에 설명하는 포인트
IRSA 관련 이슈는 보통 IAM 정책부터 의심하지만, AssumeRoleWithWebIdentity는 STS 네트워크가 먼저입니다.
- IAM 신뢰 정책이 완벽해도 STS에 못 붙으면 실패
- 특히 프라이빗 클러스터/egress 제한/프록시 환경에서는 STS Interface Endpoint가 사실상 필수
- “0s timeout”은 SDK가 빨리 포기했다기보다 연결 자체가 성립하지 않는 환경일 가능성이 큼
결론: 해결 우선순위(가장 빨리 먹히는 순)
- 파드에서
curl -v https://sts.<region>.amazonaws.com로 연결성 확인 - 프라이빗 서브넷이면 NAT 라우팅 또는 STS Interface Endpoint 구성 확인
- Endpoint 사용 시 Endpoint SG 443 / NACL ephemeral / Private DNS 점검
- 파드의
HTTPS_PROXY/NO_PROXY,AWS_REGION,AWS_STS_REGIONAL_ENDPOINTS확인 - TLS 단계에서 끊기면 MTU/SNAT/NACL로 내려가서 원인 제거
위 순서대로 보면, “AssumeRoleWithWebIdentity 0s 타임아웃” 류는 대부분 1~2시간 내에 원인까지 도달합니다.