개요
Istio는 기본적으로 뛰어난 트래픽 제어 기능을 제공하지만, 현실 세계의 다양한 요구사항을 모두 충족하긴 어렵다. 예를 들어, 특정 조건에 따라 헤더를 동적으로 추가하거나, 외부 서비스를 호출해 요청 정보를 추가해야 하는 경우도 있다. 이런 시나리오에서는 Istio 내부 API만으로는 한계가 존재한다.
이때 Istio의 내부 구성 요소인 Envoy 프록시의 필터 체인을 직접 확장하면 데이터 플레인의 동작을 더욱 유연하게 제어할 수 있다. 이를 위한 핵심 도구가 바로 EnvoyFilter 리소스다. 단, EnvoyFilter는 잘못 구성하면 서비스 메쉬 전체에 영향을 줄 수 있어 신중한 접근이 필요하다. 일부 전문가들은 운영 환경에서는 가급적 사용을 최소화할 것을 권장하기도 한다.
Envoy 필터 체인 확장 방식
Envoy는 HTTP 요청 처리 과정에서 다양한 필터 체인을 통해 트래픽을 세밀하게 제어할 수 있다. 일반적인 설정만으로는 충분하지 않은 경우, 사용자 고유의 로직을 요청 흐름에 삽입할 수 있는 여러 확장 방식을 제공한다.
• External Processing
: 외부 서비스와 통신해 요청을 실시간 보강하거나 검증
• Lua
: 내장된 Lua 엔진으로 경량 스크립트를 실행해 헤더 수정, 조건 분기 등 처리
• WebAssembly (WASM)
: 성능이 중요한 커스텀 로직을 다양한 언어로 작성하여 런타임에 삽입 가능
이러한 필터는 Envoy의 **HTTP Connection Manager(HCM)에 통합되며, 요청 흐름 중간에서 사용자 정의 처리를 가능하게 해 준다.
Istio에서 Envoy 필터 확장 적용하기
Istio는 EnvoyFilter라는 커스텀 리소스를 제공해 사용자가 직접 필터 구성을 조작할 수 있도록 한다. 이를 통해 Istio의 데이터 플레인을 정밀하게 커스터마이징 할 수 있으며, 주요 확장 방식은 다음과 같다.
- EnvoyFilter 리소스를 통한 필터 삽입 및 설정 변경
- 외부 속도 제한 서버(RateLimitServer)와의 연동
- Lua 스크립트를 활용한 동적 요청 가공
- WebAssembly 모듈을 통한 고급 커스텀 처리
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-protocol
namespace: istio-config # as defined in meshConfig resource.
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_OUTBOUND # will match outbound listeners in all sidecars
listener:
portNumber: 9307
filterChain:
filter:
name: "envoy.filters.network.tcp_proxy"
patch:
operation: INSERT_BEFORE
value:
# This is the full filter config including the name and typed_config section.
name: "envoy.extensions.filters.network.mongo_proxy"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.mongo_proxy.v3.MongoProxy"
...
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
# context omitted so that this applies to both sidecars and gateways
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
name: "envoy.filters.network.http_connection_manager"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
common_http_protocol_options:
idle_timeout: 30s
실습 환경 구성
Envoy 필터 실습을 위한 테스트 환경은 kind 기반 쿠버네티스 클러스터 위에 Istio 1.17.8을 설치하고, 외부 노출을 위한 MetalLB를 구성하는 방식으로 진행한다.
k8s(1.23.17) 배포
kind create cluster --name myk8s --image kindest/node:v1.23.17 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000 # Sample Application (istio-ingrssgateway) HTTP
hostPort: 30000
- containerPort: 30001 # Prometheus
hostPort: 30001
- containerPort: 30002 # Grafana
hostPort: 30002
- containerPort: 30003 # Kiali
hostPort: 30003
- containerPort: 30004 # Tracing
hostPort: 30004
- containerPort: 30005 # Sample Application (istio-ingrssgateway) HTTPS
hostPort: 30005
- containerPort: 30006 # TCP Route
hostPort: 30006
- containerPort: 30007 # kube-ops-view
hostPort: 30007
extraMounts: # 해당 부분 생략 가능
- hostPath: /Users/spjang/Desktop/1.Projects/istio/istio-in-action/book-source-code-master # 각자 자신의 pwd 경로로 설정
containerPath: /istiobook
networking:
podSubnet: 10.10.0.0/16
serviceSubnet: 10.200.0.0/22
EOF
# 노드에 기본 툴 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'
kind docker network에 테스트용 PC(실제로는 컨테이너) 배포
# kind 설치 시 kind 이름의 도커 브리지가 생성됨: 192.168.107/24 자신의 PC IP 대역
docker network ls
docker inspect kind
# mypc 컨테이너 기동 : kind 도커 브리지를 사용
docker run -d --rm --name mypc --network kind nicolaka/netshoot sleep infinity
docker ps
# kind network 중 컨테이너(노드) IP(대역) 확인
docker ps -q | xargs docker inspect --format '{{.Name}} {{.NetworkSettings.Networks.kind.IPAddress}}'
/mypc 192.168.107.3
/myk8s-control-plane 192.168.107.2
# 동일한 docker network(kind) 내부에서 컨테이너 이름 기반 도메인 통신 가능 확인!
docker exec -it mypc ping -c 1 192.168.107.2
docker exec -it mypc ping -c 1 myk8s-control-plane
docker exec -it myk8s-control-plane ping -c 1 mypc
MetalLB 배포(편리성 설정)
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
# 확인
kubectl get crd
kubectl get pod -n metallb-system
# IPAddressPool, L2Advertisement 설정 : MetalLB 파드(speaker) 배포 정상 완료 후 아래 설정 실행
cat << EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 192.168.107.101-192.168.107.120 # 자신의 kind 도커 network 대역
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
EOF
istio 1.17.8 설치
# myk8s-control-plane 진입 후 설치 진행
docker exec -it myk8s-control-plane bash
-----------------------------------
# (옵션) 코드 파일들 마운트 확인
tree /istiobook/ -L 1
혹은
git clone ... /istiobook
# istioctl 설치
export ISTIOV=1.17.8
echo 'export ISTIOV=1.17.8' >> /root/.bashrc
curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
# demo 프로파일 컨트롤 플레인 배포
istioctl install --set profile=demo --set values.global.proxy.privileged=true -y
# 보조 도구 설치
kubectl apply -f istio-$ISTIOV/samples/addons
# 빠져나오기
exit
네임스페이스 및 서비스 노출 설정
# 실습을 위한 네임스페이스 설정
kubectl create ns istioinaction
kubectl label namespace istioinaction istio-injection=enabled
kubectl get ns --show-labels
# istio-ingressgateway 서비스 : nodeport 지정 변경 , externalTrafficPolicy 설정 (ClientIP 수집)
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "LoadBalancer", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "LoadBalancer", "ports": [{"port": 443, "targetPort": 8443, "nodePort": 30005}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
kubectl describe svc -n istio-system istio-ingressgateway
# NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), tracing(30004)
kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'
Istio에서 필터를 확장하는 세 가지 방법
1. 외부 호출 기반 속도 제한 구성
Istio의 기본 기능만으로는 요청 수를 세밀하게 제어하기 어렵다. 특히 서비스 전체에 일관된 속도 제한을 적용하려면 외부 의존성이 필요하다. 이를 위해 Envoy의 rate_limit 필터와 외부 Rate Limit Server(RLS)를 연동하는 아키텍처를 사용한다.
왜 외부 속도 제한 서버가 필요한가?
속도 제한은 단일 Pod 또는 인스턴스 기준이 아닌, 서비스 전반에 걸친 제어가 핵심이다. 다수의 복제본이 있을 경우, 요청 카운트를 공유해야 하는데 이를 위해 Redis 등의 스토리지를 가진 RLS 아키텍처가 요구된다.
구성 요소 및 흐름
- Envoy 필터 설정: 요청의 특정 속성(예: x-loyalty 헤더)을 기반으로 디스크립터를 구성
- RLS 서버: 디스크립터별 요청 횟수를 Redis에 저장하고 제한 판단
- EnvoyFilter 리소스: 디스크립터 전달을 위한 rate_limits.actions 명시
예를 들어, x-loyalty 헤더 값에 따라 분당 요청 횟수를 제한할 수 있다:
# 예시 디스크립터 구성 (config.yaml)
descriptors:
- key: header_match
value: no_loyalty
rate_limit:
unit: MINUTE
requests_per_unit: 1
- key: header_match
value: gold_request
rate_limit:
unit: MINUTE
requests_per_unit: 10
- key: header_match
value: silver_request
rate_limit:
unit: MINUTE
requests_per_unit: 5
- key: header_match
value: bronze_request
rate_limit:
unit: MINUTE
requests_per_unit: 3
EnvoyFilter로 요청 속성 전달 설정
도 제한 서버가 제한 결정을 내리려면, Envoy에서 요청의 특정 속성(예: 헤더 값)을 전달하도록 설정해야 한다. 이를 위해 EnvoyFilter를 이용해 rate_limit action을 명시한다.
# EnvoyFilter 액션 설정 예시
rate_limits:
- actions:
- header_value_match:
descriptor_value: gold_request
headers:
- name: "x-loyalty"
exact_match: gold
이러한 액션은 EnvoyFilter 리소스를 통해 catalog 서비스에 적용할 수 있다.
실습 절차
Step 1: 기본 서비스 배포
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction
kubectl apply -f services/webapp/istio/webapp-catalog-gw-vs.yaml -n istioinaction
kubectl apply -f ch9/sleep.yaml -n istioinaction
Step 2: RLS 및 Redis 구성
kubectl apply -f rlsconfig.yaml -n istioinaction
kubectl apply -f rls.yaml -n istioinaction
Step 3: EnvoyFilter 구성
kubectl apply -f catalog-ratelimit.yaml -n istioinaction
kubectl apply -f catalog-ratelimit-actions.yaml -n istioinaction
# EnovyFiliter 주요 설정
# cat ch14/rate-limit/catalog-ratelimit-actions.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: catalog-ratelimit-actions
namespace: istioinaction
...
patch:
operation: MERGE
# Applies the rate limit rules.
value:
rate_limits: # 속도 제한 조치
- actions:
- header_value_match:
descriptor_value: no_loyalty
expect_match: false
headers:
- name: "x-loyalty"
- actions:
- header_value_match:
descriptor_value: bronze_request
headers:
- name: "x-loyalty"
exact_match: bronze
- actions:
- header_value_match:
descriptor_value: silver_request
headers:
- name: "x-loyalty"
exact_match: silver
- actions:
- header_value_match:
descriptor_value: gold_request
headers:
- name: "x-loyalty"
exact_match: gold
# 배포 확인
kubectl get envoyfilter -A
kubectl get pod -n istioinaction
Step 4: 속도 제한 테스트
테스트용 sleep 앱을 사용해 catalog 서비스를 호출해 보자. loyalty 헤더를 생략하면 1분 1회, silver면 5회, gold면 10회로 제한된다.
# sleep 앱에서 catalog 서비스를 호출 시도 : 대략 1분에 한 번 정도 호출 성공! >> x-loyalty 헤더가 없을 때 속도 제한 값!
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://catalog/items -v
...
< HTTP/1.1 429 Too Many Requests
< x-envoy-ratelimited: true
...
# silver 헤더: 6번째 값부터 429 에러 발생
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v # 429에러
설정 및 확인
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'inbound|3000||' -o json
...
"rateLimits": [
{
"actions": [
{
"headerValueMatch": {
"descriptorValue": "no_loyalty",
"expectMatch": false,
"headers": [
{
"name": "x-loyalty"
}
]
}
}
]
},
{
"actions": [
{
"headerValueMatch": {
"descriptorValue": "bronze_request",
"headers": [
{
"name": "x-loyalty",
"exactMatch": "bronze"
...
마무리 및 리소스 정리
테스트가 끝나면 리소스를 삭제하자
kubectl delete envoyfilter -n istioinaction --all
kubectl delete -f rlsconfig.yaml -n istioinaction
kubectl delete -f rls.yaml -n istioinaction
외부 호출 기반 속도 제한 구성은 Istio의 데이터 플레인을 실질적으로 확장한 대표적인 예시다. 이 구조는 네트워크 정책이나 인증과 같이 복잡한 판단이 필요한 기능에도 활용될 수 있다
2. Lua 스크립트 기반 커스텀 로직 삽입
Lua는 Envoy에 내장된 스크립팅 언어로, 요청과 응답을 빠르게 가공하는 데 적합하다. 헤더 조작, 요청 바디 분석, 외부 서비스 호출, 간단한 분기 로직 등에 유용하게 쓰인다.
Istio에서는 EnvoyFilter 리소스를 통해 Lua 필터를 삽입할 수 있으며, 이를 통해 트래픽 흐름에 동적으로 커스텀 로직을 삽입할 수 있다
.
Lua가 적합한 이유
Envoy의 트래픽 제어는 주로 VirtualService, DestinationRule, AuthorizationPolicy 등으로 구성되지만, 이들만으로는 조건 분기, 외부 연동 등이 어렵다. Lua는 다음과 같은 상황에 적합하다.
- 요청/응답 헤더 수정
- 요청 바디 검사 및 조건 분기
- 외부 서비스 호출 (예: A/B 테스트)
- 간단한 정책 분기
Lua 필터 구조
EnvoyFilter 리소스 내부에 envoy.filters.http.lua 필터를 추가하고, Lua 코드를 inlineCode로 직접 정의한다. 주요 구조는 다음과 같다:
function envoy_on_request(request_handle)
-- 외부 서비스 호출 및 헤더 삽입
end
function envoy_on_response(response_handle)
-- 응답 헤더 조작
end
외부 서비스 호출은 httpCall() 함수를 사용하며, 이때 연결을 위한 cluster 리소스도 함께 등록해야 한다.
실습 예시: A/B 테스트 그룹 지정
외부 서비스 bucket-tester에서 A/B 테스트 그룹을 받아와, 요청 헤더 x-test-cohort로 추가하는 로직을 구현해 보자.
Step 1: 버킷 테스트용 서비스 배포
kubectl apply -f ch14/httpbin.yaml -n istioinaction
kubectl apply -f ch14/bucket-tester-service.yaml -n istioinaction
- httpbin은 받은 요청의 헤더를 응답으로 반환
- bucket-tester는 A/B 테스트 그룹을 판단해 문자열을 응답
Step 2: Lua 필터 삽입
# cat ch14/lua-filter.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: httpbin-lua-extension
namespace: istioinaction
...
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_request(request_handle) # 아래 줄에 코드 입력
local headers, test_bucket = request_handle:httpCall(
"bucket_tester",
{
[":method"] = "GET",
[":path"] = "/",
[":scheme"] = "http",
[":authority"] = "bucket-tester.istioinaction.svc.cluster.local",
["accept"] = "*/*"
}, "", 5000)
request_handle:headers():add("x-test-cohort", test_bucket)
end
function envoy_on_response(response_handle) # 아래 줄에 코드 입력
response_handle:headers():add("istioinaction", "it works!")
end
...
Lua 필터가 적용된 EnvoyFilter는 httpbin 워크로드에 삽입되며, 해당 요청마다 bucket-tester에 HTTP 요청을 보내고 결과를 헤더로 붙인다.
Step 3: 결과확인
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://httpbin.istioinaction:8000/headers
# httpbin 서비스 호출 확인!
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://httpbin.istioinaction:8000/ -v
...
< HTTP/1.1 503 Service Unavailable
< content-length: 39
< content-type: text/plain
< istioinaction: it works!
< date: Sun, 18 May 2025 07:59:34 GMT
< server: envoy
< x-envoy-upstream-service-time: 51
...
invalid header value for: x-test-cohort
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://httpbin.istioinaction:8000/headers
...
invalid header value for: x-test-cohort
# 정상 실습 시..
{
"headers": {
"Accept": "*/*",
"Content-Length": "0",
"Host": "httpbin.istioinaction:8000",
"User-Agent": "curl/7.69.1",
"X-B3-Sampled": "1",
"X-B3-Spanid": "1d066f4b17ee147b",
"X-B3-Traceid": "1ec27110e4141e131d066f4b17ee147b",
"X-Test-Cohort": "dark-launch-7" # A/B 테스트 서비스를 호출할 때 덧붙이는 새 헤더 x-test-cohort 가 보임
}
}
정상적으로 작동할 경우 응답에 X-Test-Cohort: dark-launch-7 헤더가 포함된다. 그러나 실습 환경에 따라 오류로 인해, invalid header value for: x-test-cohort 헤더가 보인다. 하지만 응답을 확인해 보면 istioinaction: it works!
이 보이는 것으로 보아, EnovyFiliter가 잘 작동함을 확인할 수 있다.
(주의: 요청 바디를 다루면 Envoy가 바디 전체를 메모리에 적재할 수 있어 성능 저하 가능성이 있다. Envoy Lua 필터 공식 문서 참고.)
3. WebAssembly(Wasm)를 활용한 고급 확장
WebAssembly(Wasm)는 다양한 언어로 작성된 코드를 바이너리 포맷으로 컴파일해, 가상머신에서 안전하고 이식성 있게 실행할 수 있도록 설계된 기술이다. Istio에서는 Wasm을 활용해 Envoy 프록시에 새로운 HTTP 필터를 작성하고 동적으로 로드할 수 있으며, 기존 Envoy 바이너리를 수정하지 않고도 데이터 플레인을 유연하게 확장할 수 있다
Wasm이 적합한 이유
기존에는 Envoy 필터를 작성하려면 C++로 구현해 정적으로 빌드해야 했고, 이로 인해 유지보수 및 배포가 매우 부담스러웠다. 반면 Wasm 기반 확장은 다음과 같은 장점이 있다.
- 다양한 언어 지원: Rust, AssemblyScript, TinyGo 등
- 런타임 동적 로딩 가능: Envoy 재빌드 없이 필터 교체
- 보안성: 메모리 안전(Safe), 샌드박스 기반 실행 환경
Istio의 Wasm 모듈 배포 방식
Istio는 Wasm 모듈을 동적으로 배포하고 관리할 수 있는 메커니즘을 갖추고 있다.
- Istio 1.9부터 istio-agent가 원격 HTTP 소스로부터 Wasm 모듈을 가져와 로컬에 캐시
- EnvoyFilter 또는 WasmPlugin 리소스를 통해 모듈을 Envoy에 삽입
- Istio 1.12부터는 OCI 이미지 기반 모듈 배포 지원 (Docker Hub, GCR 등에서 이미지 형태로 가져오기 가능)
실습: HTTP 기본 인증 필터 적용
구성 개요
- 기본 인증을 적용하는 Wasm 필터를 Istio Ingress Gateway에 적용
- 원격 OCI 이미지 레지스트리에서 basic_auth 필터를 가져옴
- /api 경로에 대해 GET/POST 요청 시 인증 필요하도록 설정
WasmPlugin 리소스 적용
kubectl apply -f - <<EOF
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: basic-auth
namespace: istio-system # 모든 네임스페이스에 영향
spec:
selector:
matchLabels:
istio: ingressgateway
url: oci://ghcr.io/istio-ecosystem/wasm-extensions/basic_auth:1.12.0
phase: AUTHN
pluginConfig:
basic_auth_rules:
- prefix: "/api"
request_methods:
- "GET"
- "POST"
credentials:
- "ok:test"
- "YWRtaW4zOmFkbWluMw=="
EOF
# 적용 확인
kubectl get WasmPlugin -A
NAMESPACE NAME AGE
istio-system basic-auth 5s
동작 테스트
자격 증명 없이 요청
EXT_IP=$(kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog -v
...
< HTTP/1.1 401 Unauthorized
< www-authenticate: Basic realm=istio
자격 증명 포함 요청
docker exec -it mypc curl -s -H "Authorization: Basic YWRtaW4zOmFkbWluMw==" -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog -v
...
> Authorization: Basic YWRtaW4zOmFkbWluMw==
* Request completely sent off
< HTTP/1.1 200 OK
이처럼 Istio에 WebAssembly를 활용하면 Envoy 필터를 정적 빌드 없이도 동적으로 확장할 수 있으며, 보안 필터 같은 기능을 별도 언어로 작성하여 안전하게 배포할 수 있다.
고급 보안 필터 적용: Coraza WAF 연동
Coraza는 Go 언어로 개발된 고성능 Web Application Firewall(WAF)로, OWASP의 ModSecurity SecLang 규칙과 100% 호환되는 OWASP CRS(Core Rule Set)를 지원한다. proxy-wasm 기반으로 Envoy에 직접 삽입할 수 있으며, Istio에서는 WasmPlugin 리소스를 통해 손쉽게 배포할 수 있다.
Coraza WAF의 특징
- 보안성: SQL Injection, XSS, Shellshock, 코드 인젝션 등 다양한 공격을 탐지 및 차단
- 확장성: 감사 로그, 액션, 연산자 등을 자유롭게 구성 가능
- 성능: 대규모 트래픽도 처리 가능한 경량 아키텍처
- 호환성: 기존 ModSecurity 규칙과 drop-in 방식으로 연동 가능
- 운영 유연성: CRS 설정 파일 튜닝 및 rule 기반 정책 제어 가능
Istio에 Coraza (코라자) WAF 적용
Istio에서 Coraza 적용
다음과 같은 방식으로 WasmPlugin 리소스를 생성해 필터를 적용할 수 있다:
# Istio WasmPlugin 설정
kubectl apply -f - <<EOF
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: coraza-ingressgateway
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
url: oci://ghcr.io/corazawaf/coraza-proxy-wasm
phase: AUTHN
pluginConfig:
default_directives: default
directives_map:
default:
- Include @demo-conf
- SecDebugLogLevel 9
- SecRuleEngine On
- Include @crs-setup-conf
- Include @owasp_crs/*.conf
EOF
적용 후 로그 확인:
#
kubectl logs -n istio-system -l app=istio-ingressgateway | grep -i wasm
2025-05-24T22:44:56.625218Z info wasm fetching image corazawaf/coraza-proxy-wasm from registry ghcr.io with tag latest
#
kubectl get WasmPlugin -A
NAMESPACE NAME AGE
istio-system coraza-ingressgateway 9s
동작 확인
# 정상 호출
curl -s http://webapp.istioinaction.io:30000/api/catalog
# XSS 공격 시도
curl -s 'http://webapp.istioinaction.io:30000/api/catalog?arg=<script>alert(0)</script>' -IL
# 결과: HTTP/1.1 403 Forbidden
# SQL Injection 시도
curl -i -X POST 'http://webapp.istioinaction.io:30000/api/catalog' --data "1%27%20ORDER%20BY%203--%2B"
# 결과: HTTP/1.1 403 Forbidden
...
WAF가 요청을 차단한 경우, Envoy 로그에는 Coraza의 탐지 및 차단 로그가 출력된다.
Prometheus 메트릭도 waf_filter로 노출되므로 관측이 가능하다.
'Kubernetes > Istio' 카테고리의 다른 글
Istio 시리즈 # 13 - Istio Ambient Mode 살펴보기 (4) | 2025.06.09 |
---|---|
Istio 시리즈 # 12 - Istio와 가상머신 통합하기(VM Support) (2) | 2025.06.01 |
Istio 시리즈 # 10 - Istio로 구현하는 다중 클러스터 서비스 메시 (Multi-Cluster) (0) | 2025.05.25 |
Istio 시리즈 # 9 – Istio 성능 튜닝 가이드(Istio Tuning) (0) | 2025.05.18 |
Istio 시리즈 # 8 - Istio 트러블 슈팅 가이드(Istio Troubleshooting) (1) | 2025.05.17 |