3W - 서비스 엔트리와 이그레스 게이트웨이

개요

트래픽 관리의 마지막 내용으로 외부로 나가는 트래픽을 관리해본다.
일단 서비스 메시 외부로 나가는 트래픽을 전부 차단한 다음, 서비스 엔트리 리소스를 이용해 특정 주소로 통신이 가능하게 만든다.
이후에는 이 아웃바운드 트래픽을 조금 더 통합적으로 관리할 수 있도록 이그레스 게이트웨이를 사용한다.

사전 지식

아웃바운드 트래픽

초기 서비스에서 아웃바운드, 내부에서 외부로 나가는 트래픽을 자유롭게 열어두는 경우가 많다.
그러나 임의의 공격자가 내부로 침투한 상황에서 함부로 정보를 바깥으로 유출하는 것을 막는 것도 공격 표면을 줄이는 하나의 보안 조치이다.
이스티오에서도 이런 기능을 제공하며, 제한적으로 특정 주소에 대한 아웃바운드만 허용하도록 세팅하는 것이 가능하다.

Service Entry

서비스 메시 내의 구성원은 서비스 레지스트리를 통해 서로의 주소를 파악하고 관리한다.
이스티오는 컨트롤 플레인이 이 서비스 레지스트리를 관리하며 각 프록시에게 필요한 주소의 정보를 알려준다.
그런데 여기에서 문제가 발생하는 것이 하나 있다.
서비스 메시 외부의 주소에 통신하기 위해서 어떻게 해야 하는가?
이때 외부 주소를 서비스 레지스트리에 등록하기 위해, 서비스 진입점을 만드는 리소스가 바로 ServiceEntry이다.[1]
이 리소스를 만들면, Gateway나 VirtualService에서 해당 주소에 대해 여러 설정을 할 수 있게 된다.

ServiceEntry 양식 작성법

apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: httpbin-ext
spec:
  hosts:
  - httpbin.org
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  location: MESH_EXTERNAL

어떤 식으로 작성하는지 간단하게 설명한 후에 기능들을 살펴보겠다.
일단 hostsports 필드를 통해 어떤 호스트, 포트를 진입점으로 등록할 것인지 명시한다.

  addresses:
  - 192.192.192.192/24
  endpoints:
  - address: us.foo.bar.com
    ports:
      http: 8080

addresses 필드는 이 진입점으로 들어오기 위한 IP 대역을 나타낸다.
가상 IP라고 보면 되겠다.
endpoints는 실제 트래픽을 보내야할 엔드포인트를 나타낸다.
이 필드가 있으면 기본적으로 서비스 엔트리가 등록될 때 hosts 필드를 이용해 DNS 쿼리를 날리지 않고, 이 주소를 사용한다.

location 필드에는 두 가지 값이 가능하다.

resolution 필드는 프록시가 IP 주소를 알아내어 어떻게 라우팅할지를 지정한다.

이그레스 게이트웨이

서비스 엔트리를 배치하면 서비스 메시의 엔보이들은 해당 주소에 대해 제대로 트래픽을 보낼 수 있게 된다.
그러나 이것만으로는 충분치 않은 사용 케이스가 있을 수 있다!
단순 서비스 엔트리를 등록하는 방식은 외부로 가는 트래픽을 제대로 추적 관리하기가 힘들다는 것이다.
물론 이미 한 차례 특정한 호스트에 대해서만 트래픽을 보낼 수 있도록 하는 것도 훌륭한 보안이다.
그러나 외부로 향하는 트래픽이 위험할 수 있기에 제한을 한다면, 아예 외부로 나가는 지점을 하나로 줄여서 관리하는 것도 꽤나 도움이 될 것이다.
이럴 때 사용하는 것이 바로 이그레스 게이트웨이이다.

구체적으로 이그레스 게이트웨이는 다음의 상황에서도 유용하다.

실습 진행

이그레스 게이트웨이에 대해서는 자세히 설명하지 않겠다.
사실 그냥 저번 주차에 공부한 인그레스 게이트웨이의 역방향일 뿐이다.

아웃바운드 트래픽 세팅 확인

keti debug -- curl naver.com 

image.png
기본 이스티오 설정에서는 서비스 메시 아웃바운드 트래픽은 열려 있다.
실제로 이런 요청은 클러스터 중 PassthroughCluster를 통해 나간다.[2]
이 클러스터는 가상 클러스터로서 등록된 클러스터가 아닌 주소로 가는 요청이 기본으로 빠지게 되는 라우팅 테이블의 게이트웨이라고 생각하면 되겠다.
image.png
모든 엔보이의 클러스터 설정을 보면 이 클러스터가 있는 것을 볼 수 있다.
image.png
그리고 엔보이의 리스너 필드를 보면 0.0.0.0에 대해서 패스스루 클러스터를 타는 것을 볼 수 있다.
몇몇 개는 특정 조건을 만족할 시 라우트를 타는데, 대체로 메트릭이나 컨트롤플레인과의 통신과 연관된다.
image.png
몇 번 외부 호출을 해보면 키알리로도 이렇게 패스스루 클러스터를 통해 나간다는 것을 확인할 수 있다.
image.png
BlackHoleCluster라는 것도 있는데, 이것 역시 가상의 클러스터로 패스스루 클러스터와 정 반대로 모든 트래픽을 막아버리는 클러스터이다.

아웃바운드 트래픽 제한

그럼 이제 외부로 가는 통신을 막아버리자!

  meshConfig:
    outboundTrafficPolicy:
      mode: REGISTRY_ONLY

메시 전역적으로 막는 방법은 쉽다.
이스티오 설정 파일에 아웃바운드 트래픽 정책이 원래는 ALLOW_ANY로 돼있는데, 이걸 REGISTRY_ONLY로 바꿔주면 된다.
image.png
이걸 설정하자마자 엔보이들의 리스너 설정을 보면 그 많던 패스스루들이 사라진 것을 볼 수 있다!
대신 그 자리엔 Non-HTTP/Non-TCP라는 것들이 남아있다.
image.png
json 양식으로 조금 더 뜯어보면 명확하게 보이는데, 아예 블랙홀 클러스터로 가라고 표시되는 것이 보인다.
image.png
요청을 외부로 다시 보내보면, 이번에는 502 에러를 반환한다.

서비스엔트리 활용

그럼 이제 특정한 외부 호스트에 대해서만 요청이 가능하도록 뚫어주는 작업을 해본다.
여태 클러스터에 등록되지 않은 모든 요청이 블랙홀 클러스터로 빠져버렸으므로, 아예 클러스터로 특정 주소를 등록해야만 통신이 가능하게 된다!

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: jsonplaceholder
spec:
  hosts:
  - jsonplaceholder.typicode.com
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  location: MESH_EXTERNAL

image.png
서비스 엔트리 리소스를 만들어 메시 외부의 주소를 서비스 레지스트리에 등록한다.
이 호스트는 책 예제에서 사용하는 호스트로, 가짜 게시판 api서버처럼 동작하면서 응답을 리턴해준다.
image.png
클러스터 내 엔드포인트가 아니니 EDS에는 아무런 영향이 없었으나, CDS, RDS, LDS에 설정이 들어가는 것을 확인할 수 있다.
image.png
클러스터 설정을 보면 위와 같이 STRICT DNS 타입으로 클러스터가 생성됐다.
라우트 쪽도 보면 똑같이 세팅된 게 있는데, 이제 너무 반복적인 것 같아서 자세한 보기는 생략한다.

kubectl apply -f services/forum/kubernetes/forum-all.yaml -n istioinaction

책 예제로 포럼이라는 워크로드도 있는데, 여기에서 위의 가짜 api 서버로 데이터를 받아온다.

WEBAPP="webapp.istioinaction.io"
while true; do curl -s "http://$WEBAPP:30000/api/users" -I --resolve "$WEBAPP:30000:127.0.0.1" | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done

image.png
이렇게 반복 접근을 걸어서 또 키알리로 확인해보면 jsonplaceholder라는 서비스 엔트리로 요청이 전달되는 것을 볼 수 있다!
image.png
요청이 가고 나서 엔드포인트 설정을 보면 아예 ip주소가 레지스트리에 추가된 것을 알 수 있다.

이그레스 게이트웨이 배치

지금은 단순하게 외부의 주소를 레지스트리에 등록하는 방식을 사용했다.
키알리를 봐도 알 수 있듯이, 이 방식에서는 트래픽을 제대로 모니터링하기는 어렵다.
그래서 이번엔 이그레스 게이트웨이를 배치해보자.

    egressGateways:
    - name: istio-egressgateway
      enabled: true

이것도 설정하는 법은 간단하다.
그냥 이스티오 설정 양식에 인그레스 게이트웨이 만들었듯이 딸깍 이그레스 게이트웨이 만들어주면 된다.

apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: egress-gateway
spec:
  selector:
    istio: egressgateway
  servers:
    - hosts:
        - jsonplaceholder.typicode.com
      port:
        name: http
        number: 80
        protocol: HTTP

게이트웨이 리소스를 만드는 것도 일단 똑같다.
서비스 엔트리로 등록한 클러스터는 이 게이트웨이가 처리하겠다, 하고 등록해준다.
설정하는 방법도 그냥 인그레스 게이트웨이 쓸 때와 다를 게 없다.
일단 서비스 메시에 게이트웨이 리소스를 등록한다.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: vs-egress
  namespace: istioinaction
spec:
  gateways:
    - egress-gateway
    - mesh
  hosts:
    - jsonplaceholder.typicode.com
  http:
    - name: for-mesh
      match:
        - gateways:
            - mesh
          port: 80
      route:
        - destination:
            host: istio-egressgateway.istio-system.svc.cluster.local
            port:
              number: 80
    - name: for-gateway
      match:
        - gateways:
            - egress-gateway
          port: 80
      route:
        - destination:
            host: jsonplaceholder.typicode.com
            port:
              number: 80

버츄얼 서비스를 만들 때 조금 까다로울 수 있는데, 위와 같이 만들어준다.
두 설정이 있는데 이 두 개는 사실 쪼개서 써도 상관은 없다.
먼저 mesh 내에서 해당 호스트로 가는 요청은 이그레스 게이트웨이 워크로드로 가야한다고 명시해준다.
그리고 게이트웨이에 대해서는 들어온 요청이 외부의 jsonplaceholder 주소로 가야 한다고 명시한다.
그럼 mesh에서 외부 주소로의 요청은 이그레스 게이트웨이로, 그리고 이그레스 게이트웨이에서는 해당 외부 주소로 트래픽을 보낼 것이다.
image.png
그럼 아까 봤던 서비스 엔트리 리소스는 안 보이고 이그레스 게이트웨이를 통해 트래픽이 나가게 된다.
그림을 딱 봐도 알겠지만, 아까와 다르게 이번에는 트래픽에 대한 메트릭 정보를 볼 수 있다!
image.png
이제 나가려는 트래픽에 대해 이그레스 게이트웨이에서 메트릭을 추적할 수도 있게 됐다.
이그레스 게이트웨이에 로깅 설정도 넣어주면 구체적으로 어떤 트래픽이 나가고 있는지도 확인할 수 있게 될 것이다.

결론

생각보다 이그레스 게이트웨이를 설정하는 과정은 쉬운 듯 하면서도 번거로웠다.
메시 내부의 트래픽이 이그레스를 타기 위해서는 다음의 과정이 필요하다.

이런 번거로움이 있긴 하지만, 위에서 말한 이점들을 얻기 위해서 이그레스를 세팅하는 것은 유의미하다는 생각이 든다.

image.png
번외로, 세팅이 잘 됐는지 안 됐는지 확인할 때 istioctl analyze가 매우 유용하다.
이거 없었으면 세팅하는데 한 세월 걸렸을 듯.

이전 글, 다음 글

다른 글 보기

이름 index noteType created
1W - 서비스 메시와 이스티오 1 published 2025-04-10
1W - 간단한 장애 상황 구현 후 대응 실습 2 published 2025-04-10
1W - Gateway API를 활용한 설정 3 published 2025-04-10
1W - 네이티브 사이드카 컨테이너 이용 4 published 2025-04-10
2W - 엔보이 5 published 2025-04-19
2W - 인그레스 게이트웨이 실습 6 published 2025-04-17
3W - 버츄얼 서비스를 활용한 기본 트래픽 관리 7 published 2025-04-22
3W - 트래픽 가중치 - flagger와 argo rollout을 이용한 점진적 배포 8 published 2025-04-22
3W - 트래픽 미러링 패킷 캡쳐 9 published 2025-04-22
3W - 서비스 엔트리와 이그레스 게이트웨이 10 published 2025-04-22
3W - 데스티네이션 룰을 활용한 네트워크 복원력 11 published 2025-04-26
3W - 타임아웃, 재시도를 활용한 네트워크 복원력 12 published 2025-04-26
4W - 이스티오 메트릭 확인 13 published 2025-05-03
4W - 이스티오 메트릭 커스텀, 프로메테우스와 그라파나 14 published 2025-05-03
4W - 오픈텔레메트리 기반 트레이싱 예거 시각화, 키알리 시각화 15 published 2025-05-03
4W - 번외 - 트레이싱용 심플 메시 서버 개발 16 published 2025-05-03
5W - 이스티오 mTLS와 SPIFFE 17 published 2025-05-11
5W - 이스티오 JWT 인증 18 published 2025-05-11
5W - 이스티오 인가 정책 설정 19 published 2025-05-11
6W - 이스티오 설정 트러블슈팅 20 published 2025-05-18
6W - 이스티오 컨트롤 플레인 성능 최적화 21 published 2025-05-18
8W - 가상머신 통합하기 22 published 2025-06-01
8W - 엔보이와 iptables 뜯어먹기 23 published 2025-06-01
9W - 앰비언트 모드 구조, 원리 24 published 2025-06-07
9W - 앰비언트 헬름 설치, 각종 리소스 실습 25 published 2025-06-07
7W - 이스티오 메시 스케일링 26 published 2025-06-09
7W - 엔보이 필터를 통한 기능 확장 27 published 2025-06-09

관련 문서

이름 noteType created
Istio ServiceEntry knowledge 2025-04-17
3W - 서비스 엔트리와 이그레스 게이트웨이 published 2025-04-22

참고


  1. https://istio.io/latest/docs/reference/config/networking/service-entry/ ↩︎

  2. https://istio.io/v1.12/blog/2019/monitoring-external-service-traffic/ ↩︎