Skip to content

Split View: Istio 아키텍처 내부 분석: 컨트롤 플레인과 데이터 플레인

|

Istio 아키텍처 내부 분석: 컨트롤 플레인과 데이터 플레인

들어가며

Istio는 Kubernetes 환경에서 가장 널리 사용되는 서비스 메시입니다. 하지만 "VirtualService를 만들면 트래픽이 라우팅된다"는 수준을 넘어, 내부에서 실제로 어떤 일이 일어나는지 이해하는 것은 운영과 트러블슈팅에 큰 차이를 만듭니다.

이 글에서는 Istio의 컨트롤 플레인과 데이터 플레인이 어떻게 상호작용하고, 사용자가 정의한 CRD가 어떻게 Envoy 구성으로 변환되는지 내부 메커니즘을 분석합니다.

Istio 아키텍처 개요

Istio는 크게 두 부분으로 구성됩니다:

┌─────────────────────────────────────────────────┐
Control Plane│  ┌───────────────────────────────────────────┐  │
│  │              istiod                        │  │
│  │  ┌─────────┐ ┌─────────┐ ┌──────────┐   │  │
│  │  │  Pilot  │ │ Citadel │ │  Galley  │   │  │
│  │    (xDS)  (CA)(Validate)│   │  │
│  │  └─────────┘ └─────────┘ └──────────┘   │  │
│  └───────────────────────────────────────────┘  │
├─────────────────────────────────────────────────┤
Data Plane│  ┌──────────┐  ┌──────────┐  ┌──────────┐     │
│  │ App + EP │  │ App + EP │  │ App + EP │     │
 (Pod A) (Pod B) (Pod C)  │     │
│  └──────────┘  └──────────┘  └──────────┘     │
EP = Envoy Proxy (istio-proxy sidecar)└─────────────────────────────────────────────────┘

istiod: 통합된 컨트롤 플레인

역사적 배경

Istio 1.5 이전에는 Pilot, Citadel, Galley, Mixer가 각각 별도의 마이크로서비스로 배포되었습니다. Istio 1.5부터 이들이 istiod라는 단일 바이너리로 통합되었고, Mixer는 1.8에서 완전히 제거되었습니다.

Pilot: 트래픽 관리 엔진

Pilot은 istiod의 핵심으로, 다음 역할을 수행합니다:

  1. 서비스 디스커버리: Kubernetes API 서버를 감시하여 Service, Endpoint, Pod 변경을 추적
  2. 구성 변환: Istio CRD(VirtualService, DestinationRule 등)를 Envoy 구성으로 변환
  3. xDS 서버: 변환된 구성을 gRPC 스트림으로 각 Envoy 프록시에 푸시
Kubernetes API Server
   ┌─────────┐
Pilot  │ ← Istio CRD 감시 (VirtualService, DestinationRule, Gateway...)
   │         │ ← Kubernetes 리소스 감시 (Service, Endpoints, Pod...)
   └────┬────┘
xDS (gRPC stream)
   ┌─────────┐
Envoy  │ ← LDS, RDS, CDS, EDS, SDS 수신
   └─────────┘

Citadel: 인증서 관리

Citadel(현재 istiod에 통합)은 메시 내 워크로드의 아이덴티티와 인증서를 관리합니다:

  • CA(Certificate Authority) 역할 수행
  • 각 워크로드에 X.509 인증서 발급
  • SPIFFE 표준 기반 아이덴티티 부여
  • 인증서 자동 로테이션 (기본 24시간)

Galley: 구성 검증

Galley는 Istio 구성의 유효성을 검증합니다:

  • Kubernetes Admission Webhook을 통한 구성 검증
  • CRD 스키마 검증
  • 구성 간 참조 무결성 확인 (예: VirtualService가 참조하는 Gateway 존재 여부)

Envoy 사이드카 주입 메커니즘

MutatingWebhookConfiguration

Istio의 사이드카 주입은 Kubernetes의 MutatingAdmissionWebhook을 활용합니다:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: istio-sidecar-injector
webhooks:
  - name: sidecar-injector.istio.io
    namespaceSelector:
      matchLabels:
        istio-injection: enabled
    rules:
      - apiGroups: ['']
        apiVersions: ['v1']
        operations: ['CREATE']
        resources: ['pods']

파드가 생성될 때 다음 과정이 진행됩니다:

1. kubectl apply -f deployment.yaml
2. Kubernetes API Server가 Admission Webhook 호출
3. istiod의 Sidecar Injector가 파드 스펙 수정
4. 수정된 파드 스펙이 반환
5. 수정된 스펙으로 파드 생성

주입되는 컨테이너

사이드카 주입 시 두 개의 컨테이너가 추가됩니다:

1. istio-init (Init Container)

initContainers:
  - name: istio-init
    image: proxyv2
    command:
      - istio-iptables
      - '-p'
      - '15001' # Envoy outbound 포트
      - '-z'
      - '15006' # Envoy inbound 포트
      - '-u'
      - '1337' # istio-proxy UID (이 UID의 트래픽은 리다이렉트 제외)
      - '-m'
      - 'REDIRECT'
    securityContext:
      capabilities:
        add: ['NET_ADMIN', 'NET_RAW']

istio-init 컨테이너는 iptables 규칙을 설정하여 모든 인바운드/아웃바운드 트래픽을 Envoy 프록시로 리다이렉트합니다.

2. istio-proxy (Sidecar Container)

containers:
  - name: istio-proxy
    image: proxyv2
    ports:
      - containerPort: 15090 # Prometheus 메트릭
      - containerPort: 15021 # 헬스 체크
    env:
      - name: ISTIO_META_CLUSTER_ID
        value: 'Kubernetes'
      - name: PILOT_CERT_PROVIDER
        value: 'istiod'

iptables 트래픽 리다이렉트

istio-init이 설정하는 iptables 규칙의 흐름:

[인바운드 트래픽]
외부 → Pod IP:Port
  → iptables PREROUTING
ISTIO_INBOUND 체인
REDIRECT to 15006 (Envoy inbound listener)
Envoy가 처리 후 localhost:AppPort로 전달

[아웃바운드 트래픽]
App → 외부 서비스 IP:Port
  → iptables OUTPUT
ISTIO_OUTPUT 체인
REDIRECT to 15001 (Envoy outbound listener)
Envoy가 처리 후 실제 목적지로 전달

[예외]
UID 1337 (istio-proxy)의 트래픽은 리다이렉트 제외 → 무한 루프 방지

xDS 프로토콜 상세

xDS(x Discovery Service)는 Envoy가 동적으로 구성을 수신하는 API 프로토콜입니다.

xDS API 종류

API전체 이름역할
LDSListener Discovery Service리스너 구성 (포트, 프로토콜)
RDSRoute Discovery ServiceHTTP 라우팅 규칙
CDSCluster Discovery Service업스트림 클러스터 정의
EDSEndpoint Discovery Service클러스터 내 실제 엔드포인트 목록
SDSSecret Discovery ServiceTLS 인증서 및 키

구성 푸시 흐름

[1] 사용자가 VirtualService 생성
[2] Pilot이 Kubernetes API 감시를 통해 변경 감지
[3] Pilot이 VirtualService를 Envoy RDS 구성으로 변환
[4] 관련 CDS, EDS 구성도 함께 생성
[5] gRPC 스트림으로 해당 워크로드의 Envoy에 푸시
[6] Envoy가 새 구성을 핫 리로드 (연결 끊김 없음)

ADS (Aggregated Discovery Service)

Istio는 ADS를 사용하여 모든 xDS 응답을 단일 gRPC 스트림으로 통합합니다. 이는 구성 일관성을 보장합니다:

  • CDS와 EDS 간의 순서 보장 (클러스터 정의 먼저, 엔드포인트 나중)
  • LDS와 RDS 간의 순서 보장
  • 원자적 구성 업데이트

구성 확인 방법

# 특정 파드의 Envoy 리스너 확인
istioctl proxy-config listeners PODNAME.NAMESPACE

# 라우트 구성 확인
istioctl proxy-config routes PODNAME.NAMESPACE

# 클러스터 구성 확인
istioctl proxy-config clusters PODNAME.NAMESPACE

# 엔드포인트 확인
istioctl proxy-config endpoints PODNAME.NAMESPACE

# 전체 Envoy 구성 덤프
istioctl proxy-config all PODNAME.NAMESPACE -o json

Envoy 필터 체인 아키텍처

Envoy 프록시는 계층적 필터 체인으로 요청을 처리합니다:

[요청 흐름]

Listener (포트 바인딩)
Filter Chain (일치하는 필터 체인 선택)
    ├── Network Filters
    │   ├── TCP Proxy Filter (L4)
    │   └── HTTP Connection Manager (L7)
    │       │
    │       ├── HTTP Filters
    │       │   ├── RBAC Filter (인가)
    │       │   ├── JWT Authn Filter (인증)
    │       │   ├── Fault Injection Filter
    │       │   ├── CORS Filter
    │       │   ├── Stats Filter (메트릭)
    │       │   └── Router Filter (최종 라우팅)
    │       │
    │       └── Route Configuration
    │           ├── Virtual Host 선택
    │           └── Route 매칭 및 Cluster 결정
Cluster (업스트림 선택)
Endpoint (실제 대상 파드)

Listener 구조

Listener 0.0.0.0:15006 (Inbound)
├── FilterChain: App 포트 (: 8080)
│   ├── TLS Inspector
│   ├── HTTP Connection Manager
│   │   ├── istio_authn filter
│   │   ├── envoy.filters.http.rbac
│   │   └── envoy.filters.http.router
│   └── Route: inbound|8080|http|service.ns.svc.cluster.local
└── FilterChain: Default (passthrough)

Listener 0.0.0.0:15001 (Outbound)
├── FilterChain: 서비스별 매칭
│   ├── HTTP Connection Manager
│   │   ├── envoy.filters.http.fault
│   │   ├── envoy.filters.http.cors
│   │   ├── istio.stats
│   │   └── envoy.filters.http.router
│   └── Route: 서비스별 VirtualHost
└── FilterChain: PassthroughCluster (매칭되지 않는 트래픽)

워크로드 아이덴티티: SPIFFE

SPIFFE ID 체계

Istio는 SPIFFE(Secure Production Identity Framework For Everyone) 표준을 사용합니다:

spiffe://TRUST_DOMAIN/ns/NAMESPACE/sa/SERVICE_ACCOUNT

예시:
spiffe://cluster.local/ns/production/sa/frontend

인증서 발급 흐름 (CSR Flow)

[1] istio-agent (파드 내)가 키 쌍 생성
[2] CSR(Certificate Signing Request) 생성
[3] CSR을 istiod에 전송 (gRPC, 이미 부트스트랩 토큰으로 인증)
[4] istiod가 CSR 검증:
    - ServiceAccount 토큰 유효성
    - 네임스페이스 소속 확인
[5] istiod의 CAX.509 인증서 서명
[6] 서명된 인증서를 istio-agent에 반환
[7] istio-agent가 SDS를 통해 Envoy에 인증서 전달
[8] Envoy가 mTLS에 인증서 사용

SDS (Secret Discovery Service)

인증서는 파일 시스템이 아닌 SDS를 통해 Envoy에 전달됩니다:

  • istio-agent가 로컬 SDS 서버 역할
  • Envoy가 SDS API로 인증서 요청
  • 인증서 로테이션 시 Envoy 재시작 불필요
  • 인증서가 디스크에 기록되지 않아 보안성 향상

구성 변환: Istio CRD에서 Envoy 구성으로

VirtualService 변환 예시

사용자가 정의한 VirtualService:

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

이것이 Envoy RDS 구성으로 변환됩니다:

{
  "name": "reviews.default.svc.cluster.local:9080",
  "virtual_hosts": [
    {
      "name": "reviews.default.svc.cluster.local:9080",
      "domains": ["reviews.default.svc.cluster.local"],
      "routes": [
        {
          "match": {
            "prefix": "/",
            "headers": [
              {
                "name": "end-user",
                "string_match": {
                  "exact": "jason"
                }
              }
            ]
          },
          "route": {
            "cluster": "outbound|9080|v2|reviews.default.svc.cluster.local"
          }
        },
        {
          "match": {
            "prefix": "/"
          },
          "route": {
            "cluster": "outbound|9080|v1|reviews.default.svc.cluster.local"
          }
        }
      ]
    }
  ]
}

DestinationRule 변환 예시

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: reviews-destination
spec:
  host: reviews
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100

이것은 Envoy CDS 구성으로 변환됩니다:

{
  "name": "outbound|9080|v1|reviews.default.svc.cluster.local",
  "type": "EDS",
  "eds_cluster_config": {
    "service_name": "outbound|9080|v1|reviews.default.svc.cluster.local"
  },
  "circuit_breakers": {
    "thresholds": [
      {
        "max_connections": 100
      }
    ]
  },
  "transport_socket": {
    "name": "envoy.transport_sockets.tls",
    "typed_config": {
      "common_tls_context": {
        "tls_certificate_sds_secret_configs": [
          {
            "name": "default",
            "sds_config": {
              "api_config_source": {
                "api_type": "GRPC",
                "grpc_services": [
                  {
                    "envoy_grpc": {
                      "cluster_name": "sds-grpc"
                    }
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
}

구성 동기화 및 디버깅

proxy-status로 동기화 상태 확인

$ istioctl proxy-status
NAME                    CDS    LDS    EDS    RDS    ECDS   ISTIOD
frontend-v1-xxx.prod    SYNCED SYNCED SYNCED SYNCED        istiod-abc
reviews-v1-yyy.prod     SYNCED SYNCED SYNCED SYNCED        istiod-abc
ratings-v1-zzz.prod     STALE  SYNCED SYNCED SYNCED        istiod-abc

상태 코드:

  • SYNCED: 프록시가 최신 구성을 받음
  • NOT SENT: istiod가 아직 구성을 보내지 않음
  • STALE: istiod가 구성을 보냈지만 ACK를 받지 못함

구성 차이 비교

# istiod가 보낸 구성과 프록시가 가진 구성 비교
istioctl proxy-config all PODNAME -o json > proxy-config.json
istioctl proxy-status PODNAME --diff

성능 고려사항

컨트롤 플레인 확장

  • istiod는 수평 확장 가능 (여러 복제본)
  • 각 Envoy는 하나의 istiod 인스턴스에 연결
  • istiod 장애 시 Envoy는 마지막으로 받은 구성으로 계속 동작

대규모 메시에서의 최적화

  1. Sidecar 리소스 사용: 각 워크로드가 알아야 할 서비스 범위 제한
  2. exportTo 설정: CRD의 가시성 범위 제한
  3. 이벤트 배치 처리: istiod는 짧은 기간 내 여러 변경을 묶어서 푸시
  4. 증분 xDS(Delta xDS): 변경된 부분만 전송
# Sidecar 리소스로 Envoy 메모리 최적화
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
  name: default
  namespace: production
spec:
  egress:
    - hosts:
        - './*' # 같은 네임스페이스 서비스
        - 'istio-system/*' # Istio 시스템 서비스
        - 'monitoring/prometheus' # 특정 외부 서비스

마무리

Istio의 내부 아키텍처를 이해하면 다음과 같은 이점이 있습니다:

  1. 트러블슈팅 능력 향상: xDS 동기화 문제, 사이드카 주입 실패, 인증서 만료 등을 빠르게 진단
  2. 성능 최적화: Sidecar 리소스, 연결 풀 튜닝, 구성 범위 제한 등을 적절히 활용
  3. 보안 강화: mTLS 동작 원리를 이해하고 올바른 PeerAuthentication 설정

다음 글에서는 트래픽 관리 엔진의 내부 동작을 더 깊이 살펴보겠습니다.

Istio Architecture Internals: Control Plane and Data Plane

Introduction

Istio is the most widely adopted service mesh for Kubernetes environments. However, understanding what actually happens internally beyond "creating a VirtualService routes traffic" makes a significant difference in operations and troubleshooting.

This post analyzes the internal mechanisms of how Istio's control plane and data plane interact, and how user-defined CRDs are translated into Envoy configurations.

Istio Architecture Overview

Istio consists of two major parts:

┌─────────────────────────────────────────────────┐
Control Plane│  ┌───────────────────────────────────────────┐  │
│  │              istiod                        │  │
│  │  ┌─────────┐ ┌─────────┐ ┌──────────┐   │  │
│  │  │  Pilot  │ │ Citadel │ │  Galley  │   │  │
│  │    (xDS)  (CA)(Validate)│   │  │
│  │  └─────────┘ └─────────┘ └──────────┘   │  │
│  └───────────────────────────────────────────┘  │
├─────────────────────────────────────────────────┤
Data Plane│  ┌──────────┐  ┌──────────┐  ┌──────────┐     │
│  │ App + EP │  │ App + EP │  │ App + EP │     │
 (Pod A) (Pod B) (Pod C)  │     │
│  └──────────┘  └──────────┘  └──────────┘     │
EP = Envoy Proxy (istio-proxy sidecar)└─────────────────────────────────────────────────┘

istiod: The Unified Control Plane

Historical Background

Before Istio 1.5, Pilot, Citadel, Galley, and Mixer were each deployed as separate microservices. Starting with Istio 1.5, they were unified into a single binary called istiod, and Mixer was completely removed in 1.8.

Pilot: Traffic Management Engine

Pilot is the core of istiod, performing the following roles:

  1. Service Discovery: Watches the Kubernetes API server to track Service, Endpoint, and Pod changes
  2. Configuration Translation: Converts Istio CRDs (VirtualService, DestinationRule, etc.) into Envoy configuration
  3. xDS Server: Pushes translated configurations to each Envoy proxy via gRPC streams
Kubernetes API Server
   ┌─────────┐
Pilot  │ ← Watches Istio CRDs (VirtualService, DestinationRule, Gateway...)
   │         │ ← Watches Kubernetes resources (Service, Endpoints, Pod...)
   └────┬────┘
xDS (gRPC stream)
   ┌─────────┐
Envoy  │ ← Receives LDS, RDS, CDS, EDS, SDS
   └─────────┘

Citadel: Certificate Management

Citadel (now integrated into istiod) manages workload identity and certificates in the mesh:

  • Acts as a CA (Certificate Authority)
  • Issues X.509 certificates to each workload
  • Assigns identity based on the SPIFFE standard
  • Automatic certificate rotation (default 24 hours)

Galley: Configuration Validation

Galley validates Istio configuration:

  • Configuration validation via Kubernetes Admission Webhook
  • CRD schema validation
  • Cross-reference integrity checking (e.g., whether a Gateway referenced by a VirtualService exists)

Envoy Sidecar Injection Mechanism

MutatingWebhookConfiguration

Istio's sidecar injection leverages Kubernetes MutatingAdmissionWebhook:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: istio-sidecar-injector
webhooks:
  - name: sidecar-injector.istio.io
    namespaceSelector:
      matchLabels:
        istio-injection: enabled
    rules:
      - apiGroups: ['']
        apiVersions: ['v1']
        operations: ['CREATE']
        resources: ['pods']

When a pod is created, the following process occurs:

1. kubectl apply -f deployment.yaml
2. Kubernetes API Server calls the Admission Webhook
3. istiod Sidecar Injector modifies the pod spec
4. Modified pod spec is returned
5. Pod is created with the modified spec

Injected Containers

Two containers are added during sidecar injection:

1. istio-init (Init Container)

initContainers:
  - name: istio-init
    image: proxyv2
    command:
      - istio-iptables
      - '-p'
      - '15001' # Envoy outbound port
      - '-z'
      - '15006' # Envoy inbound port
      - '-u'
      - '1337' # istio-proxy UID (traffic from this UID is excluded from redirect)
      - '-m'
      - 'REDIRECT'
    securityContext:
      capabilities:
        add: ['NET_ADMIN', 'NET_RAW']

The istio-init container sets up iptables rules to redirect all inbound/outbound traffic to the Envoy proxy.

2. istio-proxy (Sidecar Container)

containers:
  - name: istio-proxy
    image: proxyv2
    ports:
      - containerPort: 15090 # Prometheus metrics
      - containerPort: 15021 # Health check
    env:
      - name: ISTIO_META_CLUSTER_ID
        value: 'Kubernetes'
      - name: PILOT_CERT_PROVIDER
        value: 'istiod'

iptables Traffic Redirect

The flow of iptables rules set by istio-init:

[Inbound Traffic]
External -> Pod IP:Port
  -> iptables PREROUTING
  -> ISTIO_INBOUND chain
  -> REDIRECT to 15006 (Envoy inbound listener)
  -> Envoy processes then forwards to localhost:AppPort

[Outbound Traffic]
App -> External Service IP:Port
  -> iptables OUTPUT
  -> ISTIO_OUTPUT chain
  -> REDIRECT to 15001 (Envoy outbound listener)
  -> Envoy processes then forwards to actual destination

[Exception]
Traffic from UID 1337 (istio-proxy) is excluded from redirect -> prevents infinite loop

xDS Protocol In Detail

xDS (x Discovery Service) is the API protocol through which Envoy dynamically receives configuration.

xDS API Types

APIFull NameRole
LDSListener Discovery ServiceListener configuration (ports, protocols)
RDSRoute Discovery ServiceHTTP routing rules
CDSCluster Discovery ServiceUpstream cluster definitions
EDSEndpoint Discovery ServiceActual endpoint list within clusters
SDSSecret Discovery ServiceTLS certificates and keys

Configuration Push Flow

[1] User creates a VirtualService
[2] Pilot detects the change via Kubernetes API watch
[3] Pilot translates VirtualService to Envoy RDS configuration
[4] Related CDS and EDS configurations are also generated
[5] Pushed to the workload's Envoy via gRPC stream
[6] Envoy hot-reloads the new configuration (no connection drops)

ADS (Aggregated Discovery Service)

Istio uses ADS to consolidate all xDS responses into a single gRPC stream. This ensures configuration consistency:

  • Ordering guarantee between CDS and EDS (cluster definition first, endpoints after)
  • Ordering guarantee between LDS and RDS
  • Atomic configuration updates

Verifying Configuration

# Check Envoy listeners for a specific pod
istioctl proxy-config listeners PODNAME.NAMESPACE

# Check route configuration
istioctl proxy-config routes PODNAME.NAMESPACE

# Check cluster configuration
istioctl proxy-config clusters PODNAME.NAMESPACE

# Check endpoints
istioctl proxy-config endpoints PODNAME.NAMESPACE

# Full Envoy configuration dump
istioctl proxy-config all PODNAME.NAMESPACE -o json

Envoy Filter Chain Architecture

The Envoy proxy processes requests through a hierarchical filter chain:

[Request Flow]

Listener (port binding)
Filter Chain (select matching filter chain)
    ├── Network Filters
    │   ├── TCP Proxy Filter (L4)
    │   └── HTTP Connection Manager (L7)
    │       │
    │       ├── HTTP Filters
    │       │   ├── RBAC Filter (authorization)
    │       │   ├── JWT Authn Filter (authentication)
    │       │   ├── Fault Injection Filter
    │       │   ├── CORS Filter
    │       │   ├── Stats Filter (metrics)
    │       │   └── Router Filter (final routing)
    │       │
    │       └── Route Configuration
    │           ├── Virtual Host selection
    │           └── Route matching and Cluster determination
Cluster (upstream selection)
Endpoint (actual target pod)

Listener Structure

Listener 0.0.0.0:15006 (Inbound)
├── FilterChain: App port (e.g., 8080)
│   ├── TLS Inspector
│   ├── HTTP Connection Manager
│   │   ├── istio_authn filter
│   │   ├── envoy.filters.http.rbac
│   │   └── envoy.filters.http.router
│   └── Route: inbound|8080|http|service.ns.svc.cluster.local
└── FilterChain: Default (passthrough)

Listener 0.0.0.0:15001 (Outbound)
├── FilterChain: Per-service matching
│   ├── HTTP Connection Manager
│   │   ├── envoy.filters.http.fault
│   │   ├── envoy.filters.http.cors
│   │   ├── istio.stats
│   │   └── envoy.filters.http.router
│   └── Route: Per-service VirtualHost
└── FilterChain: PassthroughCluster (unmatched traffic)

Workload Identity: SPIFFE

SPIFFE ID Scheme

Istio uses the SPIFFE (Secure Production Identity Framework For Everyone) standard:

spiffe://TRUST_DOMAIN/ns/NAMESPACE/sa/SERVICE_ACCOUNT

Example:
spiffe://cluster.local/ns/production/sa/frontend

Certificate Issuance Flow (CSR Flow)

[1] istio-agent (in-pod) generates a key pair
[2] Creates a CSR (Certificate Signing Request)
[3] Sends CSR to istiod (gRPC, authenticated via bootstrap token)
[4] istiod validates the CSR:
    - ServiceAccount token validity
    - Namespace membership verification
[5] istiod CA signs the X.509 certificate
[6] Returns signed certificate to istio-agent
[7] istio-agent delivers the certificate to Envoy via SDS
[8] Envoy uses the certificate for mTLS

SDS (Secret Discovery Service)

Certificates are delivered to Envoy via SDS, not through the filesystem:

  • istio-agent acts as a local SDS server
  • Envoy requests certificates via the SDS API
  • No Envoy restart needed for certificate rotation
  • Certificates are not written to disk, improving security

Configuration Translation: From Istio CRDs to Envoy Config

VirtualService Translation Example

A user-defined VirtualService:

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

This is translated into Envoy RDS configuration:

{
  "name": "reviews.default.svc.cluster.local:9080",
  "virtual_hosts": [
    {
      "name": "reviews.default.svc.cluster.local:9080",
      "domains": ["reviews.default.svc.cluster.local"],
      "routes": [
        {
          "match": {
            "prefix": "/",
            "headers": [
              {
                "name": "end-user",
                "string_match": {
                  "exact": "jason"
                }
              }
            ]
          },
          "route": {
            "cluster": "outbound|9080|v2|reviews.default.svc.cluster.local"
          }
        },
        {
          "match": {
            "prefix": "/"
          },
          "route": {
            "cluster": "outbound|9080|v1|reviews.default.svc.cluster.local"
          }
        }
      ]
    }
  ]
}

DestinationRule Translation Example

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: reviews-destination
spec:
  host: reviews
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100

This is translated into Envoy CDS configuration:

{
  "name": "outbound|9080|v1|reviews.default.svc.cluster.local",
  "type": "EDS",
  "eds_cluster_config": {
    "service_name": "outbound|9080|v1|reviews.default.svc.cluster.local"
  },
  "circuit_breakers": {
    "thresholds": [
      {
        "max_connections": 100
      }
    ]
  },
  "transport_socket": {
    "name": "envoy.transport_sockets.tls",
    "typed_config": {
      "common_tls_context": {
        "tls_certificate_sds_secret_configs": [
          {
            "name": "default",
            "sds_config": {
              "api_config_source": {
                "api_type": "GRPC",
                "grpc_services": [
                  {
                    "envoy_grpc": {
                      "cluster_name": "sds-grpc"
                    }
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
}

Configuration Synchronization and Debugging

Checking Sync Status with proxy-status

$ istioctl proxy-status
NAME                    CDS    LDS    EDS    RDS    ECDS   ISTIOD
frontend-v1-xxx.prod    SYNCED SYNCED SYNCED SYNCED        istiod-abc
reviews-v1-yyy.prod     SYNCED SYNCED SYNCED SYNCED        istiod-abc
ratings-v1-zzz.prod     STALE  SYNCED SYNCED SYNCED        istiod-abc

Status codes:

  • SYNCED: Proxy has received the latest configuration
  • NOT SENT: istiod has not yet sent the configuration
  • STALE: istiod sent the configuration but did not receive an ACK

Comparing Configuration Differences

# Compare configuration sent by istiod with proxy's current config
istioctl proxy-config all PODNAME -o json > proxy-config.json
istioctl proxy-status PODNAME --diff

Performance Considerations

Control Plane Scaling

  • istiod can be horizontally scaled (multiple replicas)
  • Each Envoy connects to a single istiod instance
  • If istiod fails, Envoy continues operating with the last received configuration

Optimization in Large-Scale Meshes

  1. Use Sidecar resources: Limit the scope of services each workload needs to know
  2. Set exportTo: Limit CRD visibility scope
  3. Event batching: istiod batches multiple changes within a short period before pushing
  4. Incremental xDS (Delta xDS): Send only changed portions
# Optimize Envoy memory with Sidecar resource
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
  name: default
  namespace: production
spec:
  egress:
    - hosts:
        - './*' # Same namespace services
        - 'istio-system/*' # Istio system services
        - 'monitoring/prometheus' # Specific external service

Conclusion

Understanding Istio's internal architecture provides these benefits:

  1. Improved troubleshooting: Quickly diagnose xDS sync issues, sidecar injection failures, certificate expiration, etc.
  2. Performance optimization: Properly leverage Sidecar resources, connection pool tuning, and configuration scope limits
  3. Enhanced security: Understand how mTLS works and configure PeerAuthentication correctly

In the next post, we will dive deeper into the internals of the traffic management engine.