Istio Hands-on Study - 9주차 Ambient Mesh

김성중·2025년 6월 2일

Istio Hands-on Study

목록 보기
10/10

가시다(gasida) 님이 진행하는 Istio Hands-on Study 1기 과정을 참여하여 정리한 글입니다.
9주차는 Ambient Mesh 주제로 학습을 하였습니다.

Ambient Mesh를 EKS v1.32와 Istio v1.26.1 환경에서 실습한 내용을 정리하였습니다.
(ingress-gateway 대신 Gateway API로 ALB 이용)

Istio Ambients는

개요

  • Ambient 모드에서 Istio는 노드마다 배포되는 L4(레이어 4) 프록시와, 선택적으로 네임스페이스마다 배포되는 L7(레이어 7) 프록시를 사용하여 기능을 구현합니다.

  • 이러한 계층적 접근 방식은 Istio를 점진적으로 도입할 수 있도록 해주며, 메쉬가 없는 상태에서 시작해 보안이 적용된 L4 오버레이를 거쳐, 필요에 따라 네임스페이스 단위로 L7 처리 및 정책 적용까지 원활하게 전환할 수 있게 합니다.

  • 또한, 서로 다른 Istio 데이터 플레인 모드에서 실행 중인 워크로드 간에도 원활하게 상호 운용이 가능하므로, 사용자는 시간이 지나며 요구 사항이 변화함에 따라 다양한 기능을 조합해 사용할 수 있습니다.

  • 워크로드 파드에 더 이상 사이드카로 실행되는 프록시가 필요하지 않기 때문에, ambient 모드는 비공식적으로 “사이드카 없는 메쉬(sidecar-less mesh)”라고 불리기도 합니다.

작동 방식

  • Ambient 모드는 Istio의 기능을 두 개의 명확한 계층으로 분리합니다.

  • 기본 계층에서는 ztunnel 보안 오버레이가 트래픽의 라우팅과 제로 트러스트 보안을 처리합니다.

  • 그 위의 계층에서는 필요할 경우 L7 웨이포인트 프록시(waypoint proxy)를 활성화하여 Istio의 전체 기능을 사용할 수 있습니다. 웨이포인트 프록시는 ztunnel만 사용하는 경우보다 무겁지만, 여전히 인프라의 ambient 구성 요소로 실행되며, 애플리케이션 파드에는 어떠한 수정도 필요하지 않습니다.

사이드카 모드를 사용하는 파드 및 워크로드는 ambient 모드를 사용하는 파드와 동일한 메쉬 내에서 공존할 수 있습니다.
“Ambient 메쉬”라는 용어는 ambient 모드를 지원하도록 설치된 Istio 메쉬를 의미하며, 사이드카 방식 또는 ambient 방식 중 어느 데이터 플레인 방식이든 사용하는 메쉬 파드를 지원할 수 있습니다.

Ambient 모드의 설계 및 Istio 컨트롤 플레인과의 상호 작용에 대한 자세한 내용은 데이터 플레인컨트롤 플레인 아키텍처 문서를 참고하세요.

ztunnel

  • ztunnel(Zero Trust tunnel) 컴포넌트는 Istio의 Ambient 데이터 플레인 모드를 구동하는, 노드마다 배포되는 특수 목적의 프록시입니다.

  • ztunnel은 메쉬 내에서 워크로드 간의 보안 연결 및 인증을 담당합니다.
    ztunnel 프록시는 Rust로 작성되었으며, mTLS, 인증, L4 권한 부여, 텔레메트리 등 L3 및 L4 기능만을 처리하도록 설계되었습니다.
    ztunnel은 워크로드의 HTTP 트래픽을 종료하거나 HTTP 헤더를 파싱하지 않습니다.
    ztunnel은 L3 및 L4 트래픽이 워크로드, 다른 ztunnel 프록시, 또는 웨이포인트 프록시로 효율적이고 안전하게 전송되도록 보장합니다.

  • 보안 오버레이(secure overlay)”라는 용어는 ambient 메쉬에서 ztunnel 프록시를 통해 구현되는 L4 네트워크 기능 집합을 통칭합니다.
    이 전송 계층은 HBONE(HTTP-Based Overlay Network Environment)이라 불리는 HTTP CONNECT 기반의 트래픽 터널링 프로토콜로 구현됩니다.

Waypoint proxies

  • 웨이포인트 프록시(Waypoint Proxy)는 Istio의 사이드카 데이터 플레인 모드에서도 사용하는 Envoy 프록시를 기반으로 한 배포 방식입니다.

  • 웨이포인트 프록시는 애플리케이션 파드 외부에서 실행되며, 애플리케이션과 독립적으로 설치, 업그레이드, 확장할 수 있습니다.

  • 일부 Ambient 모드 사용 사례는 L4 보안 오버레이 기능만으로 충분하며, 이 경우 L7 기능이 필요 없기 때문에 웨이포인트 프록시를 배포하지 않아도 됩니다.
    반면, 고급 트래픽 관리 및 L7 네트워크 기능이 필요한 경우에는 웨이포인트 프록시의 배포가 필요합니다.

애플리케이션 배포 사용 사례Ambient 모드 구성
상호 TLS를 통한 제로 트러스트 네트워킹,
클라이언트 애플리케이션 트래픽의 암호화 및 터널링 전송,
L4 권한 부여, L4 텔레메트리
ztunnel만 사용 (기본값)
위 기능에 더해 고급 Istio 트래픽 관리 기능
(L7 권한 부여, 텔레메트리, VirtualService 기반 라우팅 포함)
ztunnel + 웨이포인트 프록시 사용

시작하기

Istio 설치 & 샘플어플리케이션 배포

Istio CLI 다운로드

  • Istio는 istioctl이라는 명령줄 도구를 사용하여 설정합니다. 이 도구와 샘플 애플리케이션을 다운로드하세요:
$ curl -L https://istio.io/downloadIstio | sh -
$ cd istio-1.26.1
$ export PATH=$PWD/bin:$PATH
  • istioctl 명령어가 정상 작동하는지 버전을 출력하여 확인하세요.
    이 시점에서는 아직 클러스터에 Istio가 설치되지 않았기 때문에, 실행 중인 Istio 파드가 없다는 메시지를 보게 됩니다:
$ istioctl version
Istio is not present in the cluster: no running Istio pods in namespace "istio-system"
client version: 1.26.1

클러스터에 Istio 설치방법

  • 본 실습에서는 Terraform에서 Helm으로 배포하였습니다. 아래 내용은 참고하세요
  • istioctl은 여러 구성 프로파일을 지원하며, 각기 다른 기본 옵션을 포함합니다.
  • Ambient 모드를 위한 지원은 ambient 프로파일에 포함되어 있습니다.
  • 다음 명령어로 Istio를 설치하세요:
$ istioctl install --set profile=ambient --skip-confirmation

설치가 완료되면 다음과 같은 출력 결과를 통해 모든 컴포넌트가 성공적으로 설치되었음을 확인할 수 있습니다:

✔ Istio core installed
✔ Istiod installed
✔ CNI installed
✔ Ztunnel installed
✔ Installation complete

Kubernetes Gateway API CRD 설치

  • 트래픽 라우팅을 구성하기 위해 Kubernetes Gateway API를 사용할 것입니다.
  • 대부분의 Kubernetes 클러스터에서는 Gateway API CRD가 기본적으로 설치되어 있지 않으므로, 다음 명령어로 설치되어 있는지 확인하고, 없을 경우 설치하세요:
$ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml

Terraform으로 EKS 생성 & Istio 배포

  • 소스 복제
git clone https://github.com/aws-samples/istio-on-eks.git
cd istio-on-eks/terraform-blueprint/ambient 
  • 소스 수정(선택)
# main.tf 수정 (서울리전, 노드스펙다운)
locals {
  name   = "istio-sejkim"             # basename(path.cwd)
  region = "ap-northeast-2"           # us-west-2
...
  eks_managed_node_groups = {
    ng-sejkim = {                     # initial = {
      instance_types = ["t3.medium"]  # ["m5.large"]
      min_size     = 2                # 1
      max_size     = 5
      desired_size = 2                      
...

# main.tf 수정 (추후 gateway-api 배포 위해 istio-ingress는 주석처리)
    # istio-ingress = {
    #   chart            = "gateway"
    #   chart_version    = local.istio_chart_version
    #   repository       = local.istio_chart_url
    #   name             = "istio-ingress"
    #   namespace        = "istio-ingress" # per https://github.com/istio/istio/blob/master/manifests/charts/gateways/istio-ingress/values.yaml#L2
    #   create_namespace = true

    #   values = [
    #     yamlencode(
    #       {
    #         labels = {
    #           istio = "ingressgateway"
    #         }
    #         service = {
    #           annotations = {
    #             "service.beta.kubernetes.io/aws-load-balancer-type"            = "external"
    #             "service.beta.kubernetes.io/aws-load-balancer-nlb-target-type" = "ip"
    #             "service.beta.kubernetes.io/aws-load-balancer-scheme"          = "internet-facing"
    #             "service.beta.kubernetes.io/aws-load-balancer-attributes"      = "load_balancing.cross_zone.enabled=true"
    #           }
    #         }
    #       }
    #     )
    #   ]
    # }
  • Terraform 코드 실행
❯ terraform apply -target='module.vpc' -auto-approve
❯ terraform apply -target='module.eks' -auto-approve
❯ aws eks --region ap-northeast-2 update-kubeconfig --name istio-sejkim
❯ terraform apply -target='module.eks_blueprints_addons' -auto-approve
❯ terraform apply -auto-approve
  • 배포 내용 확인
# eks 1.32
❯ kubectl get nodes -o wide
NAME                                             STATUS   ROLES    AGE     VERSION               INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                       KERNEL-VERSION                    CONTAINER-RUNTIME
ip-10-0-27-246.ap-northeast-2.compute.internal   Ready    <none>   9m46s   v1.32.3-eks-473151a   10.0.27.246   <none>        Amazon Linux 2023.7.20250512   6.1.134-152.225.amzn2023.x86_64   containerd://1.7.27
ip-10-0-40-177.ap-northeast-2.compute.internal   Ready    <none>   9m45s   v1.32.3-eks-473151a   10.0.40.177   <none>        Amazon Linux 2023.7.20250512   6.1.134-152.225.amzn2023.x86_64   containerd://1.7.27

❯ terraform state list | grep helm 
module.eks_blueprints_addons.helm_release.this["istio-base"]
module.eks_blueprints_addons.helm_release.this["istio-cni"]
module.eks_blueprints_addons.helm_release.this["istiod"]
module.eks_blueprints_addons.helm_release.this["ztunnel"]
module.eks_blueprints_addons.module.aws_load_balancer_controller.helm_release.this[0]

# istio 1.26.1, istio-ingress gateway는 설치 안함)
❯ helm -n istio-system list
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
istio-base      istio-system    1               2025-06-03 12:37:09.922264 +0900 KST    deployed        base-1.26.1     1.26.1     
istio-cni       istio-system    1               2025-06-03 12:37:07.079489 +0900 KST    deployed        cni-1.26.1      1.26.1     
istiod          istio-system    1               2025-06-03 12:37:02.573573 +0900 KST    deployed        istiod-1.26.1   1.26.1     
ztunnel         istio-system    1               2025-06-03 12:37:04.649074 +0900 KST    deployed        ztunnel-1.26.1  1.26.1 

❯ kubectl get pod,svc,ep -n istio-system
NAME                          READY   STATUS    RESTARTS   AGE
pod/istio-cni-node-b2cgm      1/1     Running   0          7m51s
pod/istio-cni-node-qz65k      1/1     Running   0          7m51s
pod/istiod-7d56d75f5b-pxq6n   1/1     Running   0          7m54s
pod/ztunnel-4vr7d             1/1     Running   0          7m53s
pod/ztunnel-7wstc             1/1     Running   0          7m53s

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                                 AGE
service/istiod   ClusterIP   172.20.142.108   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP   7m54s

NAME               ENDPOINTS                                                           AGE
endpoints/istiod   10.0.42.144:15012,10.0.42.144:15010,10.0.42.144:15017 + 1 more...   7m54s
  • Kubernetes Gateway API CRDs 배포
❯ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml

customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io created
customresourcedefinition.apiextensions.k8s.io/gateways.gateway.networking.k8s.io created
customresourcedefinition.apiextensions.k8s.io/grpcroutes.gateway.networking.k8s.io created
customresourcedefinition.apiextensions.k8s.io/httproutes.gateway.networking.k8s.io created
customresourcedefinition.apiextensions.k8s.io/referencegrants.gateway.networking.k8s.io created

# istio resouce 확인
❯ kubectl api-resources | grep istio
wasmplugins                                      extensions.istio.io/v1alpha1        true         WasmPlugin
destinationrules                    dr           networking.istio.io/v1              true         DestinationRule
envoyfilters                                     networking.istio.io/v1alpha3        true         EnvoyFilter
gateways                            gw           networking.istio.io/v1              true         Gateway
proxyconfigs                                     networking.istio.io/v1beta1         true         ProxyConfig
serviceentries                      se           networking.istio.io/v1              true         ServiceEntry
sidecars                                         networking.istio.io/v1              true         Sidecar
virtualservices                     vs           networking.istio.io/v1              true         VirtualService
workloadentries                     we           networking.istio.io/v1              true         WorkloadEntry
workloadgroups                      wg           networking.istio.io/v1              true         WorkloadGroup
authorizationpolicies               ap           security.istio.io/v1                true         AuthorizationPolicy
peerauthentications                 pa           security.istio.io/v1                true         PeerAuthentication
requestauthentications              ra           security.istio.io/v1                true         RequestAuthentication
telemetries                         telemetry    telemetry.istio.io/v1               true         Telemetry

# gateway class
❯ kubectl get gatewayclasses.gateway.networking.k8s.io
NAME             CONTROLLER                    ACCEPTED   AGE
istio            istio.io/gateway-controller   True       3h11m
istio-remote     istio.io/unmanaged-gateway    True       3h11m
istio-waypoint   istio.io/mesh-controller      True       3h11m

샘플 어플리케이션 배포

Bookinfo application

  • To explore Istio, I will install the sample Bookinfo application, composed of four separate microservices used to demonstrate various Istio features.
❯ kubectl create namespace bookinfo
namespace/bookinfo created

❯ kubectl apply -f https://raw.githubusercontent.com/istio/istio/master/samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo

❯ kubectl apply -f https://raw.githubusercontent.com/istio/istio/master/samples/bookinfo/platform/kube/bookinfo-versions.yaml -n bookinfo

❯ kubectl get pods -n bookinfo
NAME                              READY   STATUS    RESTARTS   AGE
productpage-v1-54bb874995-h9tvr   1/1     Running   0          3m33s
details-v1-766844796b-smp85       1/1     Running   0          3m34s
reviews-v1-598b896c9d-t9n2j       1/1     Running   0          3m34s
reviews-v2-556d6457d-ccfc6        1/1     Running   0          3m34s
reviews-v3-564544b4d6-f978n       1/1     Running   0          3m34s
ratings-v1-5dc79b6bcd-w96zf       1/1     Running   0          3m34s
  • Gateway, httpRoutes 배포 (Internet-facing ALB 생성, 개인도메인과 ACM 적용)
cat <<EOF > gateway-httproute-bookinfo.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: bookinfo-gateway
  namespace: bookinfo
  annotations:
    external-dns.alpha.kubernetes.io/hostname: "bookinfo.ksj7279.click"
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" 
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
    service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-Ext-2018-06"
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:ap-northeast-2:1**********3:certificate/415404eb-e2e2-4744-b2e4-1108735b5903" 
spec:
  gatewayClassName: istio 
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: Same
    - name: https
      port: 443
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bookinfo
  namespace: bookinfo
spec:
  parentRefs:
    - name: bookinfo-gateway
  hostnames:
    - "bookinfo.ksj7279.click"
  rules:
    - matches:
        - path:
            type: Exact
            value: /productpage
        - path:
            type: PathPrefix
            value: /static
        - path:
            type: Exact
            value: /login
        - path:
            type: Exact
            value: /logout
        - path:
            type: PathPrefix
            value: /api/v1/products
      backendRefs:
        - name: productpage
          port: 9080
EOF

❯ kubectl apply -f gateway-httproute-bookinfo.yaml
gateway.gateway.networking.k8s.io/istio-gateway created
httproute.gateway.networking.k8s.io/bookinfo created

❯ kubectl -n bookinfo get gtw,httproute
NAME                                              CLASS   ADDRESS                                                                              PROGRAMMED   AGE
gateway.gateway.networking.k8s.io/istio-gateway   istio   k8s-bookinfo-istiogat-fbc8749077-dda4c1959031124a.elb.ap-northeast-2.amazonaws.com   True         6m3s

NAME                                           HOSTNAMES                    AGE
httproute.gateway.networking.k8s.io/bookinfo   ["bookinfo.ksj7279.click"]   6m3s

❯ kubectl -n bookinfo get svc | grep gateway
bookinfo-gateway-istio   LoadBalancer   172.20.27.47     k8s-bookinfo-istiogat-fbc8749077-dda4c1959031124a.elb.ap-northeast-2.amazonaws.com   15021:31898/TCP,80:31258/TCP,443:31608/TCP   6m57s

# Gateway LB IP 확인 및 /etc/hosts에 추가
LB_IP=`dig k8s-bookinfo-istiogat-fbc8749077-dda4c1959031124a.elb.ap-northeast-2.amazonaws.com +short`echo "$LB_IP bookinfo.ksj7279.click" | sudo tee -a /etc/hosts
43.202.125.139 bookinfo.ksj7279.click

# 어플리케이션 접속curl -I https://bookinfo.ksj7279.click/productpage
HTTP/1.1 200 OK
server: istio-envoy
date: Tue, 03 Jun 2025 07:30:02 GMT
content-type: text/html; charset=utf-8
content-length: 15070
vary: Cookie
x-envoy-upstream-service-time: 165

# 반복 호출for i in $(seq 1 10000); do curl -sSI -o /dev/null https://bookinfo.ksj7279.click/productpage; done
or 
watch -n 1000 'curl -o /dev/null -s -w "%{http_code}\n" https://bookinfo.ksj7279.click/productpage'
  • Application LoadBalancer 화면

  • bookinfo 어플리케이션 웹접속 화면

  • Kiali 접속

❯ kubectl port-forward svc/kiali 20001:20001 -n istio-system &open http://localhost:20001  ## 아직 Kiali 화면에선 bookinfo 보이지 않음

어플리케이션 보호 & 시각화

  • 애플리케이션을 Ambient Mesh에 추가하는 것은 애플리케이션이 있는 네임스페이스에 라벨을 추가하는 것만큼 간단합니다.
  • 애플리케이션을 메시에 추가하면, 애플리케이션 간 통신이 자동으로 보호되고 Istio가 TCP 텔레메트리를 수집하기 시작합니다.
  • 그리고 애플리케이션을 재시작하거나 재배포할 필요도 없습니다!

Bookinfo 애플리케이션을 Mesh에 추가

  • 특정 네임스페이스에 있는 모든 파드를 Ambient Mesh에 포함시키려면, 단순히 네임스페이스에 라벨을 추가하면 됩니다:
❯ kubectl label namespace bookinfo istio.io/dataplane-mode=ambient
namespace/bookinfo labeled
  • 🎉 이제 bookinfo 네임스페이스에 있는 모든 파드가 재배포 없이 Ambient Mesh에 성공적으로 추가되었습니다.

  • 브라우저에서 Bookinfo 애플리케이션을 열면 이전과 마찬가지로 제품 페이지가 나타납니다.
    하지만 이번에는 Bookinfo 애플리케이션의 파드 간 통신이 mTLS를 사용해 암호화된다는 점이 다릅니다.
    또한, Istio가 파드 간 모든 트래픽에 대해 TCP 텔레메트리를 수집하고 있습니다.

    이제 모든 파드 간에 mTLS 암호화가 적용되었습니다 — 애플리케이션을 재시작하거나 재배포하지도 않았는데 말이죠!

어플리케이션과 메트릭 시각화

Observability Add-ons 배포

  • Istio Observability Add-ons on the EKS cluster with deployed Istio.
for ADDON in kiali jaeger prometheus grafana
do
    ADDON_URL="https://raw.githubusercontent.com/istio/istio/release-1.22/samples/addons/$ADDON.yaml"
    kubectl apply -f $ADDON_URL
done
  • 확인
❯ kubectl get pods,svc -n istio-system
NAME                              READY   STATUS    RESTARTS   AGE
pod/grafana-bdbb6d879-2fm82       1/1     Running   0          119s
pod/istio-cni-node-b2cgm          1/1     Running   0          30m
pod/istio-cni-node-qz65k          1/1     Running   0          30m
pod/istiod-7d56d75f5b-pxq6n       1/1     Running   0          30m
pod/jaeger-7b5f69d965-tm7m5       1/1     Running   0          2m3s
pod/kiali-9968cd59d-hxwmx         1/1     Running   0          2m4s
pod/prometheus-644fc9cd87-sxwcp   2/2     Running   0          2m1s
pod/ztunnel-4vr7d                 1/1     Running   0          30m
pod/ztunnel-7wstc                 1/1     Running   0          30m

NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                                          AGE
service/grafana            ClusterIP   172.20.139.227   <none>        3000/TCP                                         119s
service/istiod             ClusterIP   172.20.142.108   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP            30m
service/jaeger-collector   ClusterIP   172.20.196.135   <none>        14268/TCP,14250/TCP,9411/TCP,4317/TCP,4318/TCP   2m2s
service/kiali              ClusterIP   172.20.209.215   <none>        20001/TCP,9090/TCP                               2m4s
service/prometheus         ClusterIP   172.20.140.100   <none>        9090/TCP                                         2m1s
service/tracing            ClusterIP   172.20.132.226   <none>        80/TCP,16685/TCP                                 2m3s
service/zipkin             ClusterIP   172.20.39.168    <none>        9411/TCP                                         2m3s
# Visualize Istio Mesh console using Kiali
kubectl port-forward svc/kiali 20001:20001 -n istio-system
open http://localhost:20001

# Get to the Prometheus UI
kubectl port-forward svc/prometheus 9090:9090 -n istio-system

# Visualize metrics in using Grafana
kubectl port-forward svc/grafana 3000:3000 -n istio-system

# Visualize application traces via Jaeger
kubectl port-forward svc/tracing 16686:80 -n istio-system
  • 대시보드에서 두 서비스 사이를 연결하는 선을 클릭하면, Istio가 수집한 인바운드 및 아웃바운드 트래픽 메트릭을 확인할 수 있습니다. mTLS 활성화됨
  • TCP 메트릭 외에도 Istio는 각 서비스에 대해 강력한 ID인 SPIFFE ID를 생성했습니다.
    이 ID는 인가 정책(Authorization Policy)을 생성할 때 사용할 수 있습니다.

인가 정책을 적용

  • 애플리케이션을 Ambient Mesh에 추가한 후에는 L4(레이어 4) 인가 정책을 사용하여 애플리케이션 접근을 보호할 수 있습니다.

  • 이 기능을 통해 메시에 있는 모든 워크로드에 자동으로 발급되는 클라이언트 워크로드 ID를 기반으로, 서비스에 대한 들어오고 나가는 트래픽에 대한 접근 제어를 설정할 수 있습니다.

Layer 4 인가 정책을 적용

  • productpage 서비스와 통신할 수 있는 서비스를 제한하는 인가 정책을 만들어 보겠습니다.
  • 이 정책은 app: productpage 라벨이 붙은 파드에 적용되며, cluster.local/ns/bookinfo/sa/bookinfo-gateway-istio 서비스 계정에서만 호출을 허용합니다.
    해당 서비스 계정은 이전 단계에서 배포한 Bookinfo 게이트웨이가 사용하는 서비스 계정입니다.
❯ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: productpage-ztunnel
  namespace: bookinfo
spec:
  selector:
    matchLabels:
      app: productpage
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/bookinfo/sa/bookinfo-gateway-istio
EOF
authorizationpolicy.security.istio.io/productpage-ztunnel created
  • 브라우저에서 Bookinfo 애플리케이션(https://bookinfo.ksj7279.click/productpage)을 열면 이전과 마찬가지로 제품 페이지가 표시됩니다.
    하지만, 다른 서비스 계정에서 productpage 서비스에 접근하려고 하면 오류가 발생할 것입니다.

이제 클러스터 내 다른 클라이언트에서 Bookinfo 애플리케이션에 접근해 보겠습니다:

❯ kubectl apply -f samples/curl/curl.yaml
serviceaccount/curl created
service/curl created
deployment.apps/curl created
  • curl 파드는 다른 서비스 계정을 사용하기 때문에 productpage 서비스에 접근할 수 없습니다:
❯ kubectl exec deploy/curl -- curl -sv "http://productpage.bookinfo:9080/productpage"
* Host productpage.bookinfo:9080 was resolved.
* IPv6: (none)
* IPv4: 172.20.220.161
*   Trying 172.20.220.161:9080...
* Connected to productpage.bookinfo (172.20.220.161) port 9080
* using HTTP/1.x
> GET /productpage HTTP/1.1
> Host: productpage.bookinfo:9080
> User-Agent: curl/8.13.0
> Accept: */*
> 
* Request completely sent off
* Recv failure: Connection reset by peer
* closing connection #0
command terminated with exit code 56
  • 위 명령어로 다른 서비스 계정을 사용하는 파드에서 productpage 서비스에 요청을 보내서 접근 제한이 제대로 동작하는지 확인할 수 있습니다.
  • 응답 코드가 403 Forbidden (Recv failure: Connection reset by peer) 등으로 나오면 인가 정책이 잘 적용된 것입니다.

Layer 7 인가 정책을 적용

  • Layer 7 인가 정책을 적용하려면, 먼저 해당 네임스페이스에 Waypoint 프록시를 생성해야 합니다.
    이 프록시는 해당 네임스페이스로 들어오는 모든 Layer 7 트래픽을 처리합니다.
❯ istioctl waypoint apply --enroll-namespace -n bookinfo --wait
✅ waypoint bookinfo/waypoint applied
✅ waypoint bookinfo/waypoint is ready!
✅ namespace bookinfo labeled with "istio.io/use-waypoint: waypoint"

❯ kubectl get ns --show-labels
NAME              STATUS   AGE     LABELS
bookinfo          Active   3h57m   istio.io/dataplane-mode=ambient,istio.io/use-waypoint=waypoint,kubernetes.io/metadata.name=bookinfo
default           Active   7h15m   kubernetes.io/metadata.name=default
istio-system      Active   7h6m    kubernetes.io/metadata.name=istio-system
kube-node-lease   Active   7h15m   kubernetes.io/metadata.name=kube-node-lease
kube-public       Active   7h15m   kubernetes.io/metadata.name=kube-public
kube-system       Active   7h15m   kubernetes.io/metadata.name=kube-system
  • Waypoint 프록시를 확인하고, 상태가 Programmed=True인지 확인할 수 있습니다:
❯  kubectl get gtw waypoint -n bookinfo
NAME       CLASS            ADDRESS         PROGRAMMED   AGE
waypoint   istio-waypoint   172.20.236.17   True         110s
  • L7 인가 정책을 추가하면 curl 서비스가 productpage 서비스에 대해 GET 요청만 허용되고, 그 외의 작업은 수행할 수 없도록 명시적으로 제어할 수 있습니다.

예시 정책은 다음과 같습니다:

❯  kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: productpage-waypoint
  namespace: bookinfo
spec:
  targetRefs:
  - kind: Service
    group: ""
    name: productpage
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/default/sa/curl
    to:
    - operation:
        methods: ["GET"]
EOF
authorizationpolicy.security.istio.io/productpage-waypoint created
  • targetRefs 필드는 Waypoint 프록시에 대한 인가 정책에서 대상 서비스를 지정할 때 사용됩니다.
    rules 섹션은 이전과 유사하지만, 이번에는 to 섹션이 추가되어 허용할 연산(operation)을 명시하고 있습니다.

  • 기억하시죠?
    이전에 설정한 L4 인가 정책은 ztunnel이 게이트웨이에서 오는 연결만 허용하도록 설정되어 있었습니다.
    이제 Waypoint 프록시도 productpage 서비스에 연결할 수 있도록 L4 정책을 업데이트해야 합니다.

❯  kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: productpage-ztunnel
  namespace: bookinfo
spec:
  selector:
    matchLabels:
      app: productpage
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/bookinfo/sa/bookinfo-gateway-istio
        - cluster.local/ns/bookinfo/sa/waypoint   
EOF
authorizationpolicy.security.istio.io/productpage-ztunnel configured

❯ kubectl -n bookinfo get sa
NAME                     SECRETS   AGE
bookinfo-details         0         4h5m
bookinfo-gateway-istio   0         70m
bookinfo-productpage     0         4h5m
bookinfo-ratings         0         4h5m
bookinfo-reviews         0         4h5m
default                  0         4h6m
waypoint                 0         9m29s
  • Istio의 더 많은 기능들을 활성화하는 방법을 알아보려면, Layer 7 기능 사용자 가이드를 참고하세요.
    이 가이드는 라우팅, 트래픽 분할, L7 인가, 경로 기반 정책 등 애플리케이션 계층에서 제공하는 다양한 Istio 기능을 사용하는 방법을 자세히 설명합니다.
# This fails with an RBAC error because you're not using a GET operation
❯ kubectl exec deploy/curl -- curl -sv "http://productpage.bookinfo:9080/productpage" -X DELETE

* Host productpage.bookinfo:9080 was resolved.
* IPv6: (none)
* IPv4: 172.20.220.161
*   Trying 172.20.220.161:9080...
* Connected to productpage.bookinfo (172.20.220.161) port 9080
* using HTTP/1.x
> DELETE /productpage HTTP/1.1
> Host: productpage.bookinfo:9080
> User-Agent: curl/8.13.0
> Accept: */*
> 
* abort upload
* Empty reply from server
* shutting down connection #0
command terminated with exit code 52

# This fails with an RBAC error because the identity of the reviews-v1 service is not allowed
❯ kubectl -n bookinfo exec deploy/reviews-v1 -- curl -sv http://productpage.bookinfo:9080/productpage

*   Trying 172.20.220.161:9080...
* Connected to productpage.bookinfo (172.20.220.161) port 9080 (#0)
> GET /productpage HTTP/1.1
> Host: productpage.bookinfo:9080
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 Forbidden
< content-length: 19
< content-type: text/plain
< date: Tue, 03 Jun 2025 10:57:57 GMT
< server: istio-envoy
< x-envoy-decorator-operation: productpage.bookinfo.svc.cluster.local:9080/*
< 
{ [19 bytes data]
RBAC: access denied* Connection #0 to host productpage.bookinfo left intact

# This works as you're explicitly allowing GET requests from the curl pod
❯ kubectl exec deploy/curl -- curl -s http://productpage.bookinfo:9080/productpage | grep -o "<title>.*</title>"* Request completely sent off
* Recv failure: Connection reset by peer
* closing connection #0
command terminated with exit code 56
  • default namespace에 배포된 curl에서도 접속 가능하도록 조치 후 재 테스트
❯ kubectl label namespace default istio.io/dataplane-mode=ambient
namespace/default labeled

❯ kubectl exec deploy/curl -- curl -s http://productpage.bookinfo:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

트래픽 관리

  • 이제 Waypoint 프록시가 설치되었으므로, 서비스 간 트래픽 분할(Traffic Splitting)을 설정하는 방법을 배워보겠습니다.

  • Waypoint 프록시는 레이어 7 트래픽을 처리할 수 있으므로, 특정 조건(예: 비율, 사용자, 쿠키 등)에 따라 트래픽을 여러 백엔드 서비스로 분산할 수 있습니다.

서비스 간 트래픽 분할

  • Bookinfo 애플리케이션에는 reviews 서비스의 세 가지 버전(v1, v2, v3)이 존재합니다.
    이들 간에 트래픽을 분할하면, 새 기능 테스트, 점진적 배포(Canary), A/B 테스트 등을 수행할 수 있습니다.
  • 다음은 reviews 서비스의 트래픽을 v1에 90%, v2에 10%로 라우팅하도록 설정하는 구성입니다.
❯ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
  namespace: bookinfo
spec:
  parentRefs:
  - group: ""
    kind: Service
    name: reviews
    port: 9080
  rules:
  - backendRefs:
    - name: reviews-v1
      port: 9080
      weight: 90
    - name: reviews-v2
      port: 9080
      weight: 10
EOF
httproute.gateway.networking.k8s.io/reviews created

❯ kubectl -n bookinfo get httproutes.gateway.networking.k8s.io
NAME       HOSTNAMES                    AGE
bookinfo   ["bookinfo.ksj7279.click"]   157m
reviews                                 49s

  • 다음 명령어를 실행하면, reviews 서비스에 100번 요청을 보내고 응답 내용을 분석하여 약 10%의 트래픽이 reviews-v2로 전달되었는지 확인할 수 있습니다:
❯ kubectl exec deploy/curl -- sh -c "for i in \$(seq 1 10); do curl -s http://productpage.bookinfo:9080/productpage | grep reviews-v.-; done"

                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v2-556d6457d-jxzf2
                  reviews-v2-556d6457d-jxzf2
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
                  reviews-v1-598b896c9d-4vr6c
  • 대부분의 요청이 reviews-v1으로 전송되는 것을 확인할 수 있습니다. 이를 확인하려면 웹 브라우저에서 Bookinfo 애플리케이션을 열고 페이지를 여러 번 새로 고침해 보세요.
  • reviews-v1에서의 응답에는 별이 표시되지 않으며, reviews-v2에서의 응답에는 검은색 별(★) 이 표시됩니다.

Clean up

  • 더 이상 Istio와 관련 리소스가 필요하지 않다면, 이 섹션의 단계를 따라 삭제할 수 있습니다.

Remove waypoint proxies

❯ kubectl label namespace bookinfo istio.io/use-waypoint-
namespace/bookinfo unlabeled
❯ istioctl waypoint delete --all -n bookinfo
waypoint bookinfo/waypoint deleted

네임스페이스를 Ambient 데이터 플레인에서 제거

  • Istio를 제거하더라도 기본 네임스페이스의 애플리케이션을 자동으로 Ambient Mesh에 포함하도록 지시하는 레이블은 제거되지 않습니다. 다음 명령어를 사용하여 해당 레이블을 제거하세요:
❯ kubectl label namespace default istio.io/dataplane-mode-
namespace/default unlabeled
  • Istio를 제거하기 전에 워크로드를 Ambient 데이터 플레인에서 제거해야 합니다.

샘플어플리케이션 제거

  • Bookinfo 샘플 애플리케이션과 curl 디플로이먼트를 삭제하려면 다음 명령어를 실행하세요:
❯ kubectl delete httproute reviews -n bookinfo
❯ kubectl delete authorizationpolicy productpage-viewer -n bookinfo
❯ kubectl delete -f samples/curl/curl.yaml
❯ kubectl delete -f samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo
❯ kubectl delete -f samples/bookinfo/platform/kube/bookinfo-versions.yaml -n bookinfo
❯ kubectl delete -f samples/bookinfo/gateway-api/bookinfo-gateway.yaml -n bookinfo

istio 삭제

❯ helm -n istio-system list
NAME            NAMESPACE       REVISION        UPDATED                             STATUS          CHART           APP VERSION
istio-base      istio-system    1               2025-06-03 12:37:09.922264 +0900 KSTdeployed        base-1.26.1     1.26.1     
istio-cni       istio-system    1               2025-06-03 12:37:07.079489 +0900 KSTdeployed        cni-1.26.1      1.26.1     
istiod          istio-system    1               2025-06-03 12:37:02.573573 +0900 KSTdeployed        istiod-1.26.1   1.26.1     
ztunnel         istio-system    1               2025-06-03 12:37:04.649074 +0900 KSTdeployed        ztunnel-1.26.1  1.26.1  

❯ helm -n istio-system uninstall ztunnel
release "ztunnel" uninstalled
❯ helm -n istio-system uninstall istio-cni
release "istio-cni" uninstalled
❯ helm -n istio-system uninstall istiod
release "istiod" uninstalled
❯ helm -n istio-system uninstall istio-base
These resources were kept due to the resource policy:
[CustomResourceDefinition] wasmplugins.extensions.istio.io
[CustomResourceDefinition] authorizationpolicies.security.istio.io
[CustomResourceDefinition] peerauthentications.security.istio.io
[CustomResourceDefinition] requestauthentications.security.istio.io
[CustomResourceDefinition] telemetries.telemetry.istio.io
[CustomResourceDefinition] destinationrules.networking.istio.io
[CustomResourceDefinition] envoyfilters.networking.istio.io
[CustomResourceDefinition] gateways.networking.istio.io
[CustomResourceDefinition] proxyconfigs.networking.istio.io
[CustomResourceDefinition] serviceentries.networking.istio.io
[CustomResourceDefinition] sidecars.networking.istio.io
[CustomResourceDefinition] virtualservices.networking.istio.io
[CustomResourceDefinition] workloadentries.networking.istio.io

release "istio-base" uninstalled

❯ istioctl uninstall -y --purge
All Istio resources will be pruned from the cluster
✔ Uninstall complete                                                                                     
❯  kubectl delete namespace istio-system
namespace "istio-system" deleted

Kubernetes Gateway API CRDs 제거

❯ kubectl delete -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml

customresourcedefinition.apiextensions.k8s.io "gatewayclasses.gateway.networking.k8s.io" deleted
customresourcedefinition.apiextensions.k8s.io "gateways.gateway.networking.k8s.io" deleted
customresourcedefinition.apiextensions.k8s.io "grpcroutes.gateway.networking.k8s.io" deleted
customresourcedefinition.apiextensions.k8s.io "httproutes.gateway.networking.k8s.io" deleted
customresourcedefinition.apiextensions.k8s.io "referencegrants.gateway.networking.k8s.io" deleted

Terraform 이용 AWS자원 삭제

❯ terraform destroy -target='module.eks_blueprints_addons' -auto-approve
❯ terraform destroy -target='module.eks' -auto-approve
❯ terraform destroy -target='module.vpc' -auto-approve
❯ terraform destroy -auto-approve

Ambient 적용 준비사항

  • 아래 내용은 Ambient 모드에서 Istio를 설치하기 위한 플랫폼 또는 환경별 사전 요구 사항입니다.

Amazon Elastic Kubernetes Service (EKS)

⛔️ 다음 조건이 모두 해당된다면:

  • Amazon VPC CNI를 사용 중이고
  • Pod ENI 트렁킹(Pod ENI trunking)이 활성화되어 있으며
  • SecurityGroupPolicy를 통해 EKS 파드에 Security Group을 직접 연결하여 사용하는 경우

🆘 다음 설정을 반드시 적용해야 합니다:

POD_SECURITY_GROUP_ENFORCING_MODEstandard명시적으로 설정해야 합니다.
그렇지 않으면 파드의 health probe가 실패합니다.

⁉️ 이유:
Istio는 kubelet health probe를 식별하기 위해 link-local SNAT 주소(예: 169.254.0.0/16)를 사용합니다.
그러나 VPC CNI는 Pod Security Group strict 모드에서 link-local 패킷을 잘못 라우팅합니다.

  • link-local 주소를 Security Group에서 제외(CIDR exclusion)하려 해도 작동하지 않습니다.
  • VPC CNI의 Pod Security Group 모드는 트렁킹된 ENI를 통해 트래픽을 조용히 다른 링크로 전달하고, 그 과정에서 Security Group 정책을 적용합니다.
  • 하지만 link-local 트래픽은 링크 간 라우팅이 불가능하기 때문에, strict 모드에서는 이를 정책적으로 처리하지 못하고 패킷을 드롭(drop) 하게 됩니다.

이 제한 사항에 대해서는 VPC CNI 컴포넌트에 오픈된 이슈(open issue)가 있습니다.

🧑🏻‍💻 현재 권장 사항 (VPC CNI 팀 기준):

  • Pod Security Group을 사용하는 경우
    strict 모드를 비활성화(standard로 설정) 하여 우회하거나
    kubelet 기반 probe 대신 exec 기반 Kubernetes probe를 사용하세요.

확인 방법:
1. Pod ENI 트렁킹 사용 여부 확인:

$ kubectl set env daemonset aws-node -n kube-system --list | grep ENABLE_POD_ENI
  1. 클러스터에서 Pod에 Security Group이 부착되어 있는지 확인:
$ kubectl get securitygrouppolicies.vpcresources.k8s.aws
  1. POD_SECURITY_GROUP_ENFORCING_MODEstandard로 설정하고 관련 파드를 재시작:
$ kubectl set env daemonset aws-node -n kube-system POD_SECURITY_GROUP_ENFORCING_MODE=standard

이 설정 후, 영향을 받는 파드들을 재시작하여 변경 사항을 적용해야 합니다.

Upgrade with Helm

⛔️ 사이드카 모드와 달리, 앰비언트 모드(Ambient mode)에서는 실행 중인 애플리케이션 파드를 강제 재시작이나 재스케줄 없이 업그레이드된 ztunnel 프록시로 전환할 수 있습니다.

하지만 ztunnel을 업그레이드하면 해당 노드에서 유지되던 모든 장기 TCP 연결이 리셋됩니다. 또한 Istio는 현재 ztunnel에 대한 카나리 업그레이드(canary upgrade)를 지원하지 않으며, 리비전(revision)을 사용하더라도 이를 수행할 수 없습니다.

운영 환경에서 ztunnel 업그레이드 시 애플리케이션 트래픽의 영향 범위를 줄이기 위해,
노드 cordon(스케줄링 금지) 또는 블루/그린(blue/green) 노드 풀 전략을 사용하는 것이 권장됩니다.
자세한 내용은 사용 중인 Kubernetes 제공자의 문서를 참고하세요.

  • 모든 Istio 업그레이드는 컨트롤 플레인(Control Plane), 데이터 플레인(Data Plane), Istio CRD(Custom Resource Definition)의 업그레이드를 포함합니다.
    앰비언트(Ambient) 데이터 플레인은 ztunnel과 게이트웨이(waypoint 포함)라는 두 개의 컴포넌트로 분리되어 있으므로, 업그레이드는 이들 각각에 대해 별도의 절차가 필요합니다.

  • 컨트롤 플레인과 CRD 업그레이드는 여기서 간단히 다루지만, 이는 사이드카 모드에서 해당 구성 요소들을 업그레이드하는 절차와 사실상 동일합니다.

  • 사이드카 모드와 마찬가지로, 게이트웨이(waypoint 포함)리비전 태그(revision tag)를 통해 업그레이드에 대한 세밀한 제어 및 롤백이 가능한 방식으로 운영할 수 있습니다.

  • 하지만 사이드카 모드와 달리, ztunnel은 DaemonSet(노드당 1개 프록시) 형태로 동작하므로, ztunnel 업그레이드는 최소한 하나의 전체 노드에 영향을 주게 됩니다.

  • 이러한 방식은 대부분의 경우 수용 가능하지만, 장기 TCP 연결을 사용하는 애플리케이션은 중단될 수 있습니다. 이러한 경우, 해당 노드에서 ztunnel을 업그레이드하기 전에
    노드를 cordon(스케줄링 금지) 하고 drain(파드 종료 후 재배치) 하는 것을 권장합니다.

  • 이 문서에서는 단순함을 위해 ztunnel의 제자리(in-place) 업그레이드 방법을 설명하며,
    이 과정에서는 짧은 다운타임이 발생할 수 있습니다.

사전 조건

업그레이드 준비

  • Istio를 업그레이드하기 전에, 새 버전의 istioctl을 다운로드하고,
    업그레이드가 현재 환경과 호환되는지 확인하기 위해 다음 명령어로 사전 점검(precheck)을 수행하는 것을 권장합니다.
$ istioctl x precheck
✔ No issues found when checking the cluster. Istio is safe to install or upgrade!
  To get started, check out <https://istio.io/latest/docs/setup/getting-started/>

이후, Helm 저장소를 업데이트합니다:

$ helm repo update istio

컨트롤 플레인 업데이트

Base components

  • 🛑 Istio 1.23 이하 버전에서 CRD(CustomResourceDefinition)를 Helm으로 업그레이드할 경우, 다음과 같은 오류가 발생할 수 있습니다:
Error: rendered manifests contain a resource that already exists. Unable to continue with update: CustomResourceDefinition "wasmplugins.extensions.istio.io" in namespace "" exists and cannot be imported into the current release: invalid ownership metadata
  • 이 오류는 기존에 설치된 CRD 리소스가 Helm 릴리스에 의해 관리되지 않아서 발생합니다. 이를 해결하려면 Helm 소유권 메타데이터를 수동으로 추가해야 합니다.
for crd in $(kubectl get crds -l chart=istio -o name && kubectl get crds -l app.kubernetes.io/part-of=istio -o name)
do
   kubectl label "$crd" "app.kubernetes.io/managed-by=Helm"
   kubectl annotate "$crd" "meta.helm.sh/release-name=istio-base" # Helm 릴리스 이름이 다르면 수정
   kubectl annotate "$crd" "meta.helm.sh/release-namespace=istio-system" # Istio 네임스페이스가 다르면 수정
done

📌 주의사항:
release-name=istio-base 및 release-namespace=istio-system은 Helm 릴리스 구성에 맞게 변경해야 합니다.

  • 클러스터 전체에 적용되는 Custom Resource Definitions (CRDs)는 새로운 버전의 Istio 컨트롤 플레인을 배포하기 전에 업그레이드되어야 합니다.
$ helm upgrade istio-base istio/base -n istio-system

istiod control plane

  • Istiod 컨트롤 플레인은 메쉬 내 트래픽을 라우팅하는 프록시를 관리하고 구성합니다.
    다음 명령은 현재 컨트롤 플레인과 함께 새로운 Istiod 인스턴스를 설치하지만,
    기존 게이트웨이 프록시나 웨이포인트를 가져오지 않으며, 새로운 게이트웨이나 웨이포인트를 생성하지도 않습니다.

  • 만약 이전 설치나 업그레이드에서 Istiod 설정을 사용자 정의했다면, 기존의 values.yaml 파일을 재사용하여 컨트롤 플레인 구성을 일관되게 유지할 수 있습니다.

In-place upgrade

$ helm upgrade istiod istio/istiod -n istio-system --wait

Revisioned upgrade

$ helm install istiod-"$REVISION" istio/istiod -n istio-system --set revision="$REVISION" --set profile=ambient --wait

CNI node agent

  • Istio CNI 노드 에이전트는 Ambient Mesh에 추가된 파드(Pod)를 감지하고, 해당 파드 내에 프록시 포트를 설정해야 한다는 정보를 ztunnel에 전달하며, 파드의 네트워크 네임스페이스 안에서 트래픽 리디렉션을 구성하는 역할을 합니다.
    이 구성요소는 데이터 플레인이나 컨트롤 플레인에는 포함되지 않습니다.

  • Istio CNI 버전 1.x는 컨트롤 플레인 버전 1.x 및 1.x+1과 호환됩니다.
    즉, CNI와 컨트롤 플레인의 버전 차이가 한 마이너 버전 이내인 경우, 컨트롤 플레인을 먼저 업그레이드한 후 CNI를 업그레이드해야 합니다.

🛑 Istio는 현재 istio-cni의 카나리 업그레이드를, revision 기능을 사용하더라도 지원하지 않습니다.
따라서 업그레이드로 인한 서비스 중단이 민감한 환경이거나, CNI 업그레이드 시 블라스트 반경(영향 범위)에 대한 더 엄격한 제어가 필요한 경우, 다음과 같은 전략을 권장합니다:

  • 노드를 드레이닝(draining) 및 업그레이드한 후 istio-cni 업그레이드를 진행하거나,
  • 노드 테인트(node taint)를 사용하여 istio-cni 업그레이드를 수동으로 오케스트레이션합니다.

🛑 Istio CNI 노드 에이전트는 system-node-critical DaemonSet입니다.
즉, 해당 노드에서 Istio의 ambient 트래픽 보안 및 운영 보장을 유지하려면 각 노드에서 반드시 실행되어야 합니다.
기본적으로, Istio CNI 노드 에이전트 DaemonSet은 안전한 인플레이스(in-place) 업그레이드를 지원합니다. 에이전트가 업그레이드되거나 재시작되는 동안에는, 에이전트가 다시 활성화되기 전까지 해당 노드에서는 새로운 파드를 시작할 수 없습니다. 이는 보안되지 않은 트래픽 누수를 방지하기 위한 조치입니다.
다만, 업그레이드 이전에 ambient mesh에 정상적으로 추가된 기존 파드들은, 업그레이드 중에도 Istio의 트래픽 보안 요구 사항에 따라 계속 동작합니다.

$ helm upgrade istio-cni istio/cni -n istio-system

Upgrade the data plane

ztunnel DaemonSet

  • ztunnel DaemonSet는 노드 프록시(Node Proxy) 구성 요소입니다.
    버전 1.x의 ztunnel은 1.x 및 1.x+1 버전의 Istio 제어 플레인(Control Plane)과 호환됩니다.
    즉, 버전 차이가 한 메이저 버전 이내인 경우, 제어 플레인을 먼저 업그레이드한 후 ztunnel을 업그레이드해야 합니다.

  • 이전에 ztunnel 설치 시 사용자 정의 설정을 적용한 경우, 이전 업그레이드나 설치에 사용했던 values.yaml 파일을 재사용하여 데이터 플레인 구성을 일관되게 유지할 수 있습니다.

🛑 ztunnel을 인플레이스(in-place) 방식으로 업그레이드하면, 리비전(revision)을 사용하더라도 해당 노드에서 실행 중인 모든 Ambient Mesh 트래픽에 일시적인 중단이 발생합니다.
실제 중단 시간은 매우 짧으며, 주로 장시간 지속되는 연결(long-running connections)에 영향을 줍니다.
프로덕션 환경에서 업그레이드 시 영향 범위(blast radius)를 최소화하려면 노드 cordon(스케줄 비활성화) 및 블루/그린(blue/green) 노드 풀 전략을 사용하는 것이 좋습니다.
자세한 내용은 사용하는 Kubernetes 클러스터 제공업체의 문서를 참고하세요.

In-place upgrade

$ helm upgrade ztunnel istio/ztunnel -n istio-system --wait

Revisioned upgrade

$ helm upgrade ztunnel istio/ztunnel -n istio-system --set revision="$REVISION" --wait

Upgrade manually deployed gateway chart (optional)

  • 수동으로 배포된 Gateway는 Helm을 사용하여 개별적으로 업그레이드해야 합니다.

In-place upgrade

$ helm upgrade istio-ingress istio/gateway -n istio-ingress

Upgrade waypoints and gateways using tags

Revisioned upgrade

  • 모범 사례를 따랐다면, 모든 게이트웨이, 워크로드 및 네임스페이스는 기본 리비전(사실상 default라는 태그 이름) 또는 istio.io/rev 레이블을 사용하고 해당 값을 태그 이름으로 설정했을 것입니다. 이제 이들 태그를 하나씩 새 Istio 데이터 플레인 버전을 가리키도록 이동시켜 업그레이드할 수 있습니다. 클러스터의 모든 태그를 나열하려면 다음 명령어를 실행하세요:
$ kubectl get mutatingwebhookconfigurations -l 'istio.io/tag' -L istio\.io/tag,istio\.io/rev
  • 각 태그에 대해, 다음 명령어를 실행하여 해당 태그를 업그레이드할 수 있습니다. $MYTAG를 태그 이름으로, $REVISION을 리비전 이름으로 바꿔 사용하세요:
$ helm template istiod istio/istiod -s templates/revision-tags.yaml --set revisionTags="{$MYTAG}" --set revision="$REVISION" -n istio-system | kubectl apply -f -
  • 이 명령은 수동 게이트웨이 배포 모드를 사용하는 객체와 사이드카(ambient 모드에서는 사용되지 않음)를 제외한, 해당 태그를 참조하는 모든 객체를 업그레이드합니다.

  • 업그레이드된 데이터 플레인을 사용하는 애플리케이션의 상태를 면밀히 모니터링한 후 다음 태그를 업그레이드하는 것이 좋습니다. 문제가 감지되면, 태그를 롤백하여 이전 리비전 이름을 가리키도록 다시 설정할 수 있습니다:

$ helm template istiod istio/istiod -s templates/revision-tags.yaml --set revisionTags="{$MYTAG}" --set revision="$OLD_REVISION" -n istio-system | kubectl apply -f -

Upgrade manually deployed gateways (optional)

  • 수동으로 배포된 Gateway는 Helm을 사용하여 개별적으로 업그레이드해야 합니다.

In-place upgrade

$ helm upgrade istio-ingress istio/gateway -n istio-ingress

Uninstall the previous control plane

  • Istio 제어 플레인의 새 리비전을 사용하도록 모든 데이터 플레인 구성 요소를 업그레이드했으며, 롤백이 필요하지 않다고 확신하는 경우, 다음 명령어를 실행하여 이전 리비전의 제어 플레인을 제거할 수 있습니다:
$ helm delete istiod-"$OLD_REVISION" -n istio-system

Istio Ambient 아키텍처

Ambient and the istio control plane

  • 모든 Istio 데이터 플레인 모드와 마찬가지로, Ambient 모드도 Istio 컨트롤 플레인을 사용합니다. Ambient 모드에서는 컨트롤 플레인이 각 Kubernetes 노드에 있는 zTunnel 프록시와 통신합니다.

  • 아래 그림은 컨트롤 플레인 관련 구성 요소들과 zTunnel 프록시와 Istiod 컨트롤 플레인 간의 흐름을 개략적으로 보여줍니다.

  • zTunnel 프록시는 xDS API를 사용하여 Istio 컨트롤 플레인(Istiod)과 통신합니다. 이를 통해 현대의 분산 시스템에 필요한 빠르고 동적인 구성 업데이트가 가능합니다. 또한 zTunnel 프록시는 자신의 Kubernetes 노드에 스케줄된 모든 Pod의 서비스 계정에 대한 mTLS 인증서를 xDS를 통해 획득합니다.

  • 하나의 zTunnel 프록시는 같은 노드에 있는 여러 Pod들을 대신하여 L4 데이터 플레인 기능을 수행할 수 있기 때문에, 관련 구성 정보와 인증서를 효율적으로 획득할 수 있어야 합니다. 이러한 멀티 테넌시 아키텍처는 각 애플리케이션 Pod마다 별도의 프록시를 두는 사이드카 모델과는 확연히 다른 방식입니다.

  • 또한 주목할 점은, Ambient 모드에서는 zTunnel 프록시 구성을 위해 사용되는 xDS 리소스가 단순화되어 있다는 것입니다. 이로 인해 다음과 같은 이점이 있습니다:

  • 성능 향상: Istiod에서 zTunnel로 전송되는 정보의 양이 훨씬 적어짐
  • 문제 해결 용이성 개선: 간단한 구성으로 디버깅 및 운영이 수월해짐

Ambient data plane

Ambient 모드에서 워크로드는 다음의 세 가지 범주 중 하나에 속할 수 있습니다:

  1. Mesh 외부 (Out of Mesh)
    Mesh 기능이 전혀 활성화되지 않은 일반적인 Pod입니다.
    Istio나 Ambient 데이터 플레인이 적용되지 않습니다.

  2. Mesh 내부 (In Mesh)
    Ambient 데이터 플레인에 포함된 Pod로, 트래픽이 zTunnel에 의해 L4 (Layer 4) 수준에서 인터셉트됩니다.
    이 모드에서는 L4 수준의 정책(L4 RBAC 등)을 Pod 트래픽에 적용할 수 있습니다.
    이 모드는 Pod에 istio.io/dataplane-mode=ambient 라벨을 설정하여 활성화할 수 있습니다.
    자세한 내용은 관련 라벨 문서를 참고하세요.

  3. Mesh 내부 + Waypoint 활성화 (In Mesh, Waypoint enabled)
    Ambient Mesh에 포함되며, Waypoint 프록시가 함께 배포된 Pod입니다.
    이 모드에서는 L7 수준의 정책(HTTP 라우팅, L7 RBAC 등)을 Pod 트래픽에 적용할 수 있습니다.
    이 모드는 Pod에 istio.io/use-waypoint 라벨을 설정하여 활성화할 수 있습니다.
    자세한 내용은 관련 라벨 문서를 참고하세요.

Mesh 내 라우팅

Outbound

Ambient Mesh에 포함된 Pod가 아웃바운드 요청을 보낼 때, 해당 요청은 투명하게 노드 로컬의 zTunnel로 리디렉션되며, zTunnel이 해당 요청을 어디로, 어떻게 전달할지를 결정합니다.
일반적으로 트래픽 라우팅 동작은 기본 Kubernetes 라우팅 방식과 동일하게 동작합니다.
즉, Service로의 요청은 해당 Service의 엔드포인트로 전송되고, Pod IP로 직접 요청을 보낼 경우에는 해당 IP로 직접 전달됩니다.

하지만 목적지의 기능(역할)에 따라 동작 방식은 달라질 수 있습니다.

  • 만약 목적지가 Mesh에 포함되어 있거나, Istio 프록시 기능(예: 사이드카)을 갖추고 있다면, 요청은 암호화된 HBONE 터널로 업그레이드됩니다.
  • 목적지가 Waypoint 프록시를 갖고 있다면, 요청은 HBONE 터널로 업그레이드됨과 동시에 해당 Waypoint로 전달되어 L7 정책이 적용됩니다.

또한 다음 사항에 유의해야 합니다:

  • Service로의 요청의 경우, 해당 Service가 Waypoint를 갖고 있다면, 요청은 해당 Waypoint로 전달되어 트래픽에 L7 정책이 적용됩니다.
  • Pod IP로의 요청의 경우에도, 해당 Pod에 Waypoint가 설정되어 있다면, 요청은 해당 Waypoint로 전달되어 L7 정책이 적용됩니다.

참고로, Deployment에 속한 일부 Pod에만 특정 라벨을 설정하는 것도 가능하므로, 일부 Pod만 Waypoint를 사용하는 고급 구성도 기술적으로는 가능합니다.
하지만 사용자에게는 이러한 고급 사용 방식은 일반적으로 권장되지 않습니다.

Inbound

  • Ambient Mesh에 포함된 Pod가 인바운드 요청을 받을 때, 해당 요청은 투명하게 노드 로컬의 zTunnel로 리디렉션됩니다. zTunnel이 요청을 받으면, Authorization Policy(인가 정책)를 적용하며, 이 검사를 통과한 요청만을 다음 단계로 전달합니다.

  • Pod는 HBONE 트래픽 또는 평문(plaintext) 트래픽을 받을 수 있습니다. 기본적으로 zTunnel은 두 종류의 트래픽을 모두 허용합니다.
    Mesh 외부에서 온 요청은 인가 정책 평가 시 피어 ID가 없기 때문에, 사용자는 모든 평문 트래픽을 차단하기 위해 특정 ID(모든 ID 또는 특정 ID)를 요구하는 정책을 설정할 수 있습니다.

  • 대상 Pod가 Waypoint가 활성화된 경우, 출발지가 Ambient Mesh 내부라면 출발지의 zTunnel이 요청이 Waypoint를 반드시 거쳐 정책이 적용되도록 보장합니다.
    하지만 Mesh 외부의 워크로드는 Waypoint 프록시에 대한 정보를 알지 못하기 때문에, 목적지가 Waypoint를 사용하더라도 Waypoint 프록시를 거치지 않고 직접 목적지로 요청을 보냅니다.

현재로서는 사이드카와 게이트웨이에서 나가는 트래픽도 Waypoint 프록시를 거치지 않습니다.
이 부분은 향후 릴리스에서 Waypoint 프록시 인지를 지원할 예정입니다.

Dataplane details

🔐 Identity

  • Ambient Mesh 내 워크로드 간의 모든 인바운드 및 아웃바운드 L4 TCP 트래픽은 데이터 플레인에 의해 mTLS (HBONE, zTunnel, x509 인증서 사용)로 보호됩니다.

  • mTLS가 강제하는 바에 따라, 출발지와 목적지는 고유한 x509 아이덴티티(신원)를 가져야 하며, 이 아이덴티티를 이용해 연결을 위한 암호화 채널이 설정됩니다.

  • 이를 위해 zTunnel은 프록시하는 워크로드들을 대신하여 여러 개의 서로 다른 워크로드 인증서(서비스 계정별로 각 노드 로컬 Pod마다 하나씩)를 관리해야 합니다.
    단, zTunnel 자체의 아이덴티티는 워크로드 간 mTLS 연결에 사용되지 않습니다.

  • 인증서를 가져올 때, zTunnel은 자신의 아이덴티티로 CA에 인증하지만, 다른 워크로드의 아이덴티티를 요청합니다.
    이때 중요한 점은 CA가 zTunnel이 해당 아이덴티티를 요청할 권한이 있는지 반드시 검증해야 한다는 것입니다.
    노드에 존재하지 않는 아이덴티티 요청은 거부됩니다.
    이는 노드가 침해되더라도 전체 메시가 침해되는 것을 방지하기 위한 매우 중요한 보안 조치입니다.

  • 이 CA 권한 검증은 Istio CA가 Kubernetes 서비스 계정 JWT 토큰을 사용해 수행하며, 이 토큰에는 Pod 정보가 인코딩되어 있습니다.
    이 같은 권한 검증은 zTunnel과 통합되는 다른 CA에도 필수 요구 사항입니다.

  • zTunnel은 노드 내 모든 아이덴티티에 대해 인증서를 요청합니다.
    이는 컨트롤 플레인에서 받은 구성 정보를 바탕으로 판단합니다.
    새로운 아이덴티티가 노드에서 발견되면 최적화를 위해 우선순위가 낮은 대기열에 등록되어 인증서 요청이 진행됩니다.
    그러나 특정 아이덴티티가 필요한 요청이 들어오면, 아직 인증서를 받지 않았더라도 즉시 인증서를 요청합니다.

  • 또한 zTunnel은 인증서의 만료가 다가올 때 인증서 갱신(로테이션) 작업도 처리합니다.

🎛️ Telemetry
zTunnel은 Istio 표준 TCP 메트릭 전체 세트를 내보냅니다.
다음 그림은 Layer 4 Ambient 데이터플레인을 보여줍니다.

그림은 Kubernetes 클러스터의 노드 W1과 W2에서 실행 중인 여러 워크로드가 Ambient Mesh에 추가된 모습을 보여줍니다. 각 노드에는 zTunnel 프록시가 한 개씩 실행되고 있습니다. 이 시나리오에서 애플리케이션 클라이언트 Pod인 C1, C2, C3는 Pod S1이 제공하는 서비스를 호출해야 합니다. L7 트래픽 라우팅이나 L7 트래픽 관리 같은 고급 L7 기능이 필요 없기 때문에, mTLS와 L4 정책 적용만을 위한 L4 데이터 플레인으로 충분하며, Waypoint 프록시는 필요하지 않습니다.

그림에서는 노드 W1에서 실행 중인 Pod C1과 C2가 노드 W2에서 실행 중인 Pod S1과 통신하는 모습을 보여줍니다.

C1과 C2의 TCP 트래픽은 zTunnel이 생성한 HBONE 연결을 통해 안전하게 터널링됩니다. 암호화 및 터널링되는 트래픽의 상호 인증을 위해 상호 TLS(mTLS)가 사용됩니다. 각 연결 양쪽 워크로드를 식별하기 위해 SPIFFE 아이덴티티가 활용됩니다. 터널링 프로토콜 및 트래픽 리디렉션 메커니즘에 관한 자세한 내용은 HBONEzTunnel 트래픽 리디렉션 가이드를 참고하시기 바랍니다.

ℹ️ 참고: 그림에서는 HBONE 터널이 두 zTunnel 프록시 간에 형성된 것으로 보이지만, 실제 터널은 출발지와 목적지 Pod 간에 형성됩니다. 트래픽은 출발지 Pod의 네트워크 네임스페이스 내에서 HBONE으로 캡슐화되고 암호화되며, 최종적으로 목적지 워커 노드의 목적지 Pod 네트워크 네임스페이스에서 캡슐화가 해제되고 복호화됩니다.
ztunnel 프록시는 여전히 HBONE 전송에 필요한 제어 평면과 데이터 평면을 논리적으로 처리하지만, 이는 출발지 및 목적지 Pod의 네트워크 네임스페이스 내부에서 수행됩니다.

📌 참고로, 그림에서 워커 노드 W2에 있는 Pod C3에서 목적지 Pod S1으로 향하는 로컬 트래픽도 로컬 zTunnel 프록시 인스턴스를 거치게 됩니다.
따라서 노드 경계를 넘는 트래픽이든 아니든 상관없이, L4 권한 부여(L4 Authorization) 및 L4 텔레메트리(L4 Telemetry) 같은 L4 트래픽 관리 기능이 동일하게 적용됩니다.

Waypoint 활성화 되었을 때 Mesh내에 라우팅

  • Istio Waypoint는 오직 HBONE 트래픽만을 수신합니다. 요청을 받으면, Waypoint는 해당 트래픽이 자신을 사용하는 Pod 또는 Service를 위한 것인지 확인합니다.

  • 트래픽을 수락한 후에는, Waypoint가 L7 정책들(예: AuthorizationPolicy, RequestAuthentication, WasmPlugin, Telemetry 등)을 적용한 뒤에 트래픽을 전달합니다.

  • Pod에 대한 직접 요청인 경우, 정책이 적용된 후 요청은 단순히 바로 전달됩니다.

  • Service에 대한 요청인 경우, Waypoint는 라우팅과 로드 밸런싱도 수행합니다. 기본적으로 Service는 자신의 엔드포인트들 사이에서 L7 로드 밸런싱을 수행하며, 요청을 자신에게 라우팅합니다. 이 동작은 해당 Service에 대한 라우트(Routes)를 설정하여 변경할 수 있습니다.

  • 예를 들어, 아래 정책은 echo 서비스에 대한 요청이 echo-v1으로 전달되도록 보장합니다:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: echo
spec:
  parentRefs:
  - group: ""
    kind: Service
    name: echo
  rules:
  - backendRefs:
    - name: echo-v1
      port: 80
  • 다음 그림은 L7 정책 적용을 위해 Waypoint가 구성되어 있는 경우, zTunnel과 Waypoint 간의 데이터 경로를 보여줍니다.
    이 경우 zTunnel은 HBONE 터널링을 사용해 트래픽을 Waypoint 프록시로 전송하며, L7 처리가 이루어진 후 Waypoint는 두 번째 HBONE 터널을 통해 트래픽을 선택된 서비스 목적지 Pod가 위치한 노드의 zTunnel로 전달합니다.

  • 일반적으로 Waypoint 프록시는 출발지 Pod나 목적지 Pod와 동일한 노드에 존재할 수도 있고, 그렇지 않을 수도 있습니다.

HBONE

  • HBONE(HTTP-Based Overlay Network Environment)은 Istio 컴포넌트 간에 사용되는 보안 터널링 프로토콜입니다. HBONE은 Istio에서 사용하는 전용 용어로, 다양한 애플리케이션 연결에 대한 TCP 스트림을 단일 mTLS 암호화 네트워크 연결(즉, 암호화된 터널) 위에서 투명하게 멀티플렉싱하는 메커니즘입니다.

  • 현재 Istio에서 구현된 HBONE 프로토콜은 다음의 세 가지 오픈 표준으로 구성되어 있습니다:

  • HTTP CONNECT는 터널 연결을 수립하는 데 사용되며, mTLS는 그 연결을 보호하고 암호화합니다. HTTP/2는 단일 암호화된 터널 위에서 여러 애플리케이션 연결 스트림을 멀티플렉싱하고, 추가적인 스트림 수준 메타데이터를 전달하는 데 사용됩니다.

Security and tenancy

  • mTLS 사양에 따라, 각 기본 터널 연결은 고유한 출발지(identity)목적지(identity)를 가져야 하며, 이들 아이덴티티를 사용해 해당 연결의 암호화가 설정되어야 합니다.

  • 이는 곧, HBONE 프로토콜을 통해 동일한 목적지 아이덴티티로 향하는 애플리케이션 연결들이 하나의 공유된, 암호화되고 보안이 유지된 HTTP/2 연결 위에서 멀티플렉싱된다는 의미입니다. 즉, 각 고유한 출발지와 목적지 조합은 전용의 보안 터널 연결을 가져야 하며, 해당 전용 연결이 애플리케이션 수준의 여러 개별 연결을 동시에 처리할 수 있다 하더라도 기본적으로는 독립된 터널이 생성되어야 합니다.

구현 방식의 세부 내용

  • Istio의 관례에 따라, ztunnel 및 HBONE 프로토콜을 이해하는 다른 프록시들은 TCP 포트 15008에서 리스너(listener)를 노출합니다.

  • HBONE은 단지 HTTP/2, HTTP CONNECT, 그리고 mTLS의 조합일 뿐이므로, HBONE을 지원하는 프록시 간에 흐르는 HBONE 터널 패킷은 다음 그림과 같은 형태를 가집니다.

    • HBONE 터널의 중요한 특징 중 하나는, 원래의 애플리케이션 요청을 변경하지 않고도 투명하게 프록시할 수 있다는 점입니다.
      즉, 애플리케이션 트래픽 스트림을 변경하지 않고도 연결에 대한 메타데이터를 목적지 프록시에 전달할 수 있으므로, 예를 들어 Istio 전용 헤더를 애플리케이션 트래픽에 덧붙일 필요가 없습니다.

    • HBONE 및 HTTP 터널링의 추가적인 활용 사례(예: UDP 지원)는 향후 Ambient 모드와 관련 표준의 발전에 따라 연구될 예정입니다.

Ztunnel traffice redirection

  • Ambient 모드의 맥락에서, 트래픽 리다이렉션(traffic redirection)은 데이터 플레인 기능을 의미하며, 이는 Ambient가 활성화된 워크로드로부터 들어오고 나가는 트래픽을 가로채어 zTunnel 노드 프록시를 통해 라우팅하는 역할을 합니다. 이와 관련하여 때때로 트래픽 캡처(traffic capture)라는 용어도 사용됩니다.

  • zTunnel은 애플리케이션 트래픽을 투명하게 암호화하고 라우팅하는 것을 목표로 하기 때문에, “Mesh 내부(in mesh)”에 있는 Pod로 들어오고 나가는 모든 트래픽을 가로채는 메커니즘이 필요합니다.
    이 작업은 보안상 매우 중요한 작업으로, 만약 zTunnel이 우회될 수 있다면, Authorization Policy 또한 우회될 수 있기 때문입니다.

Istio’s in-pod traffic redirection model

  • Ambient 모드의 Pod 내부 트래픽 리다이렉션을 가능하게 하는 핵심 설계 원칙은 zTunnel 프록시가 워크로드 Pod의 Linux 네트워크 네임스페이스 내에서 데이터 경로 캡처(data path capture)를 수행할 수 있다는 점입니다.
    이 기능은 istio-cni 노드 에이전트와 zTunnel 노드 프록시 간의 협력을 통해 구현됩니다.

  • 이 모델의 주요 이점은, Istio의 Ambient 모드가 Kubernetes의 어떤 CNI 플러그인과도 투명하게 함께 동작할 수 있으며, 동시에 Kubernetes의 네트워킹 기능에 영향을 주지 않는다는 점입니다.

  • 다음 그림은 Ambient가 활성화된 네임스페이스에 새로운 워크로드 Pod가 시작되거나 추가될 때 발생하는 이벤트의 순서를 보여줍니다.

  • istio-cni 노드 에이전트는 Pod 생성 및 삭제와 같은 CNI 이벤트에 반응하며, Ambient 라벨이 Pod나 네임스페이스에 추가되는 등의 이벤트를 감지하기 위해 Kubernetes API 서버를 지속적으로 감시합니다.

  • istio-cni 노드 에이전트는 또한 기존 CNI 플러그인 실행 이후에 호출되는 체이닝(Chained) CNI 플러그인을 설치합니다. 이 플러그인의 유일한 목적은, Ambient 모드에 등록된 네임스페이스에서 컨테이너 런타임에 의해 새로운 Pod가 생성될 때 이를 istio-cni 에이전트에 알려주고, 새로운 Pod의 컨텍스트를 전달하는 것입니다.

  • Pod가 메시에 추가되어야 함을 감지한 경우(새로운 Pod인 경우에는 CNI 플러그인을 통해, 이미 실행 중인 Pod인 경우에는 Kubernetes API 서버를 통해), 다음과 같은 순서로 작업이 진행됩니다:

    1. istio-cni는 해당 Pod의 네트워크 네임스페이스에 진입하여 트래픽 리다이렉션 규칙을 설정합니다. 이 규칙은 Pod 내부 및 외부로 이동하는 패킷을 가로채어, 노드 로컬 ztunnel 프록시 인스턴스(지정된 포트: 15008, 15006, 15001)로 투명하게 리다이렉션합니다.

    2. istio-cni 노드 에이전트는 Unix 도메인 소켓을 통해 ztunnel 프록시에 Pod의 네트워크 네임스페이스 내부에 리스닝 포트(15008, 15006, 15001)를 생성하도록 요청합니다. 이때 Pod의 네트워크 네임스페이스를 나타내는 저수준 Linux 파일 디스크립터도 함께 전달됩니다.

    3. 일반적으로는 네트워크 네임스페이스 내에서 실행 중인 프로세스가 소켓을 생성하지만, Linux의 저수준 소켓 API를 이용하면 다른 네트워크 네임스페이스 안에 리스닝 소켓을 생성하는 것도 가능합니다. 단, 대상 네임스페이스를 생성 시점에 알고 있어야 합니다.

    4. 노드 로컬 ztunnel은 내부적으로 해당 Pod를 위한 새로운 논리적 프록시 인스턴스 및 리스닝 포트 세트를 생성합니다. 이는 여전히 같은 프로세스 내에서 실행되며, 단지 Pod를 위한 전용 작업(task)이 추가되는 것입니다.

    5. Pod 내부 리다이렉션 규칙이 적용되고 ztunnel이 리스닝 포트를 생성하면, 해당 Pod는 메시에 추가되고 트래픽이 노드 로컬 ztunnel을 통해 흐르기 시작합니다.

    6. 메시 내 Pod 간의 트래픽은 기본적으로 mTLS로 암호화됩니다.

    7. 이제 Pod 네트워크 네임스페이스로 들어오고 나가는 데이터는 암호화된 상태로 전송됩니다. 메시 내의 모든 Pod는 메시 정책을 강제하고 트래픽을 안전하게 암호화할 수 있는 능력을 가지며, Pod 내부에서 실행 중인 사용자 애플리케이션은 이러한 동작을 전혀 인지하지 못합니다.

  • 다음 다이어그램은 Ambient 메시 모델에서 Pod 간의 암호화된 트래픽이 어떻게 흐르는지를 보여줍니다.업로드중..

Observing and debugging traffic redirection in ambient mode

  • Ambient 모드에서 트래픽 리다이렉션이 올바르게 작동하지 않는 경우, 문제를 좁히기 위해 몇 가지 빠른 확인 작업을 수행할 수 있습니다.
    문제 해결은 ztunnel 디버깅 가이드에서 설명하는 단계부터 시작할 것을 권장합니다.

Check the ztunnel proxy logs

  • 애플리케이션 파드가 ambient 메시에 포함되어 있을 때, ztunnel 프록시 로그를 확인하여 메쉬가 트래픽을 올바르게 리다이렉트하고 있는지 확인할 수 있습니다. 아래 예시에서 보듯이, in-pod와 관련된 ztunnel 로그는 in-pod 리다이렉션 모드가 활성화되었음을 나타내며, 프록시가 ambient 애플리케이션 파드의 네트워크 네임스페이스(netns) 정보를 수신하고 해당 파드에 대해 프록싱을 시작했음을 보여줍니다.
$ kubectl logs ds/ztunnel -n istio-system  | grep inpod
Found 3 pods, using pod/ztunnel-hl94n
inpod_enabled: true
inpod_uds: /var/run/ztunnel/ztunnel.sock
inpod_port_reuse: true
inpod_mark: 1337
2024-02-21T22:01:49.916037Z  INFO ztunnel::inpod::workloadmanager: handling new stream
2024-02-21T22:01:49.919944Z  INFO ztunnel::inpod::statemanager: pod WorkloadUid("1e054806-e667-4109-a5af-08b3e6ba0c42") received netns, starting proxy
2024-02-21T22:01:49.925997Z  INFO ztunnel::inpod::statemanager: pod received snapshot sent
2024-02-21T22:03:49.074281Z  INFO ztunnel::inpod::statemanager: pod delete request, draining proxy
2024-02-21T22:04:58.446444Z  INFO ztunnel::inpod::statemanager: pod WorkloadUid("1e054806-e667-4109-a5af-08b3e6ba0c42") received netns, starting proxy

✅ *Confirm the state of sockets

  • 다음 단계에 따라 포트 15001, 15006, 15008의 소켓이 열려 있고 리스닝 상태인지 확인하세요.
kubectl debug $(kubectl get pod -l app=curl -n ambient-demo -o jsonpath='{.items[0].metadata.name}') -it -n ambient-demo  --image nicolaka/netshoot  -- ss -ntlp
Defaulting debug container name to debugger-nhd4d.
State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
LISTEN 0      128        127.0.0.1:15080      0.0.0.0:*
LISTEN 0      128                *:15006            *:*
LISTEN 0      128                *:15001            *:*
LISTEN 0      128                *:15008            *:*

Check the iptables rules setup

  • 애플리케이션 파드 중 하나 내부에 설정된 iptables 규칙을 확인하려면, 다음 명령어를 실행하세요:
$ kubectl debug $(kubectl get pod -l app=curl -n ambient-demo -o jsonpath='{.items[0].metadata.name}') -it --image gcr.io/istio-release/base --profile=netadmin -n ambient-demo -- iptables-save
Defaulting debug container name to debugger-m44qc.
# Generated by iptables-save
*mangle
:PREROUTING ACCEPT [320:53261]
:INPUT ACCEPT [23753:267657744]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [23352:134432712]
:POSTROUTING ACCEPT [23352:134432712]
:ISTIO_OUTPUT - [0:0]
:ISTIO_PRERT - [0:0]
-A PREROUTING -j ISTIO_PRERT
-A OUTPUT -j ISTIO_OUTPUT
-A ISTIO_OUTPUT -m connmark --mark 0x111/0xfff -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
-A ISTIO_PRERT -m mark --mark 0x539/0xfff -j CONNMARK --set-xmark 0x111/0xfff
-A ISTIO_PRERT -s 169.254.7.127/32 -p tcp -m tcp -j ACCEPT
-A ISTIO_PRERT ! -d 127.0.0.1/32 -i lo -p tcp -j ACCEPT
-A ISTIO_PRERT -p tcp -m tcp --dport 15008 -m mark ! --mark 0x539/0xfff -j TPROXY --on-port 15008 --on-ip 0.0.0.0 --tproxy-mark 0x111/0xfff
-A ISTIO_PRERT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ISTIO_PRERT ! -d 127.0.0.1/32 -p tcp -m mark ! --mark 0x539/0xfff -j TPROXY --on-port 15006 --on-ip 0.0.0.0 --tproxy-mark 0x111/0xfff
COMMIT
# Completed
# Generated by iptables-save
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [175:13694]
:POSTROUTING ACCEPT [205:15494]
:ISTIO_OUTPUT - [0:0]
-A OUTPUT -j ISTIO_OUTPUT
-A ISTIO_OUTPUT -d 169.254.7.127/32 -p tcp -m tcp -j ACCEPT
-A ISTIO_OUTPUT -p tcp -m mark --mark 0x111/0xfff -j ACCEPT
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -j ACCEPT
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -p tcp -m mark ! --mark 0x539/0xfff -j REDIRECT --to-ports 15001
COMMIT
  • 명령어 출력 결과는 애플리케이션 파드의 네트워크 네임스페이스 내 netfilter/iptables의 NAT 및 Mangle 테이블에 Istio 전용 체인이 추가되었음을 보여줍니다. 파드로 들어오는 모든 TCP 트래픽은 인그레스 처리를 위해 ztunnel 프록시로 리다이렉트됩니다. 트래픽이 평문일 경우(목적지 포트가 15008이 아닌 경우), in-pod ztunnel의 평문 리스닝 포트 15006으로 리다이렉트됩니다. 트래픽이 HBONE인 경우(목적지 포트가 15008인 경우), in-pod ztunnel의 HBONE 리스닝 포트 15008로 리다이렉트됩니다. 파드에서 나가는 모든 TCP 트래픽은 egress 처리를 위해 ztunnel의 포트 15001로 리다이렉트된 후, ztunnel이 HBONE 캡슐화를 사용하여 외부로 전송합니다.

💕💕💕 9주간 Istio 학습정리를 마무리 합니다. 본 Study를 통해 내적으로 많은 성장을 하였다고 자체 평가하며, 열강해주신 가시다님께 심심한 감사 말씀드립니다. 💕💕💕

profile
I'm SJ

0개의 댓글