Skip to content
Published on

Kubernetes Network Policy 실전 가이드: Calico·Cilium 기반 마이크로세그멘테이션과 Zero-Trust 네트워크 보안

Authors
  • Name
    Twitter
Kubernetes Network Policy

들어가며

Kubernetes 클러스터는 기본적으로 모든 Pod 간 통신이 허용되는 flat network로 동작한다. 이는 개발 편의성 측면에서는 장점이지만, 보안 관점에서는 치명적인 약점이다. 하나의 Pod가 침해되면 공격자는 별도의 방화벽 없이 클러스터 내 모든 서비스에 자유롭게 접근할 수 있다. 이를 lateral movement(횡적 이동) 공격이라 하며, 컨테이너 환경에서 가장 빈번하게 발생하는 보안 인시던트 유형 중 하나다.

Red Hat의 2024 State of Kubernetes Security 보고서에 따르면, 조사 대상 조직의 약 90%가 컨테이너 또는 Kubernetes 환경에서 보안 인시던트를 경험했다고 응답했다. 이 중 상당수는 네트워크 수준의 격리가 없었기 때문에 피해가 확산된 사례였다. 특히 마이크로서비스 아키텍처에서는 서비스 간 통신 경로가 폭발적으로 증가하므로, 전통적인 경계 기반 보안(perimeter security)만으로는 내부 위협을 차단할 수 없다.

**마이크로세그멘테이션(Microsegmentation)**은 이 문제에 대한 해답이다. 네트워크를 워크로드 단위로 세분화하여 각 서비스가 명시적으로 허용된 통신만 수행하도록 제한하는 전략이다. Kubernetes에서는 NetworkPolicy API와 Calico, Cilium 같은 CNI 플러그인을 통해 이를 구현한다. 이 글에서는 기본 NetworkPolicy 스펙부터 시작해 Calico의 GlobalNetworkPolicy, Cilium의 L7 정책과 eBPF 기반 enforcement까지, 프로덕션에서 Zero-Trust 네트워크를 구축하는 전체 과정을 다룬다.

Kubernetes NetworkPolicy 기본 구조

NetworkPolicy API v1 스펙 분석

Kubernetes NetworkPolicy는 networking.k8s.io/v1 API 그룹에 속하는 네임스페이스 스코프 리소스다. Pod에 대한 인바운드(Ingress)와 아웃바운드(Egress) 트래픽을 제어하며, 정책이 하나라도 적용된 Pod는 해당 정책에 명시된 트래픽만 허용되는 화이트리스트 방식으로 동작한다.

핵심 구성 요소는 다음과 같다.

  • podSelector: 정책이 적용될 대상 Pod를 label로 선택한다. 빈 셀렉터는 네임스페이스 내 모든 Pod를 의미한다.
  • policyTypes: Ingress, Egress, 또는 둘 다를 지정한다. 생략 시 Ingress만 적용되고, egress 규칙이 있으면 Egress도 자동 포함된다.
  • ingress/egress 규칙: 허용할 트래픽 소스 또는 목적지를 정의한다. 각 규칙은 from/to (피어 선택)와 ports (포트 선택)로 구성된다.
  • 피어 셀렉터: podSelector, namespaceSelector, ipBlock 세 가지 방식으로 트래픽의 상대방을 지정한다.

중요한 점은 NetworkPolicy는 **additive(누적식)**라는 것이다. 여러 정책이 같은 Pod에 적용되면, 각 정책에서 허용하는 트래픽의 합집합이 최종 허용 범위가 된다. 정책 간 충돌이나 우선순위 개념은 없다.

Default-Deny 정책으로 기본 보안 확보

Zero-Trust의 첫 번째 단계는 모든 트래픽을 기본 차단하는 것이다. 네임스페이스마다 default-deny 정책을 적용한 뒤, 필요한 통신만 명시적으로 허용하는 방식이다.

# default-deny-all.yaml
# 네임스페이스 내 모든 Ingress/Egress 트래픽을 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

이 정책을 적용하면 production 네임스페이스의 모든 Pod는 인바운드/아웃바운드 트래픽이 모두 차단된다. DNS 조회도 차단되므로 서비스 디스커버리가 작동하지 않는다. 따라서 DNS 트래픽을 허용하는 정책을 반드시 함께 적용해야 한다.

# allow-dns.yaml
# kube-system 네임스페이스의 DNS 서비스로의 egress 허용
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

네임스페이스 간 통신 허용 정책

마이크로서비스 환경에서는 서로 다른 네임스페이스의 서비스 간 통신이 필요하다. 예를 들어 frontend 네임스페이스의 웹 서버가 backend 네임스페이스의 API 서버에 접근해야 하는 경우를 YAML로 정의하면 다음과 같다.

# allow-frontend-to-backend.yaml
# frontend 네임스페이스에서 backend API 서버로의 Ingress 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: backend
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: frontend
          podSelector:
            matchLabels:
              app: web
      ports:
        - protocol: TCP
          port: 8080

이 정책은 backend 네임스페이스의 app: api-server label을 가진 Pod에 대해, frontend 네임스페이스의 app: web Pod로부터 TCP 8080 포트 접근만 허용한다. namespaceSelectorpodSelector를 동일한 from 항목 안에 넣으면 AND 조건으로 동작하고, 별도의 from 항목으로 분리하면 OR 조건이 된다는 점에 주의해야 한다.

Calico Network Policy 심화

Calico vs 기본 NetworkPolicy 비교

Calico는 Kubernetes 기본 NetworkPolicy API를 완전히 지원하면서, 추가적인 기능을 제공하는 CNI 플러그인이다. 주요 차이점은 다음과 같다.

기능Kubernetes NetworkPolicyCalico NetworkPolicy
정책 스코프네임스페이스 단위네임스페이스 + 클러스터 전역(Global)
정책 순서(Order)없음 (additive)명시적 order 필드 지원
정책 티어(Tier)없음다중 티어 계층 구조
Deny 규칙명시적 Deny 없음명시적 Deny action 지원
Log action미지원정책 매치 시 로깅 가능
Staged Policy미지원프로덕션 적용 전 시뮬레이션
Host Endpoint미지원노드 레벨 방화벽 정책
FQDN/DNS 정책미지원DNS 이름 기반 egress 제어
L7 정책미지원Calico Enterprise에서 지원

GlobalNetworkPolicy로 클러스터 전체 Default-Deny

기본 NetworkPolicy는 네임스페이스 단위로만 적용되므로, 새 네임스페이스가 생성될 때마다 default-deny 정책을 수동으로 추가해야 한다. Calico의 GlobalNetworkPolicy는 클러스터 전체에 한 번에 적용되어 이 문제를 해결한다.

# calico-global-default-deny.yaml
# 클러스터 전체 default-deny (kube-system 제외)
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: default-deny
spec:
  tier: default
  order: 1000
  selector: all()
  namespaceSelector: '!kubernetes.io/metadata.name == "kube-system"'
  types:
    - Ingress
    - Egress

이 정책은 kube-system을 제외한 모든 네임스페이스에 기본 차단을 적용한다. order: 1000은 낮은 우선순위를 의미하여, 더 구체적인 허용 정책들이 먼저 평가된다. Calico에서는 order 값이 낮을수록 우선순위가 높다.

정책 티어링(Tier) 아키텍처

Calico의 티어(Tier) 시스템은 정책을 계층적으로 관리하는 강력한 메커니즘이다. 각 티어는 독립적인 정책 평가 파이프라인을 형성하며, 상위 티어에서 명시적으로 Allow 또는 Deny하지 않은 트래픽은 다음 티어로 전달(Pass)된다.

일반적으로 다음과 같이 3-4개의 티어로 운영한다.

  1. SecurityOps 티어: 보안팀이 관리. 악성 IP 차단, 규제 준수 정책 등 최우선 규칙
  2. Platform 티어: 플랫폼팀이 관리. DNS 허용, 모니터링 에이전트 통신, 공통 인프라 정책
  3. Application 티어: 개발팀이 관리. 애플리케이션별 서비스 간 통신 규칙
  4. Default 티어: 기본 default-deny 정책
# tier-setup.yaml
# SecurityOps 티어 생성 - 보안팀 전용 최우선 정책 계층
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
  name: security-ops
spec:
  order: 100
---
# Platform 티어 생성 - 인프라 공통 정책 계층
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
  name: platform
spec:
  order: 200
---
# Application 티어 생성 - 개발팀 서비스 정책 계층
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
  name: application
spec:
  order: 300
---
# Platform 티어: DNS 및 모니터링 트래픽 허용 정책
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: platform.allow-dns-and-monitoring
spec:
  tier: platform
  order: 100
  selector: all()
  types:
    - Egress
  egress:
    # DNS 트래픽 허용
    - action: Allow
      protocol: UDP
      destination:
        ports:
          - 53
    - action: Allow
      protocol: TCP
      destination:
        ports:
          - 53
    # Prometheus 메트릭 수집 허용
    - action: Allow
      protocol: TCP
      destination:
        selector: app == "prometheus"
        ports:
          - 9090
    # 나머지 트래픽은 다음 티어로 전달
    - action: Pass

이 구조의 장점은 **관심사 분리(Separation of Concerns)**다. 보안팀은 SecurityOps 티어에서 컴플라이언스 정책을, 플랫폼팀은 Platform 티어에서 인프라 정책을, 개발팀은 Application 티어에서 서비스별 정책을 각각 독립적으로 관리할 수 있다.

Staged Policy로 안전한 프로덕션 롤아웃

새로운 네트워크 정책을 프로덕션에 바로 적용하면 예상치 못한 서비스 중단이 발생할 수 있다. Calico의 Staged Policy는 정책을 실제 적용하지 않고 시뮬레이션 모드로 실행하여, 어떤 트래픽이 영향받는지 미리 확인할 수 있게 해준다.

Staged Policy는 리소스 타입을 StagedGlobalNetworkPolicy 또는 StagedNetworkPolicy로 변경하면 된다. 해당 정책은 트래픽을 실제로 차단하거나 허용하지 않지만, Calico 로그에서 "이 트래픽이 정책에 매치되었다"는 기록을 생성한다.

프로덕션 롤아웃 절차는 다음과 같다.

  1. StagedGlobalNetworkPolicy로 정책 배포
  2. Calico Enterprise 또는 로그에서 영향 분석 (최소 24~48시간)
  3. 예상 외 차단 트래픽이 없는지 확인
  4. 리소스 타입을 GlobalNetworkPolicy로 변경하여 실제 적용
  5. 적용 후 모니터링 및 이상 시 즉시 롤백

Cilium Network Policy와 eBPF

Cilium CiliumNetworkPolicy CRD

Cilium은 eBPF(extended Berkeley Packet Filter) 기술을 기반으로 한 고성능 CNI 플러그인이다. 기본 Kubernetes NetworkPolicy를 지원하면서, CiliumNetworkPolicyCiliumClusterwideNetworkPolicy CRD를 통해 L3/L4/L7 수준의 세밀한 정책을 정의할 수 있다.

Cilium의 가장 큰 차별점은 eBPF 기반 데이터 플레인이다. 전통적인 iptables 기반 구현과 달리, eBPF 프로그램이 커널 수준에서 패킷을 처리하므로 정책 규칙 수가 증가해도 성능 저하가 거의 없다. iptables는 규칙이 선형 체인으로 평가되어 규칙 수에 비례해 지연이 증가하지만, eBPF는 해시맵 기반 조회로 O(1)에 가까운 성능을 유지한다.

L3/L4/L7 정책 Enforcement 아키텍처

Cilium의 정책은 세 가지 레이어에서 동작한다.

  • L3 (Network Layer): IP 주소, CIDR, Kubernetes label 기반 트래픽 제어
  • L4 (Transport Layer): TCP/UDP 포트 기반 제어
  • L7 (Application Layer): HTTP 메서드/경로, gRPC 서비스, Kafka 토픽, DNS 도메인 등 애플리케이션 프로토콜 수준 제어

L7 정책은 Cilium이 내장한 Envoy 프록시를 통해 처리된다. 이를 통해 "특정 Pod는 GET /api/v1/users 요청만 허용하고, POST /api/v1/admin 요청은 차단"과 같은 세밀한 제어가 가능하다.

# cilium-l7-http-policy.yaml
# L7 HTTP 정책: API 서버에 대한 메서드/경로 기반 접근 제어
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-server-l7-policy
  namespace: backend
spec:
  endpointSelector:
    matchLabels:
      app: api-server
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: web-frontend
      toPorts:
        - ports:
            - port: '8080'
              protocol: TCP
          rules:
            http:
              # 사용자 조회 API만 허용
              - method: GET
                path: '/api/v1/users.*'
              # 사용자 생성 API 허용
              - method: POST
                path: '/api/v1/users'
              # 헬스체크 엔드포인트 허용
              - method: GET
                path: '/healthz'
    - fromEndpoints:
        - matchLabels:
            app: admin-dashboard
      toPorts:
        - ports:
            - port: '8080'
              protocol: TCP
          rules:
            http:
              # 관리자 대시보드는 모든 메서드 허용
              - method: '.*'
                path: '/api/v1/.*'

이 정책은 web-frontend에서는 사용자 관련 읽기/쓰기 API와 헬스체크만 허용하고, admin-dashboard에서는 모든 API 엔드포인트에 접근 가능하도록 설정한다. L7 정책 위반 시 HTTP 403 응답이 반환되며, Hubble을 통해 차단된 요청의 상세 정보를 확인할 수 있다.

DNS 기반 FQDN 정책으로 외부 접근 제어

프로덕션 환경에서 Pod는 외부 API(결제 게이트웨이, 서드파티 서비스 등)에 접근해야 하는 경우가 많다. IP 기반 egress 정책은 외부 서비스의 IP가 변경되면 깨지는 문제가 있다. Cilium의 FQDN 기반 정책은 DNS 이름으로 외부 접근을 제어하여 이 문제를 해결한다.

# cilium-fqdn-egress-policy.yaml
# DNS 기반 egress 정책: 허용된 외부 도메인만 접근 가능
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: payment-service-egress
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: payment-service
  egress:
    # DNS 조회 허용 (FQDN 정책 동작을 위해 필수)
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: '53'
              protocol: ANY
          rules:
            dns:
              - matchPattern: '*'
    # 결제 게이트웨이 API만 허용
    - toFQDNs:
        - matchName: api.stripe.com
        - matchName: api.paypal.com
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP
    # 내부 데이터베이스 접근 허용
    - toEndpoints:
        - matchLabels:
            app: postgresql
            role: primary
      toPorts:
        - ports:
            - port: '5432'
              protocol: TCP

이 정책은 payment-service Pod가 외부로 나가는 트래픽을 api.stripe.comapi.paypal.com의 443 포트, 그리고 내부 PostgreSQL 데이터베이스의 5432 포트로만 제한한다. DNS 조회 허용 규칙이 반드시 포함되어야 FQDN 정책이 정상 동작한다. Cilium은 DNS 응답을 가로채서 도메인에 대한 IP 매핑을 학습하고, 이후 해당 IP로의 트래픽만 허용한다.

Identity-Based 보안 모델

Cilium의 보안 모델은 전통적인 IP 기반 방화벽과 근본적으로 다르다. 각 Pod 또는 엔드포인트에 **보안 식별자(Security Identity)**를 부여하고, 패킷의 출발지 IP가 아닌 식별자를 기반으로 정책을 평가한다.

이 접근의 장점은 다음과 같다.

  • Pod 재시작/스케일링 시에도 정책 즉시 적용: IP가 변경되어도 label 기반 identity는 유지된다.
  • 정책 평가 성능 향상: IP 범위 매칭 대신 identity 해시 조회로 O(1) 성능을 달성한다.
  • 클러스터 메시 환경 지원: 멀티 클러스터 환경에서도 identity가 전파되어 일관된 정책 적용이 가능하다.

Calico vs Cilium 비교 분석

상세 비교표

두 솔루션의 핵심 차이점을 다음 표로 정리한다.

비교 항목CalicoCilium
데이터 플레인iptables (기본) / eBPF (옵션)eBPF (기본)
L3/L4 정책완전 지원완전 지원
L7 정책Enterprise 버전에서 지원오픈소스에서 기본 지원
FQDN 정책지원 (DNS Policy)지원 (toFQDNs)
정책 티어지원 (Tier CRD)미지원 (단일 계층)
Global 정책GlobalNetworkPolicyCiliumClusterwideNetworkPolicy
Staged Policy지원미지원 (policy-audit-mode 대안)
관찰성(Observability)Calico Enterprise Flow LogsHubble (오픈소스, 기본 내장)
서비스 메시별도 구성 필요Cilium Service Mesh 내장
멀티 클러스터Calico FederationCluster Mesh
암호화WireGuardWireGuard / IPsec
성능 (대규모 정책)iptables 시 규칙 수 비례 지연eBPF 해시맵으로 O(1) 조회
성숙도매우 높음 (2016~)높음 (2018~)
학습 곡선보통높음 (eBPF 개념 이해 필요)

선택 기준과 운영 환경별 추천

Calico를 선택해야 하는 경우

  • 이미 iptables 기반 네트워킹에 익숙한 운영팀
  • 정책 티어링을 통한 멀티 팀 정책 관리가 필요한 대규모 조직
  • Staged Policy로 안전한 프로덕션 롤아웃이 중요한 금융/의료 환경
  • BGP 기반 네트워크 통합이 필요한 온프레미스 환경
  • 기존 Calico 클러스터에서 점진적으로 eBPF로 전환하려는 경우

Cilium을 선택해야 하는 경우

  • L7 수준의 세밀한 정책 제어가 필요한 API 게이트웨이 환경
  • Hubble을 통한 네트워크 관찰성이 중요한 DevSecOps 조직
  • 대규모 정책(수천 개 이상)을 운영하며 eBPF 성능이 필요한 환경
  • 서비스 메시를 사이드카 없이 구현하고 싶은 경우
  • Kubernetes Gateway API와의 통합이 중요한 최신 아키텍처

실무에서는 두 솔루션 모두 프로덕션 검증이 충분히 되어 있으므로, 팀의 기술 스택과 운영 요구사항에 따라 선택하면 된다. 중요한 것은 어떤 솔루션을 선택하든 default-deny 정책을 반드시 적용하고, 정책 변경 시 영향 분석 프로세스를 갖추는 것이다.

프로덕션 운영 가이드

Zero-Trust 네트워크 구현 체크리스트

프로덕션 환경에서 Zero-Trust 네트워크를 구현할 때 다음 체크리스트를 순서대로 진행한다.

  1. 네임스페이스 레이블링 표준화: 모든 네임스페이스와 Pod에 일관된 label 체계를 적용한다. app, env, team, tier 등의 표준 label을 정의한다.
  2. 현재 트래픽 패턴 분석: Hubble이나 Calico Flow Logs로 기존 통신 패턴을 최소 1주일간 수집한다.
  3. Default-Deny 정책 적용: 먼저 audit/staged 모드로 적용하고, 영향 분석 후 enforcement 모드로 전환한다.
  4. DNS 및 필수 인프라 통신 허용: kube-dns, 모니터링 에이전트, 로그 수집기 등 인프라 서비스에 대한 egress를 허용한다.
  5. 서비스별 허용 정책 작성: 수집된 트래픽 패턴을 기반으로 각 서비스에 필요한 최소한의 통신만 허용하는 정책을 작성한다.
  6. 정책 테스트 및 검증: CI/CD 파이프라인에서 정책 린트 및 시뮬레이션을 자동화한다.
  7. 점진적 롤아웃: 개발 환경 - 스테이징 환경 - 프로덕션 카나리 - 프로덕션 전체 순으로 적용한다.
  8. 지속적 모니터링: 정책 위반, 차단된 트래픽, 새로운 통신 패턴을 실시간으로 모니터링한다.

정책 테스트 및 시뮬레이션 전략

네트워크 정책을 프로덕션에 적용하기 전에 반드시 테스트해야 한다. 다음 세 가지 수준의 테스트를 권장한다.

1단계: 정적 분석 (Static Analysis)

kubectl과 정책 린트 도구를 사용해 YAML 문법 오류, 셀렉터 오류를 검증한다. kube-linterconftest로 조직의 정책 표준 준수 여부도 자동 검증할 수 있다.

2단계: 시뮬레이션 (Dry-Run)

Calico의 Staged Policy 또는 Cilium의 policy-audit-mode를 사용한다. Cilium에서는 다음과 같이 에이전트 설정에서 감사 모드를 활성화할 수 있다.

# cilium-config.yaml
# Cilium 에이전트 설정: 정책 감사 모드 활성화
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  enable-policy: 'default'
  policy-audit-mode: 'true'
  monitor-aggregation: 'medium'
  hubble-metrics-server: ':9965'
  hubble-metrics: 'dns,drop,tcp,flow,port-distribution,icmp,httpV2'

감사 모드에서는 정책 위반 트래픽이 차단되지 않고, 대신 Hubble 로그에 action: audit 이벤트가 기록된다. 이를 분석하여 정책의 정확성을 확인한 후 감사 모드를 해제하면 된다.

3단계: 통합 테스트 (Integration Test)

실제 환경과 동일한 구성의 테스트 클러스터에서 서비스 간 통신이 정상적으로 이루어지는지 E2E 테스트를 수행한다. curl, netcat, nmap 등의 도구를 사용해 허용/차단 여부를 구체적으로 검증한다.

Hubble과 Calico Enterprise로 정책 모니터링

Hubble (Cilium)

Hubble은 Cilium에 내장된 관찰성 플랫폼으로, 네트워크 플로우를 실시간으로 시각화한다. hubble observe 명령으로 정책에 의해 차단되거나 허용된 트래픽을 확인할 수 있다.

주요 모니터링 지표는 다음과 같다.

  • hubble_flows_processed_total: 처리된 총 플로우 수
  • hubble_drop_total: 정책에 의해 차단된 패킷 수
  • hubble_policy_verdict: 정책 평가 결과 (allowed/denied/audited)
  • cilium_policy_endpoint_enforcement_status: 엔드포인트별 정책 적용 상태

Calico Enterprise Flow Logs

Calico Enterprise는 모든 허용/차단 트래픽에 대한 상세 플로우 로그를 제공한다. Elasticsearch나 Splunk로 전송하여 대시보드를 구성할 수 있으며, 정책 변경 전후의 트래픽 패턴 변화를 비교 분석하는 데 유용하다.

트러블슈팅: 정책 미적용 및 통신 차단 디버깅

프로덕션에서 자주 발생하는 네트워크 정책 문제와 디버깅 방법을 정리한다.

문제 1: 정책이 적용되었는데 트래픽이 차단되지 않음

  • CNI 플러그인이 NetworkPolicy를 지원하는지 확인한다. Flannel은 기본적으로 NetworkPolicy를 지원하지 않는다.
  • kubectl get networkpolicy -A로 정책이 올바른 네임스페이스에 있는지 확인한다.
  • podSelector가 대상 Pod의 label과 정확히 일치하는지 검증한다.

문제 2: 정상 트래픽이 차단됨

  • default-deny 적용 후 필요한 허용 정책이 누락되었는지 확인한다.
  • namespaceSelectorpodSelector의 AND/OR 조건 적용을 확인한다.
  • DNS egress 허용이 누락되면 서비스 디스커버리가 실패하므로 반드시 확인한다.

문제 3: 간헐적 통신 장애

  • Pod가 재시작되면서 새 IP가 할당될 때 정책 반영 지연이 발생할 수 있다.
  • Cilium의 경우 cilium endpoint list로 endpoint의 정책 상태를 확인한다.
  • Calico의 경우 calicoctl get workloadendpoint로 엔드포인트 매핑을 확인한다.

실패 사례와 복구 절차

사례 1: Default-Deny 없이 운영하다 Lateral Movement 공격

상황: 한 전자상거래 플랫폼에서 공개 웹 서비스의 취약점을 통해 공격자가 하나의 Pod에 침투했다. 네트워크 정책이 전혀 적용되어 있지 않았기 때문에, 공격자는 Redis 캐시, 내부 API 서버, 심지어 데이터베이스까지 자유롭게 접근하여 고객 데이터를 유출했다.

원인 분석:

  • 모든 네임스페이스에 NetworkPolicy가 없는 default-allow 상태
  • 데이터베이스가 별도 네트워크 세그먼트 없이 같은 클러스터에서 운영
  • Pod Security Standard도 미적용으로 컨테이너 이스케이프 가능

복구 및 개선:

  • 즉시 침해 Pod를 격리하고, 영향받은 서비스를 재배포
  • 전체 네임스페이스에 default-deny 정책을 점진적으로 적용
  • 데이터베이스 접근은 app: api-server label을 가진 Pod에서만 허용
  • 외부 egress는 명시적으로 허용된 도메인만 가능하도록 FQDN 정책 적용
  • 주기적인 네트워크 스캔으로 미허가 통신 경로 탐지 자동화

사례 2: 잘못된 정책 순서로 서비스 장애

상황: 보안팀이 Calico 티어에서 새로운 차단 정책을 추가했으나, order 값을 잘못 설정하여 Platform 티어의 DNS 허용 정책보다 높은 우선순위로 적용되었다. 그 결과 클러스터 전체에서 DNS 조회가 실패하여 모든 서비스 간 통신이 중단되었다.

원인 분석:

  • SecurityOps 티어의 새 정책 order가 Platform 티어의 DNS 허용 정책보다 낮은 값(높은 우선순위)이었음
  • 해당 정책이 모든 UDP 53 트래픽을 Deny로 처리
  • Staged Policy를 거치지 않고 바로 프로덕션에 적용

복구 절차:

  1. calicoctl delete gnp 명령으로 문제 정책 즉시 삭제
  2. DNS 서비스 정상화 확인 (약 30초 내 복구)
  3. 정책을 StagedGlobalNetworkPolicy로 재작성하여 시뮬레이션 수행
  4. 정책 order 값 체계 문서화: SecurityOps(100199), Platform(200299), Application(300~399)
  5. 티어 간 order 값 충돌 방지를 위한 CI/CD 검증 게이트 추가

교훈: DNS, kube-apiserver, 모니터링 등 핵심 인프라 통신은 최상위 티어에서 보호해야 하며, 새로운 차단 정책은 반드시 Staged 모드를 거쳐야 한다.

롤백 전략

네트워크 정책으로 인한 장애 발생 시 빠른 롤백이 필수적이다. 다음 세 가지 수준의 롤백을 준비해둔다.

  1. 개별 정책 롤백: 특정 정책만 이전 버전으로 되돌린다. GitOps로 관리 시 git revert 후 자동 동기화된다.
  2. 네임스페이스 단위 롤백: 해당 네임스페이스의 모든 NetworkPolicy를 삭제하여 default-allow 상태로 복원한다. 서비스 복구 후 정책을 순차적으로 재적용한다.
  3. 클러스터 단위 비상 롤백: 모든 NetworkPolicy와 Calico/Cilium 정책을 삭제한다. 최후의 수단이며, 보안 위험을 감수하고 서비스 가용성을 우선시해야 하는 긴급 상황에서만 사용한다.

운영 시 주의사항

네임스페이스 라벨링 전략

네트워크 정책의 효과는 라벨링 체계의 일관성에 달려있다. 다음과 같은 표준 label 스키마를 권장한다.

Label 키설명예시 값
app애플리케이션 이름api-server, web-frontend
version배포 버전v1, v2
env환경 구분production, staging, dev
team담당 팀platform, backend, data
tier아키텍처 티어frontend, backend, database
compliance규제 준수 레벨pci-dss, hipaa, sox

네임스페이스에도 label을 반드시 적용해야 한다. namespaceSelector는 네임스페이스의 label을 기준으로 매칭하기 때문이다. Kubernetes 1.22 이상에서는 kubernetes.io/metadata.name label이 자동 추가되어 이름 기반 선택이 가능하지만, 추가적인 분류 label을 명시적으로 관리하는 것이 좋다.

정책 변경 시 영향 범위 평가

네트워크 정책을 변경할 때는 다음 프로세스를 따른다.

  1. 변경 영향 분석: 정책이 적용되는 Pod 수, 영향받는 서비스 간 통신 경로를 사전에 파악한다.
  2. 피어 리뷰: 보안팀과 서비스 운영팀이 함께 정책 변경을 리뷰한다.
  3. 카나리 적용: 먼저 하나의 네임스페이스나 일부 Pod에만 적용하여 영향을 확인한다.
  4. 모니터링 강화: 변경 후 최소 30분간 차단된 트래픽 로그를 집중 모니터링한다.
  5. 자동 롤백 조건: 차단된 트래픽이 임계값을 초과하면 자동으로 이전 정책으로 롤백하는 메커니즘을 구성한다.

CI/CD 파이프라인에서 정책 검증 자동화

네트워크 정책도 코드로 관리하므로, CI/CD 파이프라인에서 자동 검증이 가능하다. 다음 단계를 파이프라인에 통합한다.

Lint 단계: kubeval 또는 kubeconform으로 YAML 스키마 검증을 수행한다. Calico/Cilium CRD 스키마도 함께 검증한다.

Policy 단계: conftest와 OPA Rego 정책으로 조직 표준 준수 여부를 확인한다. 예를 들어, "모든 네임스페이스에 default-deny 정책이 있는가", "egress 정책에 와일드카드 CIDR(0.0.0.0/0)이 없는가" 등을 검증한다.

Simulation 단계: 테스트 클러스터에 정책을 적용하고 E2E 테스트로 서비스 통신을 검증한다.

Approval 단계: 프로덕션 적용 전 보안팀의 수동 승인 게이트를 둔다.

# github-actions-network-policy-ci.yaml
# GitHub Actions: 네트워크 정책 검증 파이프라인
name: Network Policy Validation
on:
  pull_request:
    paths:
      - 'k8s/network-policies/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: YAML Lint
        run: |
          yamllint k8s/network-policies/

      - name: Schema Validation
        run: |
          kubeconform \
            -schema-location default \
            -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
            k8s/network-policies/*.yaml

      - name: Policy Compliance Check
        uses: open-policy-agent/conftest-action@v2
        with:
          files: k8s/network-policies/
          policy: policies/network/

      - name: Integration Test
        run: |
          kind create cluster --config test/kind-config.yaml
          kubectl apply -f k8s/network-policies/
          ./test/verify-connectivity.sh

이 파이프라인은 네트워크 정책 파일이 변경될 때마다 자동으로 YAML 린트, 스키마 검증, 컴플라이언스 검사, 통합 테스트를 수행하여 안전한 정책 배포를 보장한다.

마치며

Kubernetes 네트워크 보안은 선택이 아닌 필수다. 기본 NetworkPolicy API만으로도 충분히 의미 있는 마이크로세그멘테이션을 구현할 수 있으며, Calico의 티어링 아키텍처와 Staged Policy, Cilium의 L7 정책과 eBPF 성능은 프로덕션 환경에서 더욱 강력한 보안 체계를 제공한다.

가장 중요한 것은 시작하는 것이다. 완벽한 정책 설계를 목표로 하면 오히려 아무것도 적용하지 못하게 된다. 먼저 default-deny를 적용하고, 트래픽 패턴을 관찰하며, 점진적으로 정책을 세밀하게 다듬어 나가는 반복적 접근이 현실적이고 효과적이다.

Zero-Trust 네트워크는 단일 도구나 정책으로 달성되는 것이 아니라, 지속적인 관찰, 분석, 개선의 운영 문화에서 비롯된다. 이 글에서 다룬 기술적 방법론을 기반으로, 조직의 보안 요구사항에 맞는 네트워크 정책 전략을 수립하고 실행하길 바란다.

참고자료