Split View: Kubernetes Network Policy와 Service Mesh 완벽 가이드 (Istio, Cilium, Calico 비교)
Kubernetes Network Policy와 Service Mesh 완벽 가이드 (Istio, Cilium, Calico 비교)
- 들어가며
- Kubernetes Network Policy 기초
- Network Policy 심화: Egress, CIDR, 포트 제어
- Service Mesh 아키텍처 비교 (Istio vs Cilium vs Calico)
- Istio 기반 Service Mesh 구축
- Cilium 기반 eBPF Service Mesh
- mTLS와 제로 트러스트 네트워크
- 운영 시 주의사항과 트러블슈팅
- 실패 사례와 복구 절차
- 성능 벤치마크와 선택 가이드
- 마치며
- 참고자료

들어가며
Kubernetes 클러스터에서 Pod 간 통신은 기본적으로 모두 허용(allow-all) 상태입니다. 같은 클러스터 내라면 어떤 Pod든 다른 Pod에 자유롭게 접근할 수 있다는 뜻입니다. 작은 규모의 개발 환경에서는 크게 문제되지 않지만, 프로덕션 환경에서 수십, 수백 개의 마이크로서비스가 동작하는 상황이라면 이는 심각한 보안 위협이 됩니다.
공격자가 하나의 Pod를 탈취하면 클러스터 내 모든 서비스에 횡방향 이동(lateral movement)이 가능해지기 때문입니다. 이를 방지하려면 Network Policy를 통한 네트워크 세그멘테이션과, Service Mesh를 통한 mTLS 암호화 및 제로 트러스트 아키텍처가 필수적입니다.
이 글에서는 Kubernetes Network Policy의 기초부터 심화까지 다루고, Istio, Cilium, Calico 세 가지 솔루션의 Service Mesh 아키텍처를 비교 분석합니다. 실제 운영에서 만날 수 있는 트러블슈팅 사례와 성능 벤치마크까지 포함하여, 여러분의 환경에 가장 적합한 선택을 할 수 있도록 안내합니다.
Kubernetes Network Policy 기초
Network Policy란?
Network Policy는 Kubernetes 네이티브 리소스로, Pod 레벨에서 인바운드(Ingress)와 아웃바운드(Egress) 트래픽을 제어하는 방화벽 규칙입니다. 레이블 셀렉터를 기반으로 동작하며, Pod가 재시작되거나 노드 간 이동하더라도 일관된 정책이 적용됩니다.
중요한 전제 조건: Network Policy 리소스를 생성하더라도 이를 구현하는 CNI 플러그인(Calico, Cilium, Antrea 등)이 없으면 정책이 전혀 적용되지 않습니다. 기본 kubenet이나 Flannel은 Network Policy를 지원하지 않습니다.
Default Deny 정책
모든 네트워크 보안의 시작은 Default Deny 정책입니다. 먼저 모든 트래픽을 차단한 후, 필요한 통신만 명시적으로 허용하는 화이트리스트 방식을 적용합니다.
# default-deny-all.yaml
# 네임스페이스 내 모든 Pod의 Ingress/Egress 트래픽을 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # 빈 셀렉터 = 네임스페이스 내 모든 Pod
policyTypes:
- Ingress
- Egress
이 정책이 적용되면 production 네임스페이스의 모든 Pod는 인바운드/아웃바운드 트래픽이 완전히 차단됩니다. DNS 조회조차 불가능해지므로 반드시 DNS 허용 정책을 함께 적용해야 합니다.
# allow-dns.yaml
# kube-dns(CoreDNS) 접근을 허용하는 정책
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Pod 간 특정 통신 허용
Default Deny 상태에서 프론트엔드가 백엔드 API에 접근하도록 허용하는 예시입니다.
# allow-frontend-to-backend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
이 정책은 app: frontend 레이블을 가진 Pod에서 app: backend-api Pod의 TCP 8080 포트로의 인바운드 트래픽만 허용합니다.
Network Policy 심화: Egress, CIDR, 포트 제어
Egress 정책으로 외부 접근 제어
마이크로서비스가 외부 API나 데이터베이스에 접근하는 경우, Egress 정책으로 허용 대상을 세밀하게 제한할 수 있습니다.
# egress-external-api-and-db.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-egress-policy
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api
policyTypes:
- Egress
egress:
# 1. 같은 네임스페이스의 Redis 접근 허용
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
# 2. 외부 PostgreSQL RDS 접근 (CIDR 기반)
- to:
- ipBlock:
cidr: 10.100.0.0/16
ports:
- protocol: TCP
port: 5432
# 3. 외부 HTTPS API 접근 허용
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
ports:
- protocol: TCP
port: 443
# 4. DNS 허용
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
네임스페이스 간 통신 제어
멀티 테넌트 환경에서 네임스페이스 간 격리는 필수입니다. 특정 네임스페이스에서만 접근을 허용하는 패턴입니다.
# cross-namespace-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring-access
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api
policyTypes:
- Ingress
ingress:
# monitoring 네임스페이스의 Prometheus만 메트릭 스크래핑 허용
- from:
- namespaceSelector:
matchLabels:
team: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
Network Policy의 한계
Kubernetes 기본 Network Policy는 L3/L4 수준(IP, 포트, 프로토콜)의 제어만 가능합니다. 다음과 같은 요구사항은 기본 Network Policy로는 대응할 수 없습니다:
- L7(HTTP 경로, 메서드, 헤더) 기반 필터링
- mTLS 암호화 및 서비스 인증
- 트래픽 관측성(Observability) 및 분산 트레이싱
- 고급 트래픽 관리(카나리 배포, 서킷 브레이커, 리트라이)
- FQDN(도메인) 기반 Egress 제어
이러한 고급 기능이 필요할 때 Service Mesh가 등장합니다.
Service Mesh 아키텍처 비교 (Istio vs Cilium vs Calico)
세 가지 주요 솔루션의 아키텍처와 기능을 비교합니다.
| 항목 | Istio (Ambient Mode) | Cilium Service Mesh | Calico (Enterprise) |
|---|---|---|---|
| 데이터 플레인 | ztunnel(L4) + Waypoint Proxy(L7) | eBPF(L3/L4) + 노드별 Envoy(L7) | iptables/eBPF + Envoy(L7) |
| 사이드카 | 불필요 (Ambient Mode) | 불필요 | 선택적 |
| mTLS | 자동 (HBONE 프로토콜) | WireGuard/IPsec | WireGuard 수동 설정 |
| L7 정책 | AuthorizationPolicy | CiliumNetworkPolicy | GlobalNetworkPolicy |
| 관측성 | Kiali, Jaeger, Prometheus | Hubble (내장) | Calico Enterprise UI |
| 성능 오버헤드 | 중간 (ztunnel 경유) | 낮음 (커널 레벨) | 중간 |
| CPU 사용량 | 보통 | 30% 적음 (L4 기준) | 보통 |
| QPS 성능 | 높음 (저연결 시 우수) | 높음 (고연결 시 우수) | 보통 |
| 멀티 클러스터 | 지원 (East-West Gateway) | Cluster Mesh 지원 | Federation 지원 |
| 학습 곡선 | 높음 | 중간 | 중간 |
| 커뮤니티 | 매우 큼 (CNCF Graduated) | 큼 (CNCF Graduated) | 큼 (Tigera 주도) |
| Windows 노드 | 미지원 | 미지원 | 지원 |
| 최적 사용 사례 | 대규모 멀티 클러스터, L7 정밀 제어 | 고성능 L4, eBPF 기반 관측 | 하이브리드 환경, 엔터프라이즈 규정 준수 |
아키텍처 선택 기준
- 순수 L3/L4 네트워크 보안만 필요: Kubernetes 기본 Network Policy + Calico/Cilium CNI
- L7 트래픽 관리 + mTLS가 핵심: Istio Ambient Mode
- 고성능 + 커널 레벨 관측성: Cilium Service Mesh
- 엔터프라이즈 규정 준수 + 하이브리드: Calico Enterprise
Istio 기반 Service Mesh 구축
Istio Ambient Mode 설치
Istio 1.24부터 Ambient Mode가 정식 GA 되었습니다. 기존 사이드카 방식 대비 CPU/메모리 오버헤드를 90% 이상 줄이면서도 mTLS와 L7 트래픽 관리를 제공합니다.
# istioctl 설치
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.24.2 sh -
export PATH="$HOME/istio-1.24.2/bin:$PATH"
# Ambient 프로파일로 설치
istioctl install --set profile=ambient --skip-confirmation
# 설치 확인
kubectl get pods -n istio-system
# NAME READY STATUS RESTARTS AGE
# istiod-7b69f4b6c-xxxxx 1/1 Running 0 60s
# ztunnel-xxxxx 1/1 Running 0 60s
# istio-cni-node-xxxxx 1/1 Running 0 60s
# 네임스페이스에 Ambient 모드 활성화
kubectl label namespace production istio.io/dataplane-mode=ambient
Waypoint Proxy 배포 (L7 정책용)
L4 수준의 mTLS만 필요하다면 ztunnel만으로 충분합니다. L7 수준의 정밀한 트래픽 제어가 필요하면 Waypoint Proxy를 추가 배포합니다.
# Waypoint Proxy 생성
istioctl waypoint apply --namespace production --name backend-waypoint
# 특정 서비스에 Waypoint 연결
kubectl label service backend-api \
istio.io/use-waypoint=backend-waypoint \
-n production
Istio AuthorizationPolicy 설정
Istio의 L7 정책은 AuthorizationPolicy를 통해 HTTP 메서드, 경로, 헤더 수준까지 제어합니다.
# istio-auth-policy.yaml
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: backend-api-policy
namespace: production
spec:
targetRefs:
- kind: Service
group: ''
name: backend-api
action: ALLOW
rules:
- from:
- source:
principals:
- 'cluster.local/ns/production/sa/frontend'
to:
- operation:
methods: ['GET', 'POST']
paths: ['/api/v1/*']
- from:
- source:
principals:
- 'cluster.local/ns/monitoring/sa/prometheus'
to:
- operation:
methods: ['GET']
paths: ['/metrics']
이 정책은 frontend 서비스 어카운트에서 /api/v1/ 경로로의 GET, POST만 허용하고, Prometheus에서 /metrics 경로로의 GET만 허용합니다. 그 외 모든 요청은 403 Forbidden으로 거부됩니다.
Cilium 기반 eBPF Service Mesh
Cilium 설치 및 Service Mesh 활성화
Cilium은 eBPF를 활용하여 커널 레벨에서 네트워킹을 처리합니다. 사이드카 프록시 없이 L4 트래픽을 처리하고, L7 처리가 필요한 경우에만 노드별 공유 Envoy 프록시를 사용합니다.
# Cilium CLI 설치
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
curl -L --fail --remote-name-all \
"https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-${GOOS}-${GOARCH}.tar.gz"
sudo tar xzvfC "cilium-${GOOS}-${GOARCH}.tar.gz" /usr/local/bin
# Helm으로 Cilium 설치 (Service Mesh + Hubble 활성화)
helm repo add cilium https://helm.cilium.io/
helm repo update
helm install cilium cilium/cilium --version 1.17.0 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set envoy.enabled=true \
--set encryption.enabled=true \
--set encryption.type=wireguard
# 설치 확인
cilium status --wait
cilium connectivity test
CiliumNetworkPolicy로 L7 정책 적용
Cilium은 자체 CRD인 CiliumNetworkPolicy를 통해 HTTP, gRPC, Kafka 등 L7 프로토콜 수준의 정밀한 정책을 지원합니다.
# cilium-l7-policy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: backend-l7-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend-api
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
- method: 'GET'
path: '/api/v1/products'
- method: 'POST'
path: '/api/v1/orders'
- method: 'GET'
path: '/healthz'
- fromEndpoints:
- matchLabels:
app: prometheus
toPorts:
- ports:
- port: '9090'
protocol: TCP
rules:
http:
- method: 'GET'
path: '/metrics'
Hubble을 활용한 네트워크 관측
Cilium의 Hubble은 eBPF 기반으로 모든 네트워크 플로우를 실시간 모니터링합니다.
# Hubble CLI 설치 후 관측
hubble observe --namespace production --follow
# 특정 Pod의 트래픽만 필터링
hubble observe --namespace production \
--to-label app=backend-api \
--verdict DROPPED
# HTTP 요청 관측 (L7)
hubble observe --namespace production \
--protocol http \
--http-status 5xx
# 네트워크 플로우 시각화 (Hubble UI)
cilium hubble port-forward &
# 브라우저에서 http://localhost:12000 접속
Hubble의 출력 예시:
TIMESTAMP SOURCE DESTINATION TYPE VERDICT SUMMARY
Mar 14 10:23:01.123 production/frontend production/backend-api L7/HTTP FORWARDED GET /api/v1/products => 200
Mar 14 10:23:01.456 production/attacker production/backend-api L7/HTTP DROPPED POST /api/v1/admin => Policy denied
Mar 14 10:23:02.789 production/backend-api production/redis L4/TCP FORWARDED TCP 6379
mTLS와 제로 트러스트 네트워크
제로 트러스트란?
제로 트러스트(Zero Trust)는 "아무것도 신뢰하지 않고 모든 것을 검증한다"는 보안 모델입니다. 클러스터 내부 통신도 암호화하고, 모든 서비스 간 호출에서 신원을 검증합니다. Network Policy만으로는 트래픽 암호화가 불가능하기 때문에, mTLS(mutual TLS)를 제공하는 Service Mesh가 필요합니다.
Istio Ambient Mode의 mTLS
Istio Ambient Mode는 HBONE(HTTP-Based Overlay Network Environment) 프로토콜을 사용하여 모든 트래픽을 자동으로 mTLS 암호화합니다. ztunnel이 노드 레벨에서 인증서를 관리하며, 각 Pod마다 고유한 SPIFFE 기반 워크로드 ID를 발급합니다.
# istio-peer-auth.yaml
# STRICT 모드: mTLS가 아닌 평문 트래픽 거부
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: production
spec:
mtls:
mode: STRICT
STRICT 모드를 설정하면 해당 네임스페이스의 모든 서비스는 mTLS 연결만 수락합니다. 메시에 포함되지 않은 서비스로부터의 평문 요청은 모두 거부됩니다.
Cilium의 WireGuard 기반 암호화
Cilium은 커널 내장 WireGuard를 사용하여 노드 간 트래픽을 자동 암호화합니다. Istio의 mTLS와 달리 애플리케이션 레벨이 아닌 커널 레벨에서 작동하므로 성능 오버헤드가 적습니다.
# WireGuard 암호화 상태 확인
cilium encrypt status
# 출력 예시:
# Encryption: Wireguard
# Keys in use: 2
# Errors: 0
# Interfaces: cilium_wg0
# 암호화 키 목록 확인
cilium encrypt get
WireGuard와 mTLS의 차이점:
- WireGuard: 노드 간 L3 수준 암호화, 커널 레벨 처리, Pod 개별 ID 미부여
- mTLS (Istio): 서비스 간 L7 수준 암호화, SPIFFE 기반 워크로드 ID, 세밀한 인가 정책
프로덕션 환경에서는 Cilium WireGuard로 노드 간 암호화를 적용하고, 추가로 Istio mTLS를 통해 워크로드 레벨 인증까지 구현하는 이중 보안 전략을 사용하기도 합니다.
운영 시 주의사항과 트러블슈팅
1. Network Policy 적용 순서 주의
Network Policy는 합집합(additive) 방식으로 동작합니다. 여러 정책이 동일 Pod에 적용되면 허용 규칙이 합산됩니다. 충돌하는 정책이 있을 때 거부 규칙이 우선하는 것이 아니라, 어느 하나라도 허용하면 트래픽이 통과합니다.
# 특정 Pod에 적용된 모든 Network Policy 확인
kubectl get networkpolicy -n production -o wide
# Pod 레이블 확인 (정책 셀렉터 매칭 검증)
kubectl get pods -n production --show-labels
# Calico를 사용하는 경우 정책 매칭 확인
calicoctl get networkpolicy -n production -o yaml
2. CNI 플러그인 미설치 상태에서 Network Policy 무시
가장 흔한 실수입니다. Network Policy 리소스를 생성해도 이를 구현하는 CNI 플러그인이 없으면 정책이 전혀 적용되지 않습니다.
# CNI 플러그인 확인
kubectl get pods -n kube-system | grep -E 'calico|cilium|antrea'
# Network Policy가 실제로 적용되는지 검증하는 테스트
# 1. Default Deny 적용
kubectl apply -f default-deny-all.yaml
# 2. 통신 테스트 (차단되어야 정상)
kubectl exec -n production deploy/frontend -- \
curl -s --connect-timeout 3 http://backend-api:8080/healthz
# 타임아웃이 발생하면 정책이 제대로 적용된 것
3. DNS 해결 실패
Default Deny 정책 적용 후 DNS 허용을 누락하면 모든 서비스 디스커버리가 중단됩니다.
# DNS 문제 진단
kubectl exec -n production deploy/frontend -- nslookup backend-api
# ;; connection timed out; no servers could be reached
# CoreDNS Pod 확인
kubectl get pods -n kube-system -l k8s-app=kube-dns
# DNS 정책 적용 후 재테스트
kubectl apply -f allow-dns.yaml
kubectl exec -n production deploy/frontend -- nslookup backend-api
# Server: 10.96.0.10
# Name: backend-api.production.svc.cluster.local
4. Istio ztunnel 장애 대응
ztunnel은 노드별 DaemonSet으로 실행되며, 장애 시 해당 노드의 모든 Ambient Mesh 트래픽이 중단됩니다.
# ztunnel 상태 확인
kubectl get pods -n istio-system -l app=ztunnel
# ztunnel 로그 확인 (인증서 문제 진단)
kubectl logs -n istio-system -l app=ztunnel --tail=50
# ztunnel 재시작
kubectl rollout restart daemonset/ztunnel -n istio-system
# Istiod와의 xDS 연결 상태 확인
istioctl proxy-status
5. Cilium eBPF 맵 용량 초과
대규모 클러스터에서 Cilium eBPF 맵의 기본 크기가 부족할 수 있습니다.
# eBPF 맵 사용량 확인
cilium bpf ct list global | wc -l
cilium bpf policy get --all
# 맵 크기 증가 (Helm values 수정)
# bpf.ctGlobalTCPMax: 524288 (기본값보다 증가)
# bpf.ctGlobalAnyMax: 262144
# bpf.policyMapMax: 65536
# 변경 적용
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set bpf.ctGlobalTCPMax=524288
실패 사례와 복구 절차
사례 1: 잘못된 Egress 정책으로 전체 서비스 장애
상황: 운영팀이 보안 강화를 위해 Default Deny Egress를 적용했으나, DNS 허용 정책을 누락하여 모든 서비스 간 통신이 중단됨.
증상: 모든 Pod에서 서비스 이름으로의 접근이 실패. IP 직접 지정 시에는 통신 가능.
복구 절차:
# 1. 즉시 문제 확인
kubectl get networkpolicy -n production
# 2. DNS 허용 정책 긴급 적용
kubectl apply -f - <<'POLICY'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: emergency-allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
POLICY
# 3. 서비스 복구 확인
kubectl exec -n production deploy/frontend -- nslookup backend-api
교훈: Default Deny 정책은 반드시 DNS 허용 정책과 함께 적용해야 합니다. 정책 변경 전에 반드시 스테이징 환경에서 테스트하고, 롤백 계획을 준비하세요.
사례 2: Istio 업그레이드 중 mTLS 불일치
상황: Istio 버전 업그레이드 과정에서 구버전 사이드카와 신버전 ztunnel 간 mTLS 핸드셰이크 실패.
증상: 일부 서비스 간 503 에러 및 "upstream connect error" 메시지 발생.
복구 절차:
# 1. mTLS 모드를 임시로 PERMISSIVE로 변경 (평문+mTLS 모두 허용)
kubectl apply -f - <<'POLICY'
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: permissive-during-upgrade
namespace: production
spec:
mtls:
mode: PERMISSIVE
POLICY
# 2. 모든 워크로드 재시작하여 최신 프록시 적용
kubectl rollout restart deployment -n production
# 3. 모든 Pod가 새 버전으로 교체된 후 STRICT 복원
kubectl rollout status deployment -n production --timeout=300s
kubectl apply -f - <<'POLICY'
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: production
spec:
mtls:
mode: STRICT
POLICY
사례 3: Cilium Agent 재시작으로 인한 순간 트래픽 드롭
상황: Cilium DaemonSet 업데이트 중 노드의 eBPF 프로그램이 잠시 언로드되어 해당 노드의 Pod 간 통신이 수 초간 중단.
복구 및 예방:
# Rolling Update 전략으로 한 노드씩 업데이트
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set upgradeCompatibility=1.16 \
--set rollOutCiliumPods=true
# PodDisruptionBudget 확인
kubectl get pdb -n kube-system
# 업데이트 진행 상황 모니터링
kubectl rollout status daemonset/cilium -n kube-system --timeout=600s
성능 벤치마크와 선택 가이드
실측 벤치마크 결과 (2025년 기준)
최근 대규모 엔터프라이즈 환경에서의 비교 테스트 결과를 요약합니다.
| 메트릭 | Network Policy Only | Istio Ambient | Cilium Service Mesh |
|---|---|---|---|
| P99 Latency (ms) | 1.2 | 3.8 | 2.1 |
| QPS (요청/초) | 45,000 | 38,000 | 42,000 |
| QPS per Core | - | 2,178 | 1,815 |
| CPU 오버헤드 | 기준 | +15% | +8% |
| 메모리 오버헤드 | 기준 | +120MB/노드 | +80MB/노드 |
| 저연결 성능 | - | 우수 | 보통 |
| 고연결 성능 | - | 보통 | 우수 |
참고: Istio의 QPS per Core가 높은 것은 L7 처리 능력이 포함된 수치이며, Cilium의 CPU 측정에는 커널 내 WireGuard 암호화 비용이 제외된 점을 고려해야 합니다.
선택 가이드 플로우차트
-
L3/L4 네트워크 격리만 필요한가?
- 예: Kubernetes Network Policy + Calico 또는 Cilium CNI로 충분
- 아니오: 2번으로
-
L7 트래픽 관리(카나리, 리트라이, 서킷 브레이커)가 필요한가?
- 예: Istio Ambient Mode 또는 Cilium + Envoy
- 아니오: 3번으로
-
mTLS 기반 제로 트러스트가 요구사항인가?
- 예: Istio Ambient Mode (SPIFFE 기반 워크로드 ID)
- 아니오: Cilium WireGuard 암호화로 노드 간 암호화
-
고성능 + 커널 레벨 관측성이 우선인가?
- 예: Cilium Service Mesh + Hubble
- 아니오: Istio (더 풍부한 L7 기능)
-
Windows 노드 혼용 또는 하이브리드 환경인가?
- 예: Calico Enterprise
- 아니오: Istio 또는 Cilium
운영 규모별 권장사항
- 소규모 클러스터 (노드 10개 이하): Cilium CNI + 기본 Network Policy. Service Mesh 도입은 오버헤드 대비 이점이 적음.
- 중규모 클러스터 (노드 10~100개): Cilium Service Mesh 또는 Istio Ambient. L7 요구사항에 따라 선택.
- 대규모 클러스터 (노드 100개 이상): Istio Ambient Mode. 성숙한 멀티 클러스터 지원, 풍부한 에코시스템, 안정성.
- 하이브리드/멀티 클라우드: Calico Enterprise 또는 Cilium Cluster Mesh.
마치며
Kubernetes 네트워크 보안은 단순히 Network Policy를 적용하는 것을 넘어, 애플리케이션의 특성과 보안 요구사항에 맞는 전체적인 전략이 필요합니다.
핵심 요약:
- Network Policy는 기본 중의 기본: Default Deny로 시작하여 필요한 통신만 허용하는 화이트리스트 방식을 반드시 적용하세요. DNS 허용 정책을 잊지 마세요.
- Service Mesh는 필요할 때 도입: mTLS, L7 정책, 고급 트래픽 관리가 실제로 필요한 시점에 도입하세요. 불필요한 복잡성은 오히려 운영 부담을 증가시킵니다.
- Istio vs Cilium은 트레이드오프: Istio는 L7 기능과 생태계가 풍부하고, Cilium은 커널 레벨 성능과 관측성이 강점입니다. 요구사항에 맞게 선택하세요.
- 점진적 도입이 핵심: Default Deny 정책부터 시작하여, Network Policy를 충분히 검증한 후, 필요에 따라 Service Mesh를 추가하는 단계적 접근이 가장 안전합니다.
- 자동화와 테스트: 정책 변경은 반드시 CI/CD 파이프라인을 통해 스테이징에서 먼저 검증하고, 롤백 계획을 항상 준비하세요.
네트워크 보안은 한 번 설정하고 끝나는 것이 아닙니다. 서비스가 변화함에 따라 정책도 지속적으로 리뷰하고 업데이트해야 합니다. 분기별 정책 감사를 권장하며, Hubble이나 Kiali 같은 관측 도구를 활용하여 실제 트래픽 패턴을 기반으로 정책을 최적화하시기 바랍니다.
참고자료
Complete Guide to Kubernetes Network Policy and Service Mesh (Istio, Cilium, Calico Comparison)
- Introduction
- Kubernetes Network Policy Basics
- Advanced Network Policy: Egress, CIDR, and Port Control
- Service Mesh Architecture Comparison (Istio vs Cilium vs Calico)
- Building Service Mesh with Istio
- Cilium eBPF-based Service Mesh
- mTLS and Zero Trust Networking
- Operational Considerations and Troubleshooting
- Failure Cases and Recovery Procedures
- Performance Benchmarks and Selection Guide
- Conclusion
- References

Introduction
In a Kubernetes cluster, Pod-to-Pod communication is allow-all by default. This means any Pod can freely access any other Pod within the same cluster. While this isn't a major issue in small-scale development environments, it becomes a serious security threat in production environments where dozens or hundreds of microservices are running.
If an attacker compromises a single Pod, lateral movement to all services within the cluster becomes possible. To prevent this, Network Policy for network segmentation and Service Mesh for mTLS encryption and zero trust architecture are essential.
This article covers Kubernetes Network Policy from basics to advanced topics, and provides a comparative analysis of three major Service Mesh solutions: Istio, Cilium, and Calico. It includes real-world troubleshooting cases and performance benchmarks to help you make the best choice for your environment.
Kubernetes Network Policy Basics
What is Network Policy?
Network Policy is a Kubernetes-native resource that acts as a firewall rule controlling inbound (Ingress) and outbound (Egress) traffic at the Pod level. It operates based on label selectors and provides consistent policy enforcement even when Pods are restarted or moved between nodes.
Important prerequisite: Even if you create Network Policy resources, the policies will not take effect without a CNI plugin (Calico, Cilium, Antrea, etc.) that implements them. Default kubenet and Flannel do not support Network Policy.
Default Deny Policy
The starting point for all network security is the Default Deny policy. First block all traffic, then apply a whitelist approach that explicitly allows only necessary communication.
# default-deny-all.yaml
# Block all Ingress/Egress traffic for all Pods in the namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # Empty selector = all Pods in namespace
policyTypes:
- Ingress
- Egress
Once this policy is applied, all Pods in the production namespace will have both inbound and outbound traffic completely blocked. Since DNS lookups will also fail, you must apply a DNS allow policy alongside it.
# allow-dns.yaml
# Policy to allow access to kube-dns (CoreDNS)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Allowing Specific Pod-to-Pod Communication
Here's an example of allowing frontend access to the backend API from a Default Deny state.
# allow-frontend-to-backend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
This policy allows only inbound traffic from Pods with the app: frontend label to TCP port 8080 of app: backend-api Pods.
Advanced Network Policy: Egress, CIDR, and Port Control
Controlling External Access with Egress Policy
When microservices need to access external APIs or databases, Egress policies can precisely restrict allowed targets.
# egress-external-api-and-db.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-egress-policy
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api
policyTypes:
- Egress
egress:
# 1. Allow access to Redis in the same namespace
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
# 2. Allow access to external PostgreSQL RDS (CIDR-based)
- to:
- ipBlock:
cidr: 10.100.0.0/16
ports:
- protocol: TCP
port: 5432
# 3. Allow external HTTPS API access
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
ports:
- protocol: TCP
port: 443
# 4. Allow DNS
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
Cross-Namespace Communication Control
Namespace isolation is essential in multi-tenant environments. Here's a pattern that allows access from specific namespaces only.
# cross-namespace-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring-access
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api
policyTypes:
- Ingress
ingress:
# Allow metrics scraping only from Prometheus in the monitoring namespace
- from:
- namespaceSelector:
matchLabels:
team: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
Limitations of Network Policy
Kubernetes basic Network Policy only supports L3/L4 level (IP, port, protocol) control. The following requirements cannot be addressed with basic Network Policy:
- L7 (HTTP path, method, header) based filtering
- mTLS encryption and service authentication
- Traffic observability and distributed tracing
- Advanced traffic management (canary deployments, circuit breakers, retries)
- FQDN (domain) based Egress control
Service Mesh comes into play when these advanced features are needed.
Service Mesh Architecture Comparison (Istio vs Cilium vs Calico)
Here's a comparison of the architecture and features of three major solutions.
| Category | Istio (Ambient Mode) | Cilium Service Mesh | Calico (Enterprise) |
|---|---|---|---|
| Data Plane | ztunnel(L4) + Waypoint Proxy(L7) | eBPF(L3/L4) + per-node Envoy(L7) | iptables/eBPF + Envoy(L7) |
| Sidecar | Not required (Ambient Mode) | Not required | Optional |
| mTLS | Automatic (HBONE protocol) | WireGuard/IPsec | WireGuard manual setup |
| L7 Policy | AuthorizationPolicy | CiliumNetworkPolicy | GlobalNetworkPolicy |
| Observability | Kiali, Jaeger, Prometheus | Hubble (built-in) | Calico Enterprise UI |
| Performance Overhead | Medium (via ztunnel) | Low (kernel level) | Medium |
| CPU Usage | Moderate | 30% less (L4 baseline) | Moderate |
| QPS Performance | High (excellent at low connections) | High (excellent at high connections) | Moderate |
| Multi-cluster | Supported (East-West Gateway) | Cluster Mesh supported | Federation supported |
| Learning Curve | High | Medium | Medium |
| Community | Very large (CNCF Graduated) | Large (CNCF Graduated) | Large (Tigera-led) |
| Windows Nodes | Not supported | Not supported | Supported |
| Best Use Case | Large multi-cluster, precise L7 control | High-performance L4, eBPF-based observability | Hybrid environments, enterprise compliance |
Architecture Selection Criteria
- Only L3/L4 network security needed: Kubernetes basic Network Policy + Calico/Cilium CNI
- L7 traffic management + mTLS is key: Istio Ambient Mode
- High performance + kernel-level observability: Cilium Service Mesh
- Enterprise compliance + hybrid: Calico Enterprise
Building Service Mesh with Istio
Installing Istio Ambient Mode
Istio Ambient Mode became GA starting from Istio 1.24. It provides mTLS and L7 traffic management while reducing CPU/memory overhead by over 90% compared to the traditional sidecar approach.
# Install istioctl
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.24.2 sh -
export PATH="$HOME/istio-1.24.2/bin:$PATH"
# Install with Ambient profile
istioctl install --set profile=ambient --skip-confirmation
# Verify installation
kubectl get pods -n istio-system
# NAME READY STATUS RESTARTS AGE
# istiod-7b69f4b6c-xxxxx 1/1 Running 0 60s
# ztunnel-xxxxx 1/1 Running 0 60s
# istio-cni-node-xxxxx 1/1 Running 0 60s
# Enable Ambient mode for namespace
kubectl label namespace production istio.io/dataplane-mode=ambient
Deploying Waypoint Proxy (for L7 policies)
If only L4-level mTLS is needed, ztunnel alone is sufficient. Deploy a Waypoint Proxy when you need L7-level precise traffic control.
# Create Waypoint Proxy
istioctl waypoint apply --namespace production --name backend-waypoint
# Connect Waypoint to specific service
kubectl label service backend-api \
istio.io/use-waypoint=backend-waypoint \
-n production
Istio AuthorizationPolicy Configuration
Istio's L7 policies control down to HTTP methods, paths, and headers through AuthorizationPolicy.
# istio-auth-policy.yaml
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: backend-api-policy
namespace: production
spec:
targetRefs:
- kind: Service
group: ''
name: backend-api
action: ALLOW
rules:
- from:
- source:
principals:
- 'cluster.local/ns/production/sa/frontend'
to:
- operation:
methods: ['GET', 'POST']
paths: ['/api/v1/*']
- from:
- source:
principals:
- 'cluster.local/ns/monitoring/sa/prometheus'
to:
- operation:
methods: ['GET']
paths: ['/metrics']
This policy allows only GET and POST to /api/v1/ paths from the frontend service account, and only GET to /metrics from Prometheus. All other requests are rejected with 403 Forbidden.
Cilium eBPF-based Service Mesh
Installing Cilium and Enabling Service Mesh
Cilium leverages eBPF to handle networking at the kernel level. It processes L4 traffic without sidecar proxies and uses a per-node shared Envoy proxy only when L7 processing is needed.
# Install Cilium CLI
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
curl -L --fail --remote-name-all \
"https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-${GOOS}-${GOARCH}.tar.gz"
sudo tar xzvfC "cilium-${GOOS}-${GOARCH}.tar.gz" /usr/local/bin
# Install Cilium with Helm (Service Mesh + Hubble enabled)
helm repo add cilium https://helm.cilium.io/
helm repo update
helm install cilium cilium/cilium --version 1.17.0 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set envoy.enabled=true \
--set encryption.enabled=true \
--set encryption.type=wireguard
# Verify installation
cilium status --wait
cilium connectivity test
Applying L7 Policies with CiliumNetworkPolicy
Cilium supports precise L7 protocol-level policies for HTTP, gRPC, Kafka, and more through its own CRD, CiliumNetworkPolicy.
# cilium-l7-policy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: backend-l7-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend-api
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
- method: 'GET'
path: '/api/v1/products'
- method: 'POST'
path: '/api/v1/orders'
- method: 'GET'
path: '/healthz'
- fromEndpoints:
- matchLabels:
app: prometheus
toPorts:
- ports:
- port: '9090'
protocol: TCP
rules:
http:
- method: 'GET'
path: '/metrics'
Network Observability with Hubble
Cilium's Hubble monitors all network flows in real-time based on eBPF.
# Observe after installing Hubble CLI
hubble observe --namespace production --follow
# Filter traffic for specific Pod
hubble observe --namespace production \
--to-label app=backend-api \
--verdict DROPPED
# Observe HTTP requests (L7)
hubble observe --namespace production \
--protocol http \
--http-status 5xx
# Visualize network flows (Hubble UI)
cilium hubble port-forward &
# Access http://localhost:12000 in browser
Hubble output example:
TIMESTAMP SOURCE DESTINATION TYPE VERDICT SUMMARY
Mar 14 10:23:01.123 production/frontend production/backend-api L7/HTTP FORWARDED GET /api/v1/products => 200
Mar 14 10:23:01.456 production/attacker production/backend-api L7/HTTP DROPPED POST /api/v1/admin => Policy denied
Mar 14 10:23:02.789 production/backend-api production/redis L4/TCP FORWARDED TCP 6379
mTLS and Zero Trust Networking
What is Zero Trust?
Zero Trust is a security model of "trust nothing, verify everything." It encrypts communication within the cluster and verifies identity in every service-to-service call. Since Network Policy alone cannot encrypt traffic, a Service Mesh providing mTLS (mutual TLS) is required.
Istio Ambient Mode's mTLS
Istio Ambient Mode uses the HBONE (HTTP-Based Overlay Network Environment) protocol to automatically mTLS-encrypt all traffic. ztunnel manages certificates at the node level and issues a unique SPIFFE-based workload ID for each Pod.
# istio-peer-auth.yaml
# STRICT mode: Reject plaintext traffic without mTLS
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: production
spec:
mtls:
mode: STRICT
When STRICT mode is set, all services in the namespace will only accept mTLS connections. Plaintext requests from services not included in the mesh are all rejected.
Cilium's WireGuard-based Encryption
Cilium uses kernel-built-in WireGuard to automatically encrypt inter-node traffic. Unlike Istio's mTLS, it operates at the kernel level rather than the application level, resulting in less performance overhead.
# Check WireGuard encryption status
cilium encrypt status
# Output example:
# Encryption: Wireguard
# Keys in use: 2
# Errors: 0
# Interfaces: cilium_wg0
# Check encryption key list
cilium encrypt get
Differences between WireGuard and mTLS:
- WireGuard: L3-level inter-node encryption, kernel-level processing, no individual Pod identity
- mTLS (Istio): L7-level inter-service encryption, SPIFFE-based workload ID, fine-grained authorization policies
In production environments, a dual security strategy is sometimes used: applying Cilium WireGuard for inter-node encryption while additionally implementing Istio mTLS for workload-level authentication.
Operational Considerations and Troubleshooting
1. Network Policy Application Order
Network Policies work in an additive (union) manner. When multiple policies apply to the same Pod, allow rules are aggregated. When conflicting policies exist, deny rules do NOT take priority; if any single policy allows the traffic, it passes through.
# Check all Network Policies applied to specific Pod
kubectl get networkpolicy -n production -o wide
# Check Pod labels (verify policy selector matching)
kubectl get pods -n production --show-labels
# For Calico, verify policy matching
calicoctl get networkpolicy -n production -o yaml
2. Network Policy Ignored Without CNI Plugin
This is the most common mistake. Even if Network Policy resources are created, policies are not enforced at all without a CNI plugin that implements them.
# Check CNI plugin
kubectl get pods -n kube-system | grep -E 'calico|cilium|antrea'
# Test to verify Network Policy is actually enforced
# 1. Apply Default Deny
kubectl apply -f default-deny-all.yaml
# 2. Test communication (should be blocked)
kubectl exec -n production deploy/frontend -- \
curl -s --connect-timeout 3 http://backend-api:8080/healthz
# Timeout indicates policy is properly enforced
3. DNS Resolution Failure
If DNS allow is omitted after applying a Default Deny policy, all service discovery will be disrupted.
# Diagnose DNS issue
kubectl exec -n production deploy/frontend -- nslookup backend-api
# ;; connection timed out; no servers could be reached
# Check CoreDNS Pods
kubectl get pods -n kube-system -l k8s-app=kube-dns
# Re-test after applying DNS policy
kubectl apply -f allow-dns.yaml
kubectl exec -n production deploy/frontend -- nslookup backend-api
# Server: 10.96.0.10
# Name: backend-api.production.svc.cluster.local
4. Istio ztunnel Failure Response
ztunnel runs as a per-node DaemonSet, and when it fails, all Ambient Mesh traffic on that node is disrupted.
# Check ztunnel status
kubectl get pods -n istio-system -l app=ztunnel
# Check ztunnel logs (diagnose certificate issues)
kubectl logs -n istio-system -l app=ztunnel --tail=50
# Restart ztunnel
kubectl rollout restart daemonset/ztunnel -n istio-system
# Check xDS connection status with Istiod
istioctl proxy-status
5. Cilium eBPF Map Capacity Exceeded
In large-scale clusters, the default eBPF map sizes in Cilium may be insufficient.
# Check eBPF map usage
cilium bpf ct list global | wc -l
cilium bpf policy get --all
# Increase map sizes (modify Helm values)
# bpf.ctGlobalTCPMax: 524288 (increase from default)
# bpf.ctGlobalAnyMax: 262144
# bpf.policyMapMax: 65536
# Apply changes
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set bpf.ctGlobalTCPMax=524288
Failure Cases and Recovery Procedures
Case 1: Full Service Outage from Incorrect Egress Policy
Situation: The operations team applied Default Deny Egress for security hardening but omitted the DNS allow policy, disrupting all inter-service communication.
Symptoms: Access via service names failed from all Pods. Direct IP access still worked.
Recovery procedure:
# 1. Immediately identify the problem
kubectl get networkpolicy -n production
# 2. Urgently apply DNS allow policy
kubectl apply -f - <<'POLICY'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: emergency-allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
POLICY
# 3. Verify service recovery
kubectl exec -n production deploy/frontend -- nslookup backend-api
Lesson: Default Deny policies must always be applied alongside DNS allow policies. Always test in a staging environment before making policy changes, and prepare a rollback plan.
Case 2: mTLS Mismatch During Istio Upgrade
Situation: During an Istio version upgrade, mTLS handshake failures occurred between old-version sidecars and new-version ztunnel.
Symptoms: 503 errors and "upstream connect error" messages between some services.
Recovery procedure:
# 1. Temporarily change mTLS mode to PERMISSIVE (allow both plaintext+mTLS)
kubectl apply -f - <<'POLICY'
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: permissive-during-upgrade
namespace: production
spec:
mtls:
mode: PERMISSIVE
POLICY
# 2. Restart all workloads to apply latest proxy
kubectl rollout restart deployment -n production
# 3. Restore STRICT after all Pods are replaced with new version
kubectl rollout status deployment -n production --timeout=300s
kubectl apply -f - <<'POLICY'
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: production
spec:
mtls:
mode: STRICT
POLICY
Case 3: Momentary Traffic Drop Due to Cilium Agent Restart
Situation: During a Cilium DaemonSet update, the eBPF programs on the node were briefly unloaded, interrupting Pod-to-Pod communication on that node for several seconds.
Recovery and prevention:
# Rolling Update strategy to update one node at a time
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set upgradeCompatibility=1.16 \
--set rollOutCiliumPods=true
# Check PodDisruptionBudget
kubectl get pdb -n kube-system
# Monitor update progress
kubectl rollout status daemonset/cilium -n kube-system --timeout=600s
Performance Benchmarks and Selection Guide
Measured Benchmark Results (2025 baseline)
Here's a summary of comparison test results from recent large-scale enterprise environments.
| Metric | Network Policy Only | Istio Ambient | Cilium Service Mesh |
|---|---|---|---|
| P99 Latency (ms) | 1.2 | 3.8 | 2.1 |
| QPS (req/s) | 45,000 | 38,000 | 42,000 |
| QPS per Core | - | 2,178 | 1,815 |
| CPU Overhead | Baseline | +15% | +8% |
| Memory Overhead | Baseline | +120MB/node | +80MB/node |
| Low-connection Perf | - | Excellent | Moderate |
| High-connection Perf | - | Moderate | Excellent |
Note: Istio's higher QPS per Core includes L7 processing capability, and Cilium's CPU measurements exclude in-kernel WireGuard encryption costs.
Selection Guide Flowchart
-
Only L3/L4 network isolation needed?
- Yes: Kubernetes Network Policy + Calico or Cilium CNI is sufficient
- No: Go to 2
-
L7 traffic management (canary, retry, circuit breaker) needed?
- Yes: Istio Ambient Mode or Cilium + Envoy
- No: Go to 3
-
mTLS-based zero trust required?
- Yes: Istio Ambient Mode (SPIFFE-based workload ID)
- No: Cilium WireGuard encryption for inter-node encryption
-
High performance + kernel-level observability a priority?
- Yes: Cilium Service Mesh + Hubble
- No: Istio (richer L7 features)
-
Mixed Windows nodes or hybrid environment?
- Yes: Calico Enterprise
- No: Istio or Cilium
Recommendations by Operational Scale
- Small clusters (10 nodes or fewer): Cilium CNI + basic Network Policy. Service Mesh adoption has limited benefit relative to overhead.
- Medium clusters (10-100 nodes): Cilium Service Mesh or Istio Ambient. Choose based on L7 requirements.
- Large clusters (100+ nodes): Istio Ambient Mode. Mature multi-cluster support, rich ecosystem, stability.
- Hybrid/Multi-cloud: Calico Enterprise or Cilium Cluster Mesh.
Conclusion
Kubernetes network security goes beyond simply applying Network Policy; it requires a comprehensive strategy tailored to your application characteristics and security requirements.
Key takeaways:
- Network Policy is the absolute baseline: Start with Default Deny and apply a whitelist approach that allows only necessary communication. Don't forget the DNS allow policy.
- Introduce Service Mesh when needed: Adopt it when mTLS, L7 policies, and advanced traffic management are actually required. Unnecessary complexity only increases operational burden.
- Istio vs Cilium is a trade-off: Istio has rich L7 features and ecosystem, while Cilium excels at kernel-level performance and observability. Choose based on your requirements.
- Gradual adoption is key: The safest approach is to start with Default Deny policies, thoroughly validate Network Policies, and then add Service Mesh as needed.
- Automation and testing: Policy changes must always be validated in staging first through CI/CD pipelines, and always have a rollback plan ready.
Network security is not a one-time setup. As services evolve, policies must be continuously reviewed and updated. Quarterly policy audits are recommended, and use observability tools like Hubble or Kiali to optimize policies based on actual traffic patterns.
References
- Kubernetes Network Policies Official Docs
- Istio Official Docs - Ambient Mesh
- Cilium Official Docs - Service Mesh
- Calico Official Docs - Network Policy
- Istio Ambient vs Cilium Performance Comparison
- CNCF - Unlocking Cloud Native Security with Cilium and eBPF
- Tigera - Sidecarless mTLS in Kubernetes with Istio Ambient Mesh