Istio 서비스 메시 · 확장 지점의 값과 대가 · 실습
확장 지점을 열었더니 판올림이 무서워졌다 — EnvoyFilter 와 WasmPlugin
목표
EnvoyFilter 의 네 자리(applyTo·match.context·patch.operation·priority)를 API 서버가 어떻게 강제하는지 직접 확인하고, 같은 요구를 WasmPlugin 으로 적으면 무엇이 달라지는지 비교한다. 마지막에는 클러스터의 모든 EnvoyFilter 를 훑어 판올림 위험을 코드로 찍어 주는 점검 스크립트를 만든다.
왜 중요한가
메시를 오래 쓰면 표준 API 로 표현되지 않는 요구가 반드시 온다. 그때 EnvoyFilter 를 쓰게 되는데, 이 API 는 Istio 의 추상이 아니라 Envoy 의 내부 설정 구조를 직접 건드린다. 그래서 Istio 를 판올림하면 프록시 안의 필터 이름이나 구조가 바뀌어 패치가 조용히 적용되지 않을 수 있다 — 오류도 나지 않고, 알림도 울리지 않는다. 그렇다고 쓰지 말라는 말은 현실적이지 않다. 대신 세 가지를 습관으로 만든다. 범위를 최대한 좁히고(네임스페이스와 workloadSelector), 상대 위치 패치에는 우선순위를 적고, 어디에 무엇을 끼웠는지 기계가 읽을 수 있는 점검표로 남긴다. 그래야 판올림 전에 무엇을 다시 확인해야 하는지 사람이 기억하지 않아도 된다.
단계
1. /root/ist-envoyfilter 와 네임스페이스 ext-lab 를 만드세요. 그리고 클러스터에 등록된 확장 API 두 가지를 /root/ist-envoyfilter/ext-apis.tsv 에 <복수형 이름>\t<API 그룹>\t<kind> 로 두 줄 적으세요 — EnvoyFilter 와 WasmPlugin 입니다. 이름 오름차순으로 정렬합니다.
2. /root/ist-envoyfilter/ef-broken.yaml 에 ext-lab 네임스페이스의 EnvoyFilter inbound-lua 를 쓰되 세 곳을 일부러 틀리세요 — applyTo 는 HTTP_FILTERS, match.context 는 SIDECAR_IN, patch.operation 은 INSERT_BEFORE_ALL 입니다. workloadSelector 는 app: checkout 으로 둡니다. 이 파일을 적용하지 말고 서버 쪽 시험 적용만 해서 거절 문장을 /root/ist-envoyfilter/ef-reject.txt 에 저장하세요.
3. /root/ist-envoyfilter/ef-inbound.yaml 에 고친 EnvoyFilter inbound-lua 를 쓰고 ext-lab 에 실제로 적용하세요 — applyTo 는 HTTP_FILTER, match.context 는 SIDECAR_INBOUND, patch.operation 은 INSERT_BEFORE 이고, match.listener.filterChain.filter.name 은 envoy.filters.network.http_connection_manager 입니다. patch.value 에는 name: envoy.filters.http.lua 만 적고 priority 는 아직 넣지 마세요.
4. 네임스페이스 istio-system 을 만들고 그 안에 EnvoyFilter mesh-access-log 를 적용하세요 — workloadSelector 는 두지 않고, applyTo 는 NETWORK_FILTER, match.context 는 ANY, patch.operation 은 MERGE 로 액세스 로그를 /dev/stdout 에 붙이는 typed_config 를 씁니다. 매니페스트는 /root/ist-envoyfilter/ef-mesh.yaml 에 두세요. 그리고 지금 클러스터의 EnvoyFilter 마다 <네임스페이스>/<이름>\t<selector 있음 yes|no> 를 /root/ist-envoyfilter/ef-scope.tsv 에 정렬해 적으세요.
5. istioctl analyze -n ext-lab -o json 의 출력을 /root/ist-envoyfilter/analyze-before.json 에 저장하세요 — 3단계에서 올린 inbound-lua 에 IST0151 경고가 붙어 있어야 합니다. 그다음 /root/ist-envoyfilter/ef-inbound-priority.yaml 에 spec.priority 를 10 으로 더한 판을 써서 다시 적용하고, 같은 명령의 출력을 /root/ist-envoyfilter/analyze-after.json 에 저장하세요. 뒤쪽에는 IST0151 이 없어야 합니다.
6. /root/ist-envoyfilter/wasm.yaml 에 ext-lab 의 WasmPlugin header-check 를 쓰고 적용하세요 — selector.matchLabels 는 app: checkout, url 은 oci://registry.lab.internal/plugins/header-check:1.0, phase 는 AUTHZ, priority 는 20, pluginConfig.header 는 x-lab-tier 입니다. 그리고 /root/ist-envoyfilter/wasm-bad.yaml 에 header-check-bad 를 phase: PRE_AUTHZ 로 써서 서버 시험 적용에 거절당하게 하고 그 문장을 /root/ist-envoyfilter/wasm-reject.txt 에 저장하세요.
7. istioctl analyze -n ext-lab -o json 을 다시 돌려 /root/ist-envoyfilter/findings.tsv 에 <코드>\t<대상> 을 한 줄씩 정렬해 적으세요. 대상은 분석 결과의 origin 값을 그대로 씁니다. 그리고 /root/ist-envoyfilter/ef-inbound.yaml(3단계 파일)을 istioctl validate 로 검사한 출력을 /root/ist-envoyfilter/validate.txt 에 저장하세요 — 분석기가 잡는 것과 검증기가 잡는 것이 같지 않다는 것을 눈으로 확인합니다.
8. 네임스페이스 legacy-lab 를 만들고 EnvoyFilter legacy-ratelimit 을 적용하세요 — workloadSelector 없음, applyTo 는 HTTP_FILTER, match.context 는 SIDECAR_INBOUND, patch.operation 은 INSERT_AFTER, patch.value 는 name: envoy.filters.http.ratelimit 만 적습니다(매니페스트는 /root/ist-envoyfilter/ef-legacy.yaml). 그다음 /root/ist-envoyfilter/ef-audit.sh 를 만들어 클러스터의 모든 EnvoyFilter 를 <네임스페이스>/<이름>\t<위험코드들> 로 정렬해 표준출력에만 찍게 하세요. 위험코드는 no-selector(workloadSelector 없음)·no-priority(상대 위치 연산인데 priority 없음)·name-only(typed_config 없이 이름만) 세 가지를 쉼표로 이어 사전순으로 쓰고, 하나도 없으면 - 를 씁니다. 출력을 /root/ist-envoyfilter/audit-result.txt 에 저장하세요.
참고
- applyTo·context·operation·phase 는 모두 열거형이라 API 서버가 허용 값 목록을 돌려줍니다.
kubectl apply --dry-run=server는 만들지 않고 서버에게 물어만 봅니다.- IST0151 은 우선순위 없는 상대 위치 패치를 가리킵니다.
istioctl analyze -o json으로 코드만 뽑을 수 있습니다. - 흔한 실수: jq 에서
.spec.priority // "없음"처럼 쓰면 0 도 없는 것이 됩니다.== null로 비교하세요. - 흔한 실수: 루트 네임스페이스에 둔 EnvoyFilter 를 네임스페이스용으로 착각합니다. 거긴 메시 전체입니다.
- 참고: https://istio.io/v1.24/docs/reference/config/networking/envoy-filter/
- 참고: https://istio.io/v1.24/docs/reference/config/proxy_extensions/wasm-plugin/
- 참고: https://istio.io/v1.24/docs/reference/config/analysis/
단계 8개
- 확장 API 두 가지가 어디에 등록돼 있는지 확인한다
- 열거형 세 개를 한꺼번에 틀려 본다
- 세 곳을 고쳐 실제로 올린다
- 메시 전체에 걸리는 자리와 워크로드 하나에 걸리는 자리
- 상대 위치 패치에 우선순위가 없으면 분석기가 경고한다
- 같은 일을 표준 확장 API 로 적으면 무엇이 달라지나
- 분석기가 이 네임스페이스에서 무엇을 잡는지 표로 굳힌다
- 판올림 전에 돌릴 점검표를 스크립트로 만든다