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
어떤 식으로 작성하는지 간단하게 설명한 후에 기능들을 살펴보겠다.
일단 hosts
와 ports
필드를 통해 어떤 호스트, 포트를 진입점으로 등록할 것인지 명시한다.
addresses:
- 192.192.192.192/24
endpoints:
- address: us.foo.bar.com
ports:
http: 8080
addresses
필드는 이 진입점으로 들어오기 위한 IP 대역을 나타낸다.
가상 IP라고 보면 되겠다.
endpoints
는 실제 트래픽을 보내야할 엔드포인트를 나타낸다.
이 필드가 있으면 기본적으로 서비스 엔트리가 등록될 때 hosts
필드를 이용해 DNS 쿼리를 날리지 않고, 이 주소를 사용한다.
location
필드에는 두 가지 값이 가능하다.
- MESH_EXTERNAL - 서비스가 메시 외부에 있음을 나타낸다.
- MESH_INTERNAL - 메시 내부에 있긴 하나 레지스트리에 등록되지 않은 서비스를 등록할 때 사용한다.
- 가령 클러스터 외부에 VM을 메시 내부로 들이고 싶을 때 설정한다.
- 이렇게 설정되면 서비스 간 mTLS 설정이나, 정책 적용의 영향을 받게 된다.
resolution
필드는 프록시가 IP 주소를 알아내어 어떻게 라우팅할지를 지정한다.
- DNS - 일반적인 DNS 방식으로, 보통은
hosts
필드의 도메인을 보고 질의하여 IP 주소를 알아낸다. - NONE - 들어오는 요청이 이미 자체적으로 IP 주소 질의를 마쳤다고 가정한다.
- STATIC -
endpoints
필드에 명시된 IP 주소만 사용한다. - DNS_ROUND_ROBIN - DNS 로드밸런싱을 쓰는 환경에서 각 연결은 첫번째로 연결된 주소로만 연결되도록 보장한다.
이그레스 게이트웨이
서비스 엔트리를 배치하면 서비스 메시의 엔보이들은 해당 주소에 대해 제대로 트래픽을 보낼 수 있게 된다.
그러나 이것만으로는 충분치 않은 사용 케이스가 있을 수 있다!
단순 서비스 엔트리를 등록하는 방식은 외부로 가는 트래픽을 제대로 추적 관리하기가 힘들다는 것이다.
물론 이미 한 차례 특정한 호스트에 대해서만 트래픽을 보낼 수 있도록 하는 것도 훌륭한 보안이다.
그러나 외부로 향하는 트래픽이 위험할 수 있기에 제한을 한다면, 아예 외부로 나가는 지점을 하나로 줄여서 관리하는 것도 꽤나 도움이 될 것이다.
이럴 때 사용하는 것이 바로 이그레스 게이트웨이이다.
구체적으로 이그레스 게이트웨이는 다음의 상황에서도 유용하다.
- 특정 노드만 외부로 접근할 수 있는 상황이라 서비스 메시 내부적으로 해당 노드의 지점을 경유하고 싶다.
- 외부로 향하는 모든 트래픽에 대해 세부적인 모니터링을 하고 감사제어를 하고 싶다.
- 연결할 외부 대상에 대해 인증 인가를 해야할 때 하나의 포인트에서 처리하고 싶다.
실습 진행
이그레스 게이트웨이에 대해서는 자세히 설명하지 않겠다.
사실 그냥 저번 주차에 공부한 인그레스 게이트웨이의 역방향일 뿐이다.
아웃바운드 트래픽 세팅 확인
keti debug -- curl naver.com
기본 이스티오 설정에서는 서비스 메시 아웃바운드 트래픽은 열려 있다.
실제로 이런 요청은 클러스터 중 PassthroughCluster를 통해 나간다.[2]
이 클러스터는 가상 클러스터로서 등록된 클러스터가 아닌 주소로 가는 요청이 기본으로 빠지게 되는 라우팅 테이블의 게이트웨이라고 생각하면 되겠다.
모든 엔보이의 클러스터 설정을 보면 이 클러스터가 있는 것을 볼 수 있다.
그리고 엔보이의 리스너 필드를 보면 0.0.0.0에 대해서 패스스루 클러스터를 타는 것을 볼 수 있다.
몇몇 개는 특정 조건을 만족할 시 라우트를 타는데, 대체로 메트릭이나 컨트롤플레인과의 통신과 연관된다.
몇 번 외부 호출을 해보면 키알리로도 이렇게 패스스루 클러스터를 통해 나간다는 것을 확인할 수 있다.
BlackHoleCluster라는 것도 있는데, 이것 역시 가상의 클러스터로 패스스루 클러스터와 정 반대로 모든 트래픽을 막아버리는 클러스터이다.
아웃바운드 트래픽 제한
그럼 이제 외부로 가는 통신을 막아버리자!
meshConfig:
outboundTrafficPolicy:
mode: REGISTRY_ONLY
메시 전역적으로 막는 방법은 쉽다.
이스티오 설정 파일에 아웃바운드 트래픽 정책이 원래는 ALLOW_ANY로 돼있는데, 이걸 REGISTRY_ONLY로 바꿔주면 된다.
이걸 설정하자마자 엔보이들의 리스너 설정을 보면 그 많던 패스스루들이 사라진 것을 볼 수 있다!
대신 그 자리엔 Non-HTTP/Non-TCP
라는 것들이 남아있다.
json 양식으로 조금 더 뜯어보면 명확하게 보이는데, 아예 블랙홀 클러스터로 가라고 표시되는 것이 보인다.
요청을 외부로 다시 보내보면, 이번에는 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
서비스 엔트리 리소스를 만들어 메시 외부의 주소를 서비스 레지스트리에 등록한다.
이 호스트는 책 예제에서 사용하는 호스트로, 가짜 게시판 api서버처럼 동작하면서 응답을 리턴해준다.
클러스터 내 엔드포인트가 아니니 EDS에는 아무런 영향이 없었으나, CDS, RDS, LDS에 설정이 들어가는 것을 확인할 수 있다.
클러스터 설정을 보면 위와 같이 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
이렇게 반복 접근을 걸어서 또 키알리로 확인해보면 jsonplaceholder라는 서비스 엔트리로 요청이 전달되는 것을 볼 수 있다!
요청이 가고 나서 엔드포인트 설정을 보면 아예 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에서 외부 주소로의 요청은 이그레스 게이트웨이로, 그리고 이그레스 게이트웨이에서는 해당 외부 주소로 트래픽을 보낼 것이다.
그럼 아까 봤던 서비스 엔트리 리소스는 안 보이고 이그레스 게이트웨이를 통해 트래픽이 나가게 된다.
그림을 딱 봐도 알겠지만, 아까와 다르게 이번에는 트래픽에 대한 메트릭 정보를 볼 수 있다!
이제 나가려는 트래픽에 대해 이그레스 게이트웨이에서 메트릭을 추적할 수도 있게 됐다.
이그레스 게이트웨이에 로깅 설정도 넣어주면 구체적으로 어떤 트래픽이 나가고 있는지도 확인할 수 있게 될 것이다.
결론
생각보다 이그레스 게이트웨이를 설정하는 과정은 쉬운 듯 하면서도 번거로웠다.
메시 내부의 트래픽이 이그레스를 타기 위해서는 다음의 과정이 필요하다.
- 이그레스 게이트웨이 워크로드를 만든다.
- 서비스 엔트리로 외부 주소를 레지스트리에 등록시킨다.
- 이그레스 세팅의 경우 MESH_EXTERNAL을 쓰나 안 쓰나는 사실 상관 없다.
- 게이트웨이 리소스로 이그레스 게이트웨이를 클러스터에 등록한다.
- 버츄얼 서비스로 서비스 엔트리로 등록된 주소는 게이트웨이로 가야한다고 명시한다.
- 버츄얼 서비스로 게이트웨이가 받은 트래픽을 외부로 보내야 한다고 명시한다.
이런 번거로움이 있긴 하지만, 위에서 말한 이점들을 얻기 위해서 이그레스를 세팅하는 것은 유의미하다는 생각이 든다.
번외로, 세팅이 잘 됐는지 안 됐는지 확인할 때 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 |