Istio와 K8s NetworkPolicy, 충돌 없이 안전하게 사용하는 정책 우선순위 가이드
Kubernetes 환경에서 서비스 메시(Service Mesh)를 도입하는 것은 애플리케이션의 안정성과 가시성을 극대화하는 혁신적인 과정입니다. 하지만 이 강력한 도구들은 그만큼 복잡한 네트워킹 정책을 수반합니다. 특히, 네이티브 Kubernetes의 NetworkPolicy와 Istio가 제공하는 세밀한 제어 기능(AuthorizationPolicy, VirtualService)을 함께 사용하다 보면, "도대체 어느 규칙이 최종적으로 적용되는 걸까?"라는 근본적인 질문에 부딪히기 쉽습니다.
이 글은 시니어 DevOps 엔지니어와 SRE 분들이 가장 궁금해하는 지점, 즉 두 가지 강력한 네트워킹 정책이 충돌했을 때의 **정책 우선순위(Precedence)**를 명확하게 정리하고, 충돌을 원천적으로 방지하는 실질적인 아키텍처 설계 가이드라인을 제공합니다.
네트워킹 정책의 계층적 이해: L3/L4 vs. L7
정책 충돌을 이해하려면, 먼저 두 정책이 작동하는 '레이어'가 근본적으로 다름을 인지해야 합니다.
🌐 NetworkPolicy: 인프라 방화벽 (L3/L4 레벨)
NetworkPolicy는 Kubernetes의 CNI(Container Network Interface) 레벨에서 작동하는, 가장 낮은 단계의 방화벽 역할을 합니다. 이는 마치 데이터센터의 물리적인 출입문과 같습니다.
- 제어 범위: IP 주소(L3)와 포트 번호(L4)를 기반으로 트래픽의 **도달 가능성(Reachability)**을 통제합니다.
- 작동 방식: 특정 네임스페이스나 파드 그룹이 특정 포트로 통신할 수 있는지 여부를 결정합니다.
- 핵심 원칙: 기본적으로 모든 트래픽을 차단하는 "Deny by Default" 원칙을 따릅니다.
🛡️ Istio Policy: 애플리케이션 게이트웨이 (L7 레벨)
Istio는 사이드카 프록시(Envoy)를 통해 트래픽을 가로채서 검사합니다. 이는 데이터센터 내부의 보안 검문소와 같습니다.
- 제어 범위: HTTP 메서드(GET, POST), 헤더 값, 사용자 인증(JWT 등)과 같은 애플리케이션 계층의 세부 정보를 검사합니다.
- 작동 방식: 트래픽이 이미 목적지에 도달했다는 전제 하에, '누가(Identity)' '어떤 방식으로(Method)' 접근했는지를 검증합니다.
- 핵심 원칙: 역시 기본적으로 접근을 거부하는 **"Deny by Default"**를 따릅니다.
🚨 핵심 비교: 정책 우선순위(Precedence) 매트릭스 분석
가장 중요한 질문입니다. 트래픽이 발생했을 때, 이 두 정책 중 어느 것이 먼저 작동하며, 어느 것이 최종 승자인가요?
🚀 트래픽 흐름의 순서: CNI $\rightarrow$ Sidecar $\rightarrow$ Application
트래픽은 반드시 계층적으로 흐릅니다. 이 순서를 이해하는 것이 모든 문제 해결의 열쇠입니다.
- CNI/NetworkPolicy 검사 (L3/L4): 패킷이 클러스터 네트워크에 진입하는 순간, CNI 플러그인이 먼저 포트와 IP를 확인합니다. 여기서 차단되면, 그 이후의 과정은 없습니다.
- Sidecar/Istio 검사 (L7): 패킷이 파드에 도달하여 사이드카 프록시를 통과할 때, Istio가 L7 규칙(인증, 라우팅)을 검사합니다.
- Application 검사: 모든 검증을 통과한 트래픽만이 최종 애플리케이션 포트로 전달됩니다.
💡 실무 관점의 경험 공유: 제가 가장 많이 본 실수는, 개발팀이 "Istio에서 인증을 안 해주면 안 돼요"라며 L7 정책만 강화하고, 인프라팀이 L3/L4 정책을 너무 타이트하게 막아버린 경우입니다. 결과적으로 L3/L4에서 차단되어, Istio의 정교한 L7 인증 로직 자체가 실행될 기회조차 얻지 못하는 상황이 발생합니다.
📊 정책 적용 계층 및 제어 범위 비교표
| 정책 종류 | 제어 계층 | 주요 제어 요소 | 기본 동작 원칙 | 제어 대상 |
|---|---|---|---|---|
| NetworkPolicy | L3/L4 | IP, 포트 | Deny by Default | 네트워크 연결 자체 |
| Istio AuthorizationPolicy | L7 | HTTP Method, Header, Identity | Deny by Default | 접근 권한 (인가) |
| Istio VirtualService | L7 | Host, Path, Weight | 라우팅 규칙 | 트래픽 경로 및 분배 |
🛑 충돌 시나리오별 규칙 적용 원칙 (가장 중요)
규칙: 낮은 계층(L3/L4)에서 차단되면, 높은 계층(L7)의 규칙은 무시됩니다.
만약 NetworkPolicy가 특정 포트(예: 8080)로의 모든 인바운드 트래픽을 차단했다면, 아무리 AuthorizationPolicy에서 "이 사용자는 POST 요청을 허용해야 해"라고 설정했더라도, 패킷 자체가 사이드카 프록시까지 도달하지 못하므로 인증 과정은 시작조차 할 수 없습니다.
🛠️ 안전한 아키텍처 설계를 위한 모범 사례
정책 충돌을 막는 가장 확실한 방법은 역할 분리(Separation of Concerns) 원칙을 철저히 지키는 것입니다.
1. 역할 분리 원칙 적용하기
- NetworkPolicy (L3/L4): 오직 '통신이 가능한지(Can it reach?)' 여부만 담당합니다. (예: 서비스 A는 서비스 B의 8080 포트로만 접근 가능해야 한다.)
- Istio Policy (L7): 오직 '접근 권한이 있는지(Is it allowed?)' 여부만 담당합니다. (예: 서비스 B의 8080 포트에 접근은 가능하지만, 오직
GET메서드만 허용한다.)
2. 실전 예시: 포트 허용 + 인증 추가
다음 YAML 예시는 이 원칙을 완벽하게 구현한 예시입니다.
- NetworkPolicy (L3/L4): 서비스 A가 서비스 B의 8080 포트로 접근할 수 있도록 최소한의 통로를 열어줍니다.
- AuthorizationPolicy (L7): 통로를 통과한 트래픽에 대해, 'JWT 토큰을 가진 사용자만' 접근할 수 있도록 인증을 추가합니다.
# 1. NetworkPolicy: L3/L4 통로 확보 (최소한의 연결만 허용)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-service-b-port
namespace: default
spec:
podSelector:
matchLabels:
app: service-b
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: service-a
ports:
- port: 8080
protocol: TCP
---
# 2. AuthorizationPolicy: L7 인증 추가 (실질적인 접근 제어)
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt-auth
namespace: default
spec:
selector:
matchLabels:
app: service-b
action: ALLOW
rules:
- from:
- source:
namespaces: ["default"]
to:
- operation:
methods: ["GET"] # L7: GET 메서드만 허용
paths: ["/api/v1/data"]
requestPrincipals: ["cluster.local/ns/default/sa/service-a-sa"] # L7: 특정 서비스 계정만 허용위 예시에서, NetworkPolicy가 없으면 트래픽이 아예 도달하지 못하고, AuthorizationPolicy가 없으면 인증 없이 누구나 접근할 수 있게 됩니다. 둘 다 있어야 안전합니다.
🔍 디버깅 팁: 트래픽 흐름 추적하기
정책 충돌이 의심될 때, 다음 두 가지 도구를 순서대로 사용해 보세요.
kubectl get events: 네임스페이스 레벨에서 정책 위반이나 CNI 관련 오류 메시지가 있는지 확인합니다. (L3/L4 문제 감지)istioctl proxy-config logs <pod-name>: 사이드카 프록시의 로그를 확인하여, 트래픽이 어느 단계에서 거부되었는지(예: "Authentication failed", "No matching rule found") 구체적인 L7 에러 코드를 확인합니다.
참고: 공식 문서
이 글에서 다루는 동작·설정·에러의 1차 출처는 다음 공식 문서입니다. 버전별 옵션과 정확한 동작은 여기서 확인하세요.
자주 묻는 질문 (FAQ)
Q: NetworkPolicy를 적용하면 Istio의 모든 L7 기능이 비활성화되나요? A: 아닙니다. NetworkPolicy는 L3/L4 레벨에서 통로를 열어주는 역할만 합니다. 통로가 열린 후, 사이드카 프록시가 정상적으로 작동한다면 Istio의 L7 정책은 독립적으로 작동합니다. 단, L3/L4에서 차단되면 L7은 작동할 수 없습니다.
Q: AuthorizationPolicy만 설정하고 NetworkPolicy는 건드리지 않아도 되나요?
A: 권장되지 않습니다. 만약 클러스터의 기본 네트워크 정책이 매우 제한적이라면, Istio가 트래픽을 수신할 수 있는 최소한의 L3/L4 통로를 NetworkPolicy로 명시적으로 열어주는 것이 안정성을 높이는 가장 안전한 방법입니다.
Q: 두 정책을 모두 적용했을 때, 어떤 것이 더 우선순위가 높다고 확신할 수 있나요? A: 우선순위는 '계층적'입니다. 네트워크 스택(L3/L4)에서 막히는 것이 가장 높은 우선순위를 가지며, 이는 L7 정책보다 항상 먼저 검사됩니다.
마무리하며: 네트워킹 정책은 마치 건물을 짓는 과정과 같습니다. NetworkPolicy는 건물의 외벽과 기초 공사(구조적 안정성)를 담당하고, Istio는 내부의 보안 시스템과 출입 통제(기능적 안정성)를 담당합니다. 두 시스템의 역할을 명확히 이해하고, 각자의 영역을 침범하지 않도록 분리하는 것이 궁극의 안정성을 보장하는 핵심입니다.
이 글은 AI 에이전트가 자료 조사와 1차 초안 작성을 담당하고, 사람 편집자가 사실관계·출처·톤과 맥락을 검토한 뒤 발행했습니다. 환경(OS·버전)에 따라 결과가 다를 수 있으니 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
댓글
첫 번째 댓글을 남겨보세요.