본문 바로가기
스터디 이야기/Kubernetes Advanced Networking Study

[KANS] Service Mesh - Istio

by lakescript 2024. 10. 17.
더보기

이 스터디는 CloudNet@에서 진행하는 KANS 스터디를 참여하면서 공부하는 내용을 기록하는 블로그 포스팅입니다.

CloudNet@에서 제공해주는 자료들을 바탕으로 작성되었습니다.

Istio

Service Mesh

등장 배경

https://www.redhat.com/en/topics/microservices/what-is-a-service-mesh

 

Service Mesh는 마이크로서비스 아키텍처 환경의 시스템 전체 모니터링의 어려움, 운영시 시스템 장애가 발생했을 때 원인 파악과 병목 구간 찾기가 어렵기 때문에 탄생했다고 볼 수 있는데요. 전통적인 모놀리식 아키텍처에서는 모든 기능이 하나의 애플리케이션 안에 포함되어 있어 통신 및 상호작용이 단일 프로세스 내에서 이루어졌습니다. 하지만, 마이크로서비스 아키텍처로 전환되면서, 애플리케이션이 여러 개의 독립적인 서비스로 분리되었고, 각 서비스가 네트워크를 통해 서로 통신해야 하는 환경이 만들어졌습니다. 이로 인해 서비스 간의 통신이 매우 복잡해졌고, 결국 서비스의 개수와 복잡성이 증가할수록 운영 환경에서 네트워크 트래픽을 효율적으로 관리하고 문제를 추적하는 것이 어려워지게 되었습니다. 

 

개념

Service Mesh의 기본 개념은 마이크로서비스 간에 mesh 형태(모든 서비스가 네트워크 상에서 서로 복잡하게 연결되어 통신하는 구조)의 통신이나 그 경로를 제어하는 것 입니다.

 

기본 동작

Service Mesh의 기본 동작은 파드(Pod)간의 통신 경로에 프록시를 배치하여, 트래픽을 모니터링 및 제어를 통해 서비스 간의 통신을 중앙에서 관리하고, 보안, 트래픽 제어, 가시성 등을 쉽게 구현하는 것입니다. 이를 통해 기존 애플리케이션 코드에 수정 없이 구성이 가능합니다.

 

 

위와 같이 기존의 통신 환경이 존재합니다.

 

애플리케이션 수정 없이, 모든 애플리케이션 통신 사이에 Proxy 를 두고 통신을 합니다. 즉, Pod내에 sidecar container로 생성되어 동작하며, proxy container가 Application의 트래픽을 가로채야 합니다. 이때, Application과 sidecar container가 같은 network namespace를 사용합니다. 하지만 network namespace를 공유하니 예를들어 80 port를 각자가 사용할 수 없습니다. 그러면 어떻게 트래픽을 가로챌까요? 바로 Pod내에서 iptables rule을 사용합니다.(극악..)

 

Proxy는 결국 DataPlane이기 때문에, 이를 중앙에서 관리하는 ControlPlane을 두고 중앙에서 관리를 해야 합니다. 이때, 중앙에서 proxy의 동적인 설정 관리(라우팅, 보안 통신을 위한 mTLS 관련, 동기화 상태 정보 등)가 유연하게  설정 관리가 잘되는 Envoy가 담당합니다. 

 

Envoy란?
구글 IBM 리프트(Lyft)'가 중심이 되어 개발하고 있는 오픈 소스 소프트웨어이며, C++ 로 구현된 고성능 Proxy입니다. 특히 서비스 메쉬 환경에서 마이크로서비스 간의 네트워크 통신을 중재하고 관리하는 역할을 합니다. 또한, 네트워크의 투명성을 목표, 다양한 필터체인 지원(L3/L4, HTTP L7), 동적 configuration API 제공, api 기반 hot reload 제공합니다. 
즉, Envoy는 L4/L7 프록시로서, 서비스 간의 네트워크 통신을 관리하고, 동적 구성과 강력한 모니터링 기능을 제공하는 오픈 소스 소프트웨어입니다. 마이크로서비스 아키텍처에서 서비스 간의 트래픽을 효율적으로 제어하고, 서비스 메쉬의 핵심 프록시로서 널리 사용됩니다.

 

트래픽 모니터링

요청의 '에러율, 레이턴시, 커넥션 개수, 요청 개수' 등 메트릭 모니터링, 특정 서비스간 혹은 특정 요청 경로로 필터링이 가능합니다. 이로 인해 원인 파악이 비교적 용이해집니다.

 

트래픽 컨트롤

트래픽 시프팅(Traffic shifting)

예시) 99% 기존앱 + 1% 신규앱 , 특정 단말/사용자는 신규앱에 전달하여 단계적으로 적용하는 카니리 배포 가능


서킷 브레이커(Circuit Breaker)

목적지 마이크로서비스에 문제가 있을 시 접속을 차단하고 출발지 마이크로서비스에 요청 에러를 반환 (연쇄 장애, 시스템 전제 장애 예방)


폴트 인젝션(Fault Injection)

의도적으로 요청을 지연 혹은 실패를 구현


속도 제한(Rate Limit)

요청 개수를 제한

 

Istio란

https://istio.io/latest/docs/ops/deployment/architecture/

Istio Mesh라고도 불리는 Istio는 Ingress traffic이 들어오면 동작하는 Serive내에 Application이 존재하고 해당 Application과 통신을 하는 Proxy가 존재합니다. Service A와 Service B가 통신(Mesh Traffic) 하게 되면 필요한 설정 정보들은 control plane인 istiod에 저장되어 있어 각각 전달해줍니다. 

 

Istio 구성요소와 Envoy

https://istio.io/latest/docs/concepts/security/

 

istiod

 

istiod는 Istio의 Control Plane을 구성하는 핵심 컴포넌트로, 과거에 분리되었던 여러 기능이 통합되었습니다. 즉, Pilot, Galley, Citadel의 역할을 통합한 Control Plane 입니다

 

- Pilot: Envoy 프록시와 통신하면서 라우팅 규칙을 동기화하고, ADS를 통해 트래픽 제어 설정을 전달합니다.
- Galley: Kubernetes와의 연동 및 엔드포인트 갱신을 관리했으나, 현재는 istiod에 통합되어 Kubernetes 리소스 관리 역할을 합니다.
- Citadel: 서비스 간 통신 암호화(mTLS) 및 인증서 관리를 담당하며, 이를 통해 보안을 강화합니다.

Istio proxy

Data Plane의 중요한 구성 요소로, 주로 Envoy Proxy를 사용합니다. 각 Pod의 sidecar container 형태로 배포되며, 서비스 간의 모든 네트워크 통신을 가로채어 처리합니다. 또한, Envoy 래핑한 Proxy, istiod와 통신하고 서비스 트래픽을 통제, 옵저버빌리티를 위한 메트릭을 제공합니다.

Traffic Management 

Istio에서 트래픽 관리는 VirtualServiceDestinationRule 설정을 통해서 동작됩니다.

Gateway

Istio의 Gateway는 외부 트래픽(HTTP, HTTPS, TCP 등)을 클러스터 내부로 들어오게 하는 entry point입니다. Kubernetes의 Ingress와 비슷하지만, Istio의 Gateway는 L4~L7 계층에서 더 세밀하게 트래픽을 제어할 수 있습니다.

VirtualService

들어오는 트래픽을 어디로 라우팅할지 정의하는 리소스로 Gateway나 사이드카 프록시를 통해 들어온 트래픽을 특정 서비스(파드)로 라우팅할 수 있도록 규칙을 설정합니다. 특히, 호스트명, 경로, 헤더에 따라 트래픽을 여러 서비스로 분기할 수 있고, 로드 밸런싱, 페일오버, 트래픽 미러링 등의 기능도 지원합니다. 

 

VirtualService 는 DestinationRule 에서 설정된 서브셋(subset)을 사용하여 트래픽 컨트롤을 할 수 있습니다.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v3

 

위의 예시는 end-user: jason 헤더가 포함된 요청은 v2 서브셋(버전 2)으로 라우팅되며, 그 외의 모든 요청은 v3 서브셋(버전 3)으로 라우팅됩니다.

DestinationRule

istio에서 서비스 간 통신의 트래픽 정책을 정의하는 리소스입니다. 특히, 특정 서비스에 대한 트래픽 제어 및 정책 적용을 할 수 있습니다. Istio의 VirtualService가 트래픽을 어느 서비스로 보낼지 결정한다면, DestinationRule은 해당 서비스로 전달된 트래픽이 어떻게 처리될지 설정합니다.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: my-destination-rule
spec:
  host: my-svc
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
  - name: v3
    labels:
      version: v3

 

- host: my-svc라는 호스트(Service)에 적용됩니다.
- subsets: 서비스의 두 가지 버전(v1, v2)을 정의하여, 특정 트래픽을 해당 버전으로 보낼 수 있게 합니다.

 

즉, 3개의 subsets for the my-svc destination service 에 3개의 subsets이 있고, 이중 v1/v3 은 RAMDOM 이고 v2 는 ROUND_ROBIN의 tafficPolicy가 적용됩니다.

 

 

실습

위와 같이 istio의  통신 구조를 확인해보기 위한 실습을 진행해보겠습니다.

실습 환경 구성

- VPC 1개(퍼블릭 서브넷 2개)

- EC2 인스턴스 3대 (Ubuntu 22.04 LTS, t3.xlarge - vCPU 4 , Mem 16) 

  - k3s-s : control plane node

  - k3s-w1, w2 : worker node 

- testpc 1대는 t3.small

위와 같은 스펙으로 실습환경을 구성합니다.

 

istioctl 설치

https://istio.io/latest/docs/setup/install/

istio를 설치하는 방법에는 여러가지가 있습니다. 이번 실습에서는 istioctl을 통해 설치하도록 하겠습니다. 설치는 k3s-s node에 진행합니다.

여기서 Operator를 이용한 설치는 1.23 이후 버전부터는 지원하지 않으니 참고해주세요.

 

export ISTIOV=1.23.2
echo "export ISTIOV=1.23.2" >> /etc/profile

먼저 설치할 istio 버전(v1.23.2)을 환경변수로 설정합니다. 

 

curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV TARGET_ARCH=x86_64 sh -

위 명령어를 통해 istioctl을 설치합니다.

 

tree istio-$ISTIOV -L 2

설치된 목록을 확인합니다. 여기서 manifast.yaml 파일을 통해 istio를 설치합니다.

cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl

설치된 istioctl을 실행시키기 위해 경로를 옮겨줍니다. 

 

istioctl version --remote=false

설치된 것을 확인하기 위해 위의 명령어를 통해 version을 확인합니다.

 

Control Plane 배포

istioctl profile list

Istio Profile은 Istio를 설치할 때 설치 구성의 사전 정의된 템플릿입니다. Istio는 다양한 사용 환경과 요구사항에 맞춰 여러 가지 기능을 제공하기 때문에, 사용자는 설치 시 원하는 기능만 선택적으로 설치할 수 있습니다. profile의 종류는 아래의 사진과 같습니다.

이번 실습에서는 경량화된 k3s의 환경이다보니 demo profile을 사용하도록 하겠습니다. 

istioctl profile dump demo

demo profile를 dump 명령어로 자세히 살펴보겠습니다.

이번 실습에서는 복잡도를 조금 줄이기 위해 egressGateways를 false로 변경하도록 하겠습니다.

istioctl profile dump demo > demo-profile.yaml

 

변경방법은 dump 명령어로 보여진 spec을 yaml 파일로 저장하여 egressGateways를 변경하고 저장합니다.

 

istioctl install -f demo-profile.yaml

 

해당 파일로 istio를 다시 설치합니다.

This will install the Istio 1.23.2 "demo" profile (with components: Istio core, Istiod, and Ingress gateways) into the cluster. Proceed? (y/N)

 

위와 같이 demo profile을 변경하겠냐고 묻는 질의에 y 를 입력하면 설치가 진행됩니다.

 

설치 확인

kubectl get all,svc,ep,sa,cm,secret -n istio-system

다양한 리소스가 설치된 것을 확인하실 수 있습니다.

 

kubectl get crd  | grep istio.io | sort

다양한 crd도 확인하실 수 있습니다.

 

istio-ingressgateway 의 envoy 버전 확인

kubectl exec -it deploy/istio-ingressgateway -n istio-system -c istio-proxy -- envoy --version

istio-ingressgateway가 envoy를 매핑해서 사용하는데, 그 envoy의 버전을 확인해보겠습니다.

 

istio-ingressgateway 서비스 NodePort로 변경

kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"type":"NodePort"}}'

 

ingress, loadbalancer등 istio를 통해 pod 내부로 들어오는 방법은 많지만, 실습을 편하게 하기 위해서 LoadBalancer에서 nodePort로 변경합니다.

 

istio-ingressgateway 서비스 확인

kubectl get svc,ep -n istio-system istio-ingressgateway

istio-ingressgateway의 type이 nodeport로 변경된 것을 확인해보겠습니다.

 

 

istio-ingressgateway 서비스 포트 정보 확인

kubectl get svc -n istio-system istio-ingressgateway -o jsonpath={.spec.ports[*]} | jq

 

즉, istio-ingressgateway Pod는 nginx-ingress와 같은 역할을 합니다.

해당 service들의 port를 확인해보겠습니다. 

 

istio-ingressgateway deployment pod의 포트 정보 확인

kubectl get deploy/istio-ingressgateway -n istio-system -o jsonpath={.spec.template.spec.containers[0].ports[*]} | jq

 

kubectl get deploy/istio-ingressgateway -n istio-system -o jsonpath={.spec.template.spec.containers[0].readinessProbe} | jq

 

istiod 디플로이먼트 정보 확인

kubectl exec -it deployment.apps/istiod -n istio-system -- ss -tnlp

 

위와 마찬가지로 istiod deployment로 띄어진 pod에 접속해서 socket 정보를 확인해보겠습니다.

pilot-discovery가 보여집니다.

 

istio-ingressgateway 디플로이먼트 정보 확인

kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- ss -tnlp

istio-ingressgateway deployment로 띄어진 pod에 접근해서 socket의 정보를 확인해보겠습니다.

envoy와 pilot-agent가 보여집니다.

 

kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- ss -tnp

 

tcp 소켓에대한 정보를 확인해보겠습니다.

istio-ingressgateway와 istiod의 관계

172.16.2.3는 istio-gateway 내부에서 tcp 소켓 정보를 확인한 값입니다. 그 값이 istio-ingressgateway pod의 IP와 같습니다. 그리고 peer로 연결되어있는 주소의 값을 확인해보니 그 값은 10.10.200.198:15012이고, 해당 주소는 istiod의 ClusterIP와 Port인 것을 확인하실 수 있습니다. 즉, 서로 연결되어있다는 것을 알 수 있습니다.

 

mutating Webhook admisstion controller 사용하여 namespace에 Auto Injection 설정

Auto Injection with Namespace Label

Auto Injection with Namespace Label은 Istio에서 sidecar proxy(보통 Envoy)를 자동으로 마이크로서비스에 주입(Injection)하는 기능을 제공합니다. 이 기능은 Istio sidecar proxy를 수동으로 파드에 추가하지 않고, 특정 네임스페이스에 있는 모든 파드에 대해 자동으로 sidecar를 주입하여 service mesh에 포함되도록 설정할 수 있게 합니다. 그 기능은 mutating Webhook admisstion controller이 처리합니다.

 

kubectl label namespace default istio-injection=enabled

 

default namespace에 istio-injection=enabled라는 label을 붙여줍니다.

kubectl get ns -L istio-injection

 

위의 명령어를 통해 namespace에 istio-injection이라는 label이 붙었는지 확인해보겠습니다.

 

즉, 이제부터 default namespace에서 생성되는 pod는 mutating Webhook admisstion controller에 의해 istio sidecar가 생성됩니다.

 

Istio 통한 외부 노출 실습

istio 접속 테스트를 위한 변수 지정

export IGWHTTP=$(kubectl get service -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports[1].nodePort}')

위의 명령어로 IGWHTTP라는 환경 변수에 istio-ingressgateway의 nodePort를 설정합니다.

 

MYDOMAIN=<각자 자신의 www 도메인>

그 다음으로 접속 테스트를 원활히 하기 위해 domain까지 입력합니다.

 

echo "<istio-ingressgateway 파드가 있는 워커 노드 ip> $MYDOMAIN" >> /etc/hosts

worker node로 접속해보기 위해 위의 명령어로 /etc/hosts에 추가합니다.

 

MYDOMAIN=<각자 자신의 www 도메인>
export MYDOMAIN=<각자 자신의 www 도메인>
echo -e "192.168.10.10 $MYDOMAIN" >> /etc/hosts
echo -e "export MYDOMAIN=$MYDOMAIN" >> /etc/profile

위의 명령어를 통해 url 설정까지 진행합니다.

istio ingress gw 접속 테스트

curl -v -s $MYDOMAIN:$IGWHTTP

아직은 설정이 안되어 있어서 접속이 되지 않습니다.

 

위 설정을 testpc ec2와 local pc에서도 진행해줍니다.

 

Nginx deployment와 service 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-websrv
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-websrv
  template:
    metadata:
      labels:
        app: deploy-websrv
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: deploy-websrv
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: svc-clusterip
spec:
  ports:
    - name: svc-webport
      port: 80
      targetPort: 80
  selector:
    app: deploy-websrv
  type: ClusterIP

 

sidecar container 배포 확인

kubectl get pod,svc,ep -o wide

 

배포된 pod와 svc, endpoints를 확인해보겠습니다.

이때, init container가 먼저 실행되는데 위의 사진에서 우측에 보이시는 바와 같이 iptables rule을 설정해주는 역할을 합니다. 

 

...
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-websrv
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-websrv
  template:
    metadata:
      labels:
        app: deploy-websrv
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: deploy-websrv
        image: nginx:alpine
        ports:
        - containerPort: 80
...

 

위에서 정의한 pod yaml 파일에서 init container의 명세를 설정하지 않았는데, init container가 어떻게 생성되고 동작했던 것 일까요?

바로 default namespace에 생성을 했기 때문에 istiod가 mutating Webhook admisstion controller에 의해 init container를 임의로 생성하여 iptables rule의 정보를 넣어줍니다! 

(중간에 실습환경을 재구성했기 때문에 IP들은 달라보일 수 있습니다..! 여기서 중요한 건 init container가 어떤 역할을 했냐는 거에요!)

 

Istio Gateway/VirtualService 설정

 

이번 실습의 트래픽 흐름은 클라이언트가 NodePort를 통해 Istio의 Ingress Gateway에 접속하고, Ingress Gateway가 트래픽을 직접 Endpoints로 전달합니다. 그 후 트래픽은 sidecar(proxy) 컨테이너가 있는 애플리케이션 파드로 전달됩니다. 이때, sidecar는 트래픽을 제어하며, 애플리케이션 컨테이너로 전달합니다. 이때도 iptables 규칙이 작동하여 트래픽을 적절히 캡처합니다.

 

즉, 클라이언트 PC → (Service:NodePort) Istio ingressgateway 파드 → (Gateway, VirtualService, Service 는 Bypass) → Endpoint(파드 : 사이드카 - Application 컨테이너) 의 흐름입니다.

 

Istio Gateway/VirtualService 배포

apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: test-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: nginx-service
spec:
  hosts:
  - "$MYDOMAIN"
  gateways:
  - test-gateway
  http:
  - route:
    - destination:
        host: svc-clusterip
        port:
          number: 80

 

설치 확인

kubectl api-resources  | grep istio

설치 후 api-resource를 확인해보겠습니다.

gateway와 virtualservices가 확인됩니다.

 

kubectl get gw,vs

추가로 정말로 리소스가 배포되었는지 확인해보겠습니다.

 

Istio를 통한 Nginx 파드 접속 테스트

local에서 확인

curl -s $MYDOMAIN:$IGWHTTP | grep -o "<title>.*</title>"

 

 

접속 로그 확인

kubectl logs -n istio-system <istio-ingressgateway-pod-name> -f

위의 명령어로 접속했을 때의 log를 살펴보겠습니다.

 

istio-proxy, Istiod 가 각각 사용하는 포트 정보

istio-proxy (https://istio.io/latest/docs/ops/deployment/application-requirements/#ports-used-by-istio)
istiod (https://istio.io/latest/docs/ops/deployment/application-requirements/#ports-used-by-istio)

 

Istio Security

https://istio.io/latest/docs/concepts/security/

 

monolithic application을 microservices로 전환하면 대응이 빨라지고, 쉽게 확장 가능하며, 재사용성 향상등 다양한 이점을 얻을 수 있습니다. 하지만 몇 가지의 요구 사항이 존재합니다.

요구 사항

- 중간자 공격(man-in-the-middle attacks)을 방어하려면 트래픽 암호화가 필요합니다.
- 유연한 서비스 액세스 제어를 제공하려면 mutual TLS와 fine-grained access policies(세분화된 엑세스 정책)이 필요합니다.
- 누가 몇 시에 무엇을 했는지 확인하려면 auditing tools이 필요합니다.

Istio Security 목표

Istio 보안 기능은 강력한 신원 관리, 강력한 정책, 투명한 TLS 암호화, 그리고 인증, 권한 부여, 감사(AAA) 도구를 제공하여 서비스와 데이터를 보호합니다. 

- 기본 보안 설정: 애플리케이션 코드나 인프라를 변경할 필요가 없습니다.
- 심층 방어: 기존 보안 시스템과 통합하여 여러 층의 보안을 제공합니다.
- Zero-trust network: 신뢰할 수 없는 네트워크에서 보안 솔루션 구축할 수 있습니다.

제로 트러스트 네트워크(Zero-Trust Network)
전통적인 네트워크 보안 모델과는 다른 접근 방식을 취하는 개념입니다. 기존 보안 모델은 네트워크 내부는 신뢰할 수 있다고 가정하고 외부에서 들어오는 트래픽만 주로 방어하는 방식이었습니다. 그러나 제로 트러스트 모델에서는 내부와 외부를 불문하고 모든 트래픽과 사용자, 기기에 대해 기본적으로 신뢰하지 않는다는 전제를 세웁니다.

구성 요소

 

key와 인증서 관리를 위한 인증 기관(CA)이 존재하며, API server는 Proxy에 authentication policies(인증 정책),
authorization policies(인가 정책), secure naming information(보안 네이밍 규칙)에 대한 설정을 담당하며, sidecar 및 perimeter proxies는 클라이언트와 서버 간의 통신을 보호하기 위한 정책 집행 지점(PEP) 역할을 합니다. 마지막으로  telemetry와 감사를 관리하기 위한 Envoy proxy extensions이 존재합니다. 또한, Control Plane은 API 서버로부터 설정을 받아 Data Plane의 PEP를 구성하며, PEP는 Envoy를 사용해 구현됩니다. 

 

Identity 및 certificate 관리

Istio는 X.509 인증서를 사용해 각 워크로드에 강력한 identities를 안전하게 할당합니다. 각 Envoy 프록시 옆에서 실행되는 Istio agent는 istiod와 협력하여 대규모로 key와 certificate의 교체를 자동으로 처리합니다. 

https://istio.io/latest/docs/concepts/security/#pki

 

1.  istiod는 gRPC 서비스를 통해 인증서 서명 요청(Certificate Signing Requests|CSR)을 처리합니다.
2. Istio 에이전트는 시작 시 비공개 키와 CSR을 생성하고, its credentials(자격 증명)과 함께 CSR을 istiod에 보내 서명을 요청합니다.
3. istiod의 인증 기관(CA)은 CSR에 포함된 자격 증명을 검증합니다. 검증이 성공하면, CSR에 서명하여 인증서를 생성합니다.
4. 워크로드가 시작되면, Envoy는 Envoy secret discovery service (SDS)API를 통해 동일한 컨테이너 내의 Istio agent에게 인증서와 키를 요청합니다. (UNIX 통신)
5. Istio agent는 istiod로부터 받은 인증서와 비공개 키를 Envoy에 Envoy SDS API를 통해 전달합니다.
6. Istio 에이전트는 워크로드 인증서의 만료되는 것을 모니터링하고, 위 과정이 주기적으로 반복되어 인증서와 키를 갱신합니다.

Authentication architecture

https://istio.io/latest/docs/concepts/security/#authentication-architecture

 

Istio Mesh에서 요청을 받는 워크로드에 대해 인증(authentication) 요구 사항을 지정할 수 있으며, 이는 피어(peer) 인증 정책과 요청(request) 인증 정책을 사용하여 설정할 수 있습니다. mesh operator uses(메쉬 운영자)는 .yaml 파일을 사용해 이러한 정책을 배포하면 해당 정책은 Istio configuration storage에 저장됩니다. 그리고 이를 Istio controller가 지속적으로 모니터링합니다.


만약, 정책이 변경되면 새로운 정책은 필요한 authentication mechanisms(인증 메커니즘)을 PEP(정책 집행 지점)에게 어떻게 수행할지 알려주는 적절한 설정으로 수정됩니다. Control Plane은 JWT 검증을 위해 공개 키를 가져와 설정에 첨부하거나 Istiod가 키와 인증서 경로를 제공하고 이를 mTLS를 통해 애플리케이션 Pod에 설치할 수도 있습니다. 
즉, Istio는 구성이 변경된 사항을 targeted endpoints(대상 엔드포인트)에 비동기적으로 전송합니다. 이에 따라 Proxy가 새로운 configuration을 받으면, 해당 Pod에서 새로운 인증 요구 사항이 즉시 적용됩니다.

요청을 보내는 클라이언트 서비스는 필요한 인증 메커니즘을 준수해야 합니다. authentication 요청의 경우, 애플리케이션이 JWT 자격 증명을 획득하고 이를 요청에 사용해야 하는 책임이 있습니다. peer authentication의 경우, Istio는 두 PEP 간의 모든 트래픽을 자동으로mTLS로 연결합니다.

Authorization architecture

https://istio.io/latest/docs/concepts/security/#authorization-architecture

 

 

Authorization policy은 authorization engine을 통해 서버 측 Envoy 프록시에서 들어오는 트래픽에 대한 접근 제어를 강제로 진행합니다. 각 Envoy 프록시는 런타임에 요청을 승인하는 권한 부여 엔진을 실행하는데, 요청이 프록시에 도착하면 authorization engine은 요청의 컨텍스트를 현재 권한 부여 정책과 비교하여 평가하고, 허용(ALLOW) 또는 거부(DENY)를 반환합니다. 이 모든 걸 운영자는 .yaml 파일을 사용하여 Istio 권한 부여 정책을 정의합니다.

 

트래픽 흐름

https://jimmysong.io/en/blog/sidecar-injection-iptables-and-traffic-routing/

 

1) [파드 내부] Client PC → Istio IngressGateway 파드 구간

컨테이너에서 외부 웹서버로 요청합니다.

2) [파드 내부] IPTables → Istio-proxy 컨테이너 인입

파드 내 IPTables Chains/Rules 적용 (NAT 테이블)에서 'Istio-proxy 컨테이너'로 인입됩니다.

3)  [파드 내부] Istio-proxy 컨테이너 → Node의 호스트 네임스페이스

'Istio-proxy 컨테이너' 는 대리인(Proxy) 역할로, 출발지 포트를 변경(+2) 후 외부 웹서버에 연결합니다. 이때, 파드를 빠져나가기 전에 다시 한번 더 IPTables 적용됩니다. 이때, 이전 트래픽과 매칭되는 Rule 이 다른 것은 UID 1337 때문입니다.

4)  Node → 외부

노드에 SNAT(masquerading) 설정이 되어 있을 경우, 출발지 IP 를 노드의 NIC IP로 변환하여 외부 웹서버에 요청을 전달합니다. 

5) 외부 웹서버(리턴 트래픽) → 파드

웹 서버에서 리턴 트래픽이 파드에 돌아오는 과정은 1.2 에서 알아본 흐름과 유사합니다. 다만, 파드 내로 인입 시 목적지 포트(+2) 이므로, '애플리케이션 컨테이너’ 로 바로 가지 않고, 'Istio-proxy 컨테이너' 로 먼저 가게 됩니다.

 

트래픽 흐름 정리

즉, Istio에서 애플리케이션 컨테이너가 외부로 트래픽을 보낼 때 먼저 Pod 내에서 iptables 규칙이 적용됩니다. 이 규칙은 애플리케이션 컨테이너의 트래픽을 istio-proxy(Envoy 사이드카) 컨테이너로 리다이렉트하는 역할을 합니다. istio-proxy는 전달받은 트래픽을 처리하며, 설정된 정책에 따라 로드 밸런싱, 라우팅 등을 수행합니다. 이후, 트래픽의 포트를 변경(+2)하여 외부 서비스로 연결을 시도합니다. Pod를 나가기 전에 한 번 더 iptables 규칙이 적용되어 트래픽이 올바르게 처리되고 있는지 확인한 후, Node에 도달하면 SNAT(Source Network Address Translation)이 적용됩니다. 이 과정에서 트래픽의 출발지 IP는 Pod의 IP에서 Node의 IP로 변환됩니다.(이를 통해 외부 서비스는 Node의 IP를 출발지 IP로 인식하게 됩니다.)

 

외부에서 들어온 트래픽이 Pod에 도달하면 iptables 규칙이 적용되어 애플리케이션 컨테이너로 바로 전달되지 않고, 먼저 istio-proxy 컨테이너로 리다이렉트됩니다. istio-proxy는 Inbound 트래픽을 처리하며, 정책에 따라 보안, 모니터링, 트래픽 제어 등의 작업을 수행합니다. 이후 istio-proxy는 트래픽을 처리한 후 애플리케이션 컨테이너로 전달합니다. 이때, istio-proxy가 생성한 트래픽은 무한 루프를 방지하기 위해 다시 istio-proxy로 리다이렉트되지 않아야 하기에 iptables는 트래픽의 UID를 확인하고, UID가 1337인 경우 해당 트래픽을 외부로 바로 내보냅니다.

 

728x90

'스터디 이야기 > Kubernetes Advanced Networking Study' 카테고리의 다른 글

[KANS] Gateway API  (1) 2024.10.12
[KANS] Ingress  (2) 2024.10.09
[KANS] Service - LoadBalancer (MetalLB)  (1) 2024.10.04
[KANS] Service - ClusterIP, NodePort  (1) 2024.09.28