요즘 회사에서 AKS 운영을 하다 보면, 장애의 많은 부분이 결국 네트워크/방화벽으로 모입니다.
특히 “나가는 트래픽(Outbound)”은 서비스 내부 코드가 멀쩡해도, 보안 정책 한 줄 때문에 갑자기 Connection reset by peer로 터지기도 하죠.

문제는 여기서부터예요.

  • 개발자는 “쿠버네티스가 뭔가 잘못된 거 아니냐”
  • 보안/네트워크는 “우리 방화벽은 문제 없다(로그 없다)”
  • 운영자는 “어딘가에서 끊기는 건 확실한데… 어디지?”

이 글은 딱 그 고민을 담아서, “방화벽 이슈 같다” → “증거 기반으로 레이어를 분해” → “해결 경로(누구에게 무엇을 요청할지)까지 정리한 기록입니다.

⚠️ 보안상 도메인/리소스/구독ID/IP 등은 일부 마스킹하거나 샘플로 치환해서 작성하는 걸 권장합니다. (아래 예시는 실제 운영에서 사용한 커맨드 흐름을 그대로 둔 형태입니다.)

 

1) 배경: 우리 환경은 ‘방화벽 경유’가 기본 전제였다

우리 AKS는 겉으로는 outboundType=loadBalancer로 보이지만, 실제 데이터 플레인에서는 UDR(0.0.0.0/0)로 NVA(=Azure Firewall) 강제 경유를 하고 있습니다.

즉, 설계 의도는 다음과 같아요.

Pod/Node → (UDR: 0.0.0.0/0) → Azure Firewall/NVA → Internet

 

AKS의 outboundType 자체는 egress 동작에 영향을 주는 설정이고 공식 문서에 정리되어 있습니다.
다만 현실 운영에서는 “AKS 설정”뿐 아니라 서브넷 UDR이 실제 경로를 결정하므로, 최종적으로는 방화벽을 통과해야 외부로 나갈 수 있는 구조가 됩니다(= forced tunneling 패턴).

이 구조는 보안 관점에선 합리적이지만, 운영자 입장에서는 문제가 생길 때 항상 이런 질문으로 돌아옵니다.

“이게 방화벽 정책 문제야? 아니면 AKS/앱 문제야?”

 

2) 증상: “어떤 사이트는 되고, 어떤 곳은 TLS에서 끊긴다”

장애가 단순히 “인터넷이 안 된다”면 오히려 쉬워요.
진짜 어려운 건 이런 케이스입니다.

  • 어떤 사이트는 정상 접속 (HTTP 200)
  • 어떤 사이트는 TLS handshake 중간에 reset
  • 내부에서는 “방화벽이 막았나?” 라고 의심하지만, 보안팀은 “차단 로그 없다”라고 함

이때 제일 위험한 상태는 각 팀이 자기 관점으로만 말하면서 결론이 안 나는 상태예요.
그래서 저는 접근을 바꿨습니다.

“감으로 추측하지 말고, curl -v 로그로 끊기는 지점을 고정시키자.”

3) 해결 접근: curl -v로 레이어를 분해해서 ‘어디서 끊기는지’ 확정하기

TLS 문제는 복잡해 보여도, 사실 로그를 레이어로 쪼개면 단순해집니다.

3.1 우리가 확인한 “정상 케이스” ① (조선닷컴: TLS 1.3 + HTTP/2 성공)

curl -4 -sv --resolve www.chosun.com:443:23.205.106.145 https://www.chosun.com/ -o /dev/null
...
* Connected to www.chosun.com (23.205.106.145) port 443
* TLSv1.3 ... Client hello
* TLSv1.3 ... Server hello
* TLSv1.3 ... Certificate
* TLSv1.3 ... Finished
* ALPN: server accepted h2
< HTTP/2 200

여기서 얻는 결론은 명확합니다.

  • TCP 연결 OK
  • TLS handshake 완주(= 방화벽이 “TLS 자체”를 일괄로 막는 구조는 아님)
  • HTTP 레이어까지 정상

3.2 “정상 케이스” ② (동아 닷컴: TLS 1.2 + HTTP/1.1 성공)

curl -4 -sv https://www.donga.com/ -o /dev/null
...
* SSL connection using TLSv1.2 ...
< HTTP/1.1 200 OK

이것도 결론은 동일합니다.

  • 외부 HTTPS 자체가 안 되는 상황이 아님
  • 특정 대상/패턴에서만 끊기는 “선택적 문제”일 가능성이 커짐

4) 결정타: “우리 출구 IP가 뭐냐?”를 파드에서 확정

네트워크 논쟁에서 가장 빨리 합의되는 증거는 출구 IP입니다.

kubectl run -it --rm netshoot --image=nicolaka/netshoot -- /bin/bash
curl -s https://api.ipify.org; echo
# 172.X.X.X

이 한 줄이 의미하는 바는 큽니다.

  • “우리 egress는 실제로 방화벽(NVA) SNAT 공인 IP로 나가고 있다”는 강한 근거
  • 보안/네트워크팀과 대화할 때 ‘어느 방화벽 정책/로그를 봐야 하는지’ 범위를 좁혀줌
  • 외부 SaaS/API allowlist 요청 시에도 바로 쓸 수 있는 값

5) 그래서 결론: “방화벽 이슈 같다”가 아니라, “방화벽에서 어디를 봐야 한다”로 바꾸기

여기서부터가 ‘해결’입니다.

5.1 흔히 만나는 실패 패턴 3가지

운영 경험상 방화벽/프록시 환경에서 자주 나오는 실패 패턴은 다음 중 하나로 귀결돼요.

  1. TCP 자체가 안 붙음
    • timeout / connect fail
      → 라우팅/NSG/경로/방화벽 네트워크 규칙 레벨
  2. TLS ClientHello까지만 찍히고 reset
    • Connection reset by peer
      → 방화벽 차단, TLS inspection, SNI/카테고리 정책, 특정 CDN 대역 차단 가능성
  3. TLS는 끝났는데(verify ok) HTTP에서 막힘
    • 403/451 등
      → L7 정책, 원격 서비스 차단, 봇 차단/WAF 성격

우리 케이스는 “정상도 있음”이 확인됐기 때문에, 2번(선택적 TLS 단계 reset) 가능성이 현실적으로 큽니다.

6) 내가 지금 고민하는 해결 방향(= 블로그에 남기고 싶은 운영자의 현실)

솔직히 회사 방화벽 이슈는 기술만으로는 끝나지 않아요.
결국 협업 프로세스가 없으면 똑같은 문제가 반복됩니다.

그래서 지금 제 고민은 이거예요.

  • “장애가 날 때마다 방화벽팀에 ‘안 돼요’라고만 말하면 또 시간 끌린다.”
  • “그럼 우리가 먼저 ‘증거 패키지’를 만들어서, 방화벽팀이 바로 정책/로그를 확인할 수 있게 해야 한다.”
  • “그리고 이걸 운영 표준(체크리스트)로 만들면 다음 장애는 훨씬 빨리 끝날 것이다.”

즉, 해결은 기술적 해결 + 운영 표준화가 같이 가야 합니다.

7) 실전 대응: 방화벽팀에 바로 넘길 “증거 패키지” 템플릿

아래 4가지만 모으면, “추측”이 아니라 “조사 가능한 티켓”이 됩니다.

(1) 실패한 curl 로그 (전체 말고, handshake 구간 중심)

curl -4 -sv https://<target-host>/ -o /dev/null

(2) 성공한 비교 대상 로그(같은 파드/같은 시간대)

curl -4 -sv https://www.donga.com/ -o /dev/null

(3) 파드 기준 출구 IP

curl -s https://api.ipify.org; echo
# 172.X.X.X

(4) 시간대 + 대상 FQDN/IP (가능하면 --resolve로 특정 IP 고정 테스트까지)

curl -4 -sv --resolve <host>:443:<ip> https://<host>/ -o /dev/null

이렇게 주면 방화벽팀은 보통

  • 해당 시간대에 SNAT IP(172.X.X.X)로 나간 세션 로그
  • 목적지 FQDN/IP 기반 정책 매칭 결과
  • TLS inspection 적용 여부
  • 카테고리/URL 필터 적용 여부

를 훨씬 빠르게 볼 수 있어요.

 

 

마무리

이번 글에서 하고 싶었던 얘기는 하나입니다.

“방화벽 이슈 같아요”에서 멈추면 해결이 늦어집니다.
‘어느 레이어에서 끊겼는지’를 증거로 쪼개면, 해결은 빨라지고 재발은 줄어듭니다.