Istio Hands-on Study [1기]

[3주차] 트래픽 제어(세밀한 트래픽 라우팅) : Istio의 서비스 검색을 사용하여 클러스터 외부의 서비스로 라우팅하기

구구달스 2025. 4. 20. 21:10
CloudNet@ 가시다님이 진행하는 Istio Hands-on Study [1기]

🚀Istio로
클러스터 외부 서비스 호출 관리하기

  • Istio의 서비스 디스커버리 기능을 활용해 클러스터 외부 서비스와 안전하게 통신하는 방법
  • 외부 트래픽을 차단하고, 필요한 외부 서비스만 허용하도록 ServiceEntry를 설정하는 과정

🔒 외부 트래픽 차단 설정하기

  • 기본적으로 Istio는 서비스 메시에서 외부로 나가는 트래픽을 모두 허용하지만, 보안을 강화하려면 이를 차단할 수 있습니다.
    외부 트래픽을 차단하면 악의적인 행위자가 메시 내부의 서비스를 통해 데이터를 유출하는 걸 방지할 수 있죠. 이는 defense-in-depth 전략의 일환입니다.
  • webapp 파드에서 외부 다운로드 성공
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~$ kubectl exec -it deploy/webapp -n istioinaction -c webapp -- wget https://raw.githubusercontent.com/gasida/KANS/refs/heads/main/msa/sock-shop-demo.yaml
Connecting to raw.githubusercontent.com (185.199.108.133:443)
saving to 'sock-shop-demo.yaml'
sock-shop-demo.yaml  100% |*******************************************************************************************| 17782  0:00:00 ETA
'sock-shop-demo.yaml' saved
  • 다음 명령어로 Istio의 기본 정책을 ALLOW_ANY에서 REGISTRY_ONLY로 변경해, 서비스 메시 레지스트리에 명시적으로 등록된 서비스로만 트래픽이 나가도록 설정합니다:
    이 설정은 메시 외부로 나가는 트래픽을 차단하고, Istio의 서비스 레지스트리에 등록된 외부 서비스로만 통신을 허용
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~$ docker exec -it myk8s-control-plane bash

root@myk8s-control-plane:/# istioctl install --set profile=default --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
This will install the Istio 1.17.8 default profile with ["Istio core" "Istiod" "Ingress gateways"] components into the cluster. Proceed? (y/N) y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete                                                                                                                    Making this installation the default for injection and validation.

Thank you for installing Istio 1.17.  Please take a few minutes to tell us about your install/upgrade experience!  https://forms.gle/hMHGiwZHPU7UQRWe9
root@myk8s-control-plane:/# exit
exit
  • webapp 파드에서 외부 다운로드 실패
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~$ kubectl exec -it deploy/webapp -n istioinaction -c webapp -- wget https://raw.githubusercontent.com/gasida/KANS/refs/heads/main/msa/sock-shop-demo.yaml
Connecting to raw.githubusercontent.com (185.199.110.133:443)
wget: error getting response: Connection reset by peer
command terminated with exit code 1

실습에서는 istioctl install로 설정을 변경하지만,
실제 환경에서는 IstioOperator나 istio-system의 configmap을 수정하는 게 일반적입니다.

Istio의 outboundTrafficPolicy를 REGISTRY_ONLY로 설정해 외부 트래픽을 차단합니다.
이는 보안을 강화하는 기본적인 방어 전략입니다!


📋 ServiceEntry로 외부 서비스 등록하기

  • 메시 내부 서비스가 외부 서비스(예: 데이터베이스, 캐시, 외부 API)와 통신하려면, Istio의 서비스 레지스트리에 해당 서비스를 등록해야 해요. 이를 위해 ServiceEntry 리소스를 사용합니다.
    ServiceEntry는 외부 서비스의 메타데이터를 정의해 Istio가 이를 인식하도록 돕습니다.
  • Istio는 Kubernetes의 Service 객체를 기반으로 내부 서비스 레지스트리를 구축하지만, 외부 서비스는 ServiceEntry로 수동 등록해야 합니다.
  • 예를 들어, 우리 가상의 스토어에서 고객 피드백 포럼으로 사용하는 외부 서비스 jsonplaceholder.typicode.com을 등록해보겠습니다.
  • 다음은 ServiceEntry 설정입니다:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: jsonplaceholder #ServiceEntry의 이름
spec:
  hosts:
  - jsonplaceholder.typicode.com #ServiceEntry가 적용될 외부 서비스의 도메인 이름
                                 #이 도메인으로 향하는 모든 요청은 이 ServiceEntry 규칙의 영향을 받습니다.
  ports:
  - number: 80 #외부 서비스가 사용하는 포트 번호
    name: http
    protocol: HTTP
  resolution: DNS #외부 서비스의 엔드포인트를 어떻게 찾을지 정의
                  #'DNS'는 도메인 이름 시스템을 통해 서비스의 IP 주소를 찾는다는 의미
  location: MESH_EXTERNAL #서비스의 위치
                          #서비스가 Istio 서비스 메시 외부에 있음을 나타냅니다. 
                          # 즉, 서비스 메시에 속하지 않은 외부 서비스임을 명시
  • 이 설정은:
    • hosts: 외부 서비스의 도메인(jsonplaceholder.typicode.com)을 지정합니다.
    • ports: HTTP 프로토콜로 포트 80을 사용합니다.
    • resolution: DNS: 도메인 이름을 DNS로 확인합니다.
    • location: MESH_EXTERNAL: 서비스가 메시 외부에 있음을 나타냅니다.
  • 이 ServiceEntry는 Istio 레지스트리에 jsonplaceholder.typicode.com을 추가해 메시 내부에서 호출을 허용합니다.

ServiceEntry를 사용해 외부 서비스를 Istio 서비스 레지스트리에 등록하세요.
이는 메시 내부에서 외부 서비스 호출을 허용하는 핵심 단계입니다!


🛠️ 외부 서비스 호출 테스트하기

  • 이제 실제로 외부 서비스 호출을 테스트해볼게요.
  • 먼저 jsonplaceholder.typicode.com과 통신하는 forum 애플리케이션을 배포하고, ServiceEntry 적용 전후의 동작을 비교해봅시다.
  • forum 애플리케이션을 배포합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f services/forum/kubernetes/forum-all.yaml -n istioinaction
service/forum created
deployment.apps/forum created
  • 배포 후 상태를 확인합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get deploy,svc -n istioinaction -l app=webapp
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/webapp   1/1     1            1           167m

NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/webapp   ClusterIP   10.200.1.15   <none>        80/TCP    167m
  • forum 서비스를 호출해봅니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/users
error calling Forum service
  • 이때 REGISTRY_ONLY 정책 때문에 외부 트래픽이 차단되어 있어 error calling Forum service 같은 오류가 발생합니다.

  • 이제 ServiceEntry를 적용해 jsonplaceholder.typicode.com을 허용합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch5/forum-serviceentry.yaml -n istioinaction
serviceentry.networking.istio.io/jsonplaceholder created
  • 적용 후 다시 호출해봅니다: 이제 호출이 성공하며 사용자 목록이 반환됩니다
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://webapp.istioinaction.io:30000/api/users | jq
[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "Sincere@april.biz",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "Gwenborough",
      "zipcode": "92998-3874"
    },
    "phone": "1-770-736-8031 x56442",
    "website": "hildegard.org",
    "company": {
      "name": "Romaguera-Crona",
      "catchPhrase": "Multi-layered client-server neural-net",
      "bs": "harness real-time e-markets"
    }
  },
...

ServiceEntry 적용 전후로 forum 서비스를 호출해 외부 트래픽 차단과 허용 동작을 확인합니다.
ServiceEntry로 외부 서비스 호출이 성공합니다!


📌핵심 요약

  1. 외부 트래픽 차단: Istio의 outboundTrafficPolicy를 REGISTRY_ONLY로 설정해 메시 외부로 나가는 트래픽을 차단
  2. ServiceEntry 설정: ServiceEntry 리소스를 사용해 jsonplaceholder.typicode.com을 Istio 서비스 레지스트리에 등록해 메시 내부에서 호출을 허용
  3. 외부 서비스 테스트: forum 애플리케이션을 배포하고, ServiceEntry 적용 전후로 호출을 테스트해 트래픽 차단과 허용 동작을 확인 => ServiceEntry 적용 후 외부 API 호출이 성공했습니다.