Published on

EKS Pod에서 STS 502 Bad Gateway 원인·해결

Authors

서버에서 AWS API를 호출하다가 502 Bad Gateway를 받으면 보통 애플리케이션 로직보다 중간 경로(게이트웨이/프록시/엔드포인트) 문제일 확률이 큽니다. EKS Pod에서 STS(AssumeRoleWithWebIdentity, GetCallerIdentity) 호출이 502로 터질 때도 마찬가지입니다. 특히 IRSA를 쓰는 워크로드는 Pod → (CoreDNS) → (VPC 라우팅) → NAT/프록시/VPC Endpoint → STS 경로 중 어디에서든 502가 만들어질 수 있습니다.

이 글은 “Pod에서 STS만 502가 난다”라는 상황을 기준으로, 가장 빨리 원인을 좁히는 진단 순서원인별 해결책을 정리합니다.

> 참고: 자격증명 자체를 못 찾는 문제(예: Unable to locate credentials)는 502가 아니라 4xx/SDK 에러로 나타나는 경우가 많습니다. 그 케이스는 EKS Pod에서 AWS SDK 자격증명 못찾음 해결 가이드도 함께 확인하세요.

1) 증상 패턴 정리: “STS만 502”가 의미하는 것

STS 502는 대체로 다음 패턴으로 나타납니다.

  • Pod 내부에서만 발생 (노드에서 curl은 되는데 Pod에서만 실패)
  • 특정 서브넷/노드그룹에서만 발생 (예: private subnet의 특정 AZ)
  • IRSA 토큰 교환 시점에만 발생 (AssumeRoleWithWebIdentity 호출)
  • 간헐적 (부하/스케일 시 더 자주)

중요한 포인트는 502가 AWS STS가 직접 반환했다기보다, 중간에 있는 구성요소(프록시, NAT 인스턴스, 방화벽, VPC Endpoint, L7 장비)가 “업스트림(STS)과 통신에 실패”하고 502를 만들어 반환하는 경우가 많다는 점입니다.

2) 가장 먼저 할 5분 진단: Pod에서 STS를 직접 때려보기

애플리케이션 로그만 보면 원인이 뭉개지기 쉬우니, 문제 Pod와 동일한 네임스페이스/SA/네트워크 조건에서 직접 STS 엔드포인트를 호출합니다.

2.1 디버그 Pod 실행

kubectl -n <ns> run sts-debug \
  --image=curlimages/curl:8.5.0 \
  --serviceaccount=<your-sa> \
  --command -- sleep 36000

kubectl -n <ns> exec -it sts-debug -- sh

2.2 DNS 확인

# CoreDNS가 반환하는지
nslookup sts.amazonaws.com
nslookup sts.<region>.amazonaws.com
  • 여기서 지연이 크거나 NXDOMAIN/timeout이면 DNS/CoreDNS/네트워크부터 봐야 합니다.

2.3 HTTPS 레벨 확인(curl)

# 리전 STS 권장(글로벌은 네트워크 정책/프록시에서 막히는 경우가 있음)
REGION=ap-northeast-2
curl -sv --connect-timeout 5 https://sts.${REGION}.amazonaws.com/ \
  -o /dev/null

관찰 포인트:

  • * Connected to ... 까지 가는지 (TCP 연결)
  • TLS handshake가 완료되는지
  • 응답 헤더에 server: AmazonS3 같은 이상한 값이 나오지 않는지(잘못된 프록시/리다이렉트)
  • 502가 curl에서도 재현되는지(애플리케이션/SDK 문제 vs 네트워크 문제 분리)

2.4 IRSA 토큰 기반 AssumeRoleWithWebIdentity 재현

IRSA라면 환경변수/토큰 파일이 있어야 합니다.

# IRSA 환경 확인
env | grep -E 'AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE|AWS_REGION|AWS_DEFAULT_REGION'
ls -al $AWS_WEB_IDENTITY_TOKEN_FILE
head -c 50 $AWS_WEB_IDENTITY_TOKEN_FILE && echo

AWS CLI가 없다면 설치가 번거로우니, 가능하면 amazon/aws-cli 이미지를 별도로 띄워 재현하는 편이 빠릅니다.

kubectl -n <ns> run awscli-debug \
  --image=amazon/aws-cli:2.15.0 \
  --serviceaccount=<your-sa> \
  --command -- sleep 36000

kubectl -n <ns> exec -it awscli-debug -- bash
REGION=ap-northeast-2
aws sts get-caller-identity --region $REGION --debug
  • --debug 로그에서 어떤 엔드포인트로 붙는지, 프록시를 타는지, 리트라이 후 어떤 에러로 끝나는지가 핵심 단서입니다.

3) 원인 1: 프록시(HTTP(S)_PROXY) 환경변수로 STS가 우회됨

EKS에서 기업망/보안 정책 때문에 Pod에 HTTP_PROXY/HTTPS_PROXY를 주입하는 경우가 많습니다. 이때 프록시가 STS 도메인에 대한 CONNECT를 제대로 처리하지 못하거나, TLS 검사(SSL inspection)로 인해 업스트림 연결이 깨지면 502가 흔하게 발생합니다.

3.1 확인 방법

env | grep -i proxy

또는 애플리케이션 Deployment/Helm values에서 프록시 env가 들어갔는지 확인합니다.

3.2 해결 방법: NO_PROXY에 STS 및 AWS 도메인 추가

  • 최소: sts.<region>.amazonaws.com, sts.amazonaws.com
  • 권장: AWS API 전반을 고려해 .amazonaws.com 또는 amazonaws.com 포함
  • VPC Endpoint를 쓴다면 해당 프라이빗 DNS 도메인도 고려

예시(Deployment 일부):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    spec:
      containers:
        - name: app
          image: your-image
          env:
            - name: HTTPS_PROXY
              value: http://proxy.corp.local:3128
            - name: HTTP_PROXY
              value: http://proxy.corp.local:3128
            - name: NO_PROXY
              value: ".cluster.local,.svc,localhost,127.0.0.1,amazonaws.com,.amazonaws.com,sts.ap-northeast-2.amazonaws.com"

프록시를 꼭 타야 한다면, 프록시 장비에서 CONNECT 허용 대상에 STS를 추가하거나 TLS 검사 예외로 설정해야 합니다.

Private subnet에서 인터넷 없이 STS를 쓰려고 com.amazonaws.<region>.sts Interface VPC Endpoint를 붙이는 경우가 있습니다. 이때 보통 다음 실수로 502/timeout/SSL 오류가 납니다.

  • 엔드포인트 SG 인바운드가 443을 허용하지 않음
  • 엔드포인트가 붙은 서브넷/AZ와 Pod의 라우팅이 꼬임
  • Private DNS 활성화/비활성화로 DNS가 의도와 다르게 해석
  • NACL이 443/에페메럴 포트를 막음

4.1 확인 체크리스트

  • VPC Endpoint: com.amazonaws.<region>.sts 존재 여부
  • Endpoint 상태: Available
  • Endpoint의 Security Group 인바운드: Pod/노드 CIDR에서 TCP 443 허용
  • Subnet NACL: 아웃바운드/인바운드 에페메럴(1024-65535) 허용
  • DNS: sts.<region>.amazonaws.com프라이빗 IP로 해석되는지

Pod에서 확인:

REGION=ap-northeast-2
nslookup sts.${REGION}.amazonaws.com
# 결과가 10.x/172.31.x 등 VPC 대역이면 엔드포인트 경유 가능성이 큼

4.2 해결 방법

  • Endpoint SG에 노드 SG 또는 Pod CIDR를 소스로 443 허용
  • Private DNS를 켰다면, 의도대로 STS가 엔드포인트로 가는지 확인
  • 멀티 AZ에서 특정 AZ만 문제면, 해당 AZ 서브넷에 엔드포인트 ENI가 정상 생성됐는지 점검

5) 원인 3: NAT 게이트웨이/라우팅/보안그룹/NACL 문제(인터넷 경유)

VPC Endpoint 없이 인터넷으로 STS를 호출한다면 경로는 보통:

Pod → 노드 → 라우팅 → NAT Gateway(Private subnet) → IGW → STS

여기서 502가 직접적으로 NAT에서 생성되진 않지만, 중간 방화벽/프록시/NAT 인스턴스가 있거나, 라우팅이 불안정하면 “업스트림 실패”가 502로 보일 수 있습니다.

5.1 빠른 분기: 같은 서브넷의 노드에서 재현되는가?

  • 노드에서 curl https://sts.<region>.amazonaws.com이 되는데 Pod만 안 되면 → CNI/네트워크 정책/DNS/프록시 쪽 가능성이 큼
  • 노드에서도 안 되면 → 서브넷 라우팅/NAT/방화벽 가능성이 큼

5.2 확인 포인트

  • Private subnet route table에 0.0.0.0/0 -> nat-xxxx가 있는지
  • NAT Gateway가 문제 AZ에 존재하고, 해당 AZ의 private subnet이 올바른 NAT로 라우팅되는지
  • NACL에서 443 및 에페메럴 포트를 막지 않는지

6) 원인 4: MTU/패킷 단편화 이슈로 TLS가 깨짐(간헐적 502/timeout)

EKS에서 MTU 이슈는 “작은 요청은 되는데 TLS 핸드셰이크/큰 패킷에서 깨짐” 형태로 나타나며, 결과적으로 SDK는 리트라이하다가 502/timeout처럼 보이는 오류를 뱉기도 합니다.

특히 다음 조합에서 자주 봅니다.

  • 온프레/타 VPC와의 터널링(VPN/Transit Gateway) 경유
  • 노드 AMI/커널/iptables 설정 변화
  • CNI 커스텀 MTU 설정

6.1 진단 아이디어

  • curl -v에서 Client hello 이후 멈추거나, SSL_ERROR_SYSCALL류가 보이면 의심
  • 경로 MTU 탐지(ping DF)는 컨테이너에서 제한될 수 있어 노드/디버그 권한이 필요할 수 있음

6.2 해결 방향

  • VPC CNI의 MTU 설정(AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG, MTU) 점검
  • 터널 경유 시 경로 MTU에 맞게 낮추기

네트워크 레벨에서 iptables 모드 충돌로 통신 자체가 불안정한 경우도 있으니, 노드 네트워크가 전반적으로 이상하다면 EKS iptables-legacy/nft 충돌로 네트워크 먹통 해결도 함께 확인하는 것을 권장합니다.

7) 원인 5: STS 엔드포인트 선택(글로벌 vs 리전) 문제

일부 환경(프록시/방화벽/정책 기반 라우팅)에서는 sts.amazonaws.com(글로벌)을 막고 sts.<region>.amazonaws.com만 허용하는 경우가 있습니다. SDK 기본값/설정에 따라 글로벌로 붙다가 실패할 수 있습니다.

7.1 해결 방법: 리전 STS로 강제

  • 애플리케이션에 AWS_REGION/AWS_DEFAULT_REGION 명시
  • SDK 설정에서 STS regional endpoints 사용

예: Java AWS SDK v2(환경 변수 기반도 가능)

import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sts.StsClient;

public class StsExample {
  public static void main(String[] args) {
    StsClient sts = StsClient.builder()
        .region(Region.AP_NORTHEAST_2)
        .build();

    System.out.println(sts.getCallerIdentity());
  }
}

예: Node.js(AWS SDK v3)

import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";

const client = new STSClient({ region: "ap-northeast-2" });
const res = await client.send(new GetCallerIdentityCommand({}));
console.log(res);

8) 원인 6: IRSA는 맞는데 “토큰 교환”만 실패하는 케이스

IRSA 설정이 대체로 맞더라도, 토큰 교환 요청이 STS까지 못 가면 502가 납니다. 여기서 자주 혼동하는 것이 “IRSA가 되는데 특정 AWS 서비스만 403” vs “STS 자체가 502”입니다.

  • STS 502: 네트워크/프록시/엔드포인트 경로 문제 가능성이 큼
  • STS는 되는데 DynamoDB 403: IAM 정책/조건(예: aws:PrincipalTag, kms:ViaService) 문제 가능성이 큼

후자의 케이스는 EKS Pod에서 IRSA는 되는데 DynamoDB 403 해결에서 다룬 방식(정책/조건/리소스 ARN 검증)으로 접근하는 게 맞습니다.

9) 운영 관점의 재발 방지 체크리스트

9.1 관측(Observability)

  • 애플리케이션에서 STS 호출 실패 시 endpoint, region, proxy env, dns result를 로그에 남기기
  • NAT Gateway/Firewall/Proxy의 5xx 지표를 대시보드화
  • CoreDNS latency/timeout 지표 확인

9.2 구성 표준화

  • EKS 워크로드에 프록시를 주입한다면 NO_PROXY 기본 템플릿에 amazonaws.com 포함
  • Private cluster라면 STS 포함 필수 AWS API에 대한 VPC Endpoint 목록을 표준으로 정의
  • 멀티 AZ라면 엔드포인트/라우팅/NAT를 AZ별로 대칭 구성

10) 요약: 가장 빠른 해결 루트

  1. Pod에서 curl -v https://sts.<region>.amazonaws.com네트워크/TLS 재현
  2. env | grep -i proxy로 프록시 강제 여부 확인 → NO_PROXY에 STS/AWS 도메인 추가
  3. VPC Endpoint를 쓴다면 Endpoint SG/NACL/Private DNS/DNS 해석 IP 확인
  4. 인터넷 경유라면 NAT/라우팅/AZ 대칭성 점검
  5. 간헐적이면 MTU/TLS inspection/중간 장비 로그까지 확대

위 순서대로 보면 “왜 STS에서만 502가 나는지”를 비교적 짧은 시간 안에 좁힐 수 있습니다.