只要立了网关就算拦住了吗
한국어 원문으로 표시합니다.
한 줄 요약
메시에서 나가는 트래픽은 기본값이 어디로든 통과(ALLOW_ANY)다. 그것을 좁히는 장치가 넷 있다 — 프록시가 알 범위를 줄이는 Sidecar 리소스, 모르는 곳을 막는 REGISTRY_ONLY, 바깥 목적지를 레지스트리에 올리는 ServiceEntry, 나가는 길을 한곳으로 모으는 이그레스 게이트웨이. 넷은 막는 것이 서로 다르고, 어느 하나도 혼자서 전부를 막지 못한다.
왜 이게 필요했나
사이드카는 기본으로 클러스터의 모든 서비스를 알고 있다. 서비스가 수천 개면 모든 프록시가 수천 개의 클러스터를 들고, istiod 는 서비스 하나가 바뀔 때마다 그것을 모두에게 민다. 그리고 레지스트리에 없는 목적지(외부 주소, 파드 IP)는 PassthroughCluster 로 그냥 흘려보낸다 — 누가 어디로 나가는지 메시가 모르는 채로.
보안 요구는 반대 방향이다. "결제 서비스만 카드사 API 로 나갈 수 있다", "바깥으로 나가는 길은 감사 가능한 한곳뿐이다" 같은 것들이다. 메시가 그 요구를 도우려면 먼저 바깥 목적지를 이름으로 알아야 하고, 그다음 나가는 지점을 하나로 모아야 한다.
어떻게 동작하나
Sidecar 리소스 — 이 네임스페이스의 프록시가 무엇을 알지 정한다.
egress:
- hosts: ["./*", "istio-system/*"] ← 같은 네임스페이스와 istio-system 만 안다
outboundTrafficPolicy:
mode: REGISTRY_ONLY ← 모르는 곳은 BlackHoleCluster(502)
범위를 줄이면 프록시 설정이 작아지고, REGISTRY_ONLY 를 더하면 범위 밖은 막힌다. 막힌 요청은 접근 로그에 라우트 이름 block_all 과 함께 502 로 남는다.
ServiceEntry — 바깥 목적지를 레지스트리에 올린다. location: MESH_EXTERNAL 은 '메시 밖이라 mTLS 를 걸지 말라' 는 뜻이고, resolution: DNS 는 엔드포인트 이름을 DNS 로 풀어 쓰라는 뜻이다. 그런데 호스트 이름 자체(api.partner.test)는 클러스터 DNS 에 없다. 사이드카의 DNS 프록시(ISTIO_META_DNS_CAPTURE)를 켜면 사이드카가 그 이름에 240.240.0.0/16 대역의 가상 IP 를 자동으로 할당해 답하고, 그 값은 ServiceEntry 의 status.addresses 에도 적힌다.
이그레스 게이트웨이 — 나가는 길을 한곳으로 모은다. VirtualService 하나가 두 구간을 맡는다.
| 구간 | 매치 | 보내는 곳 |
|---|---|---|
| 사이드카 → 게이트웨이 | gateways: [mesh] |
istio-egressgateway (mTLS) |
| 게이트웨이 → 바깥 | gateways: [partner-egress] |
진짜 목적지 |
사이드카에서 게이트웨이까지의 mTLS 는 저절로 걸리지 않는다. Gateway 서버를 HTTPS · tls.mode: ISTIO_MUTUAL 로 두고, 사이드카가 게이트웨이로 갈 때 쓸 DestinationRule 부분집합에 ISTIO_MUTUAL 과 sni 를 주어야 한다(공식 Egress Gateways with TLS Origination 문서가 같은 짝을 쓴다). 그 DestinationRule 은 클라이언트 네임스페이스 → 서비스 네임스페이스 → 루트 네임스페이스 순으로 찾으므로, 여러 네임스페이스가 같은 게이트웨이를 쓰게 하려면 게이트웨이 쪽(istio-system)에 둔다. 그렇게 mTLS 로 이어지면 게이트웨이는 보낸 워크로드의 신원을 안다. 그래서 인가 정책을 게이트웨이에 걸면 '누가 이 바깥으로 나갈 수 있는가' 를 한곳에서 정할 수 있다.
못 막는 것. Sidecar 와 REGISTRY_ONLY 는 그 네임스페이스 프록시의 설정일 뿐이다. 다른 네임스페이스의 프록시는 여전히 ALLOW_ANY 이고, 사이드카가 없는 파드는 아예 모른다. Istio 문서는 이그레스 게이트웨이만으로 모든 바깥 트래픽이 그곳을 지나게 강제할 수는 없으며, 쿠버네티스 네트워크 정책 같은 다른 장치로 게이트웨이 밖의 길을 막아야 한다고 밝힌다.
현장에서 만나는 모습
"REGISTRY_ONLY 를 켰더니 메트릭 수집이 끊겼습니다." 파드가 부르던 바깥 주소(모니터링 SaaS, 클라우드 메타데이터 등)가 레지스트리에 없었던 것이다. 켜기 전에 PassthroughCluster 로 나가는 요청을 접근 로그에서 먼저 세어 ServiceEntry 로 올려 두는 것이 순서다.
"이그레스 게이트웨이를 만들었는데 협력사 방화벽 로그에 파드 IP 가 찍힙니다." VirtualService 의 mesh 쪽 규칙이 없거나 호스트가 달라서 사이드카가 게이트웨이를 거치지 않고 바로 나간 경우다. 받는 쪽이 본 출발지가 가장 정직한 증거다.
"게이트웨이에서 막았는데 어떤 팀은 여전히 나갑니다." 그 팀 네임스페이스에는 Sidecar 설정이 없거나 사이드카 없는 파드였다. 게이트웨이는 지나간 요청만 막는다.
공식 문서: Accessing External Services · Egress Gateways · Sidecar · DNS Proxying
다음 실습에서 할 것
메시 밖에 협력사 API 역할의 nginx 를 두고, 기본값에서 어디로든 나가는 것을 먼저 센다. Sidecar 로 범위를 줄이고 REGISTRY_ONLY 로 막은 뒤 ServiceEntry 로 협력사만 올리고, 이그레스 게이트웨이로 길을 모아 협력사가 본 출발지로 확인한다. 마지막으로 다른 네임스페이스에서 게이트웨이를 우회하는 길이 남아 있는 것을 보고, 게이트웨이의 인가 정책으로 나갈 수 있는 신원을 좁힌다.