Notice
Recent Posts
Recent Comments
Link
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
Archives
Today
Total
관리 메뉴

근묵자흑

Kubernetes Pattern: Network Segmentation 본문

k8s/kubernetes-pattern

Kubernetes Pattern: Network Segmentation

Luuuuu 2026. 1. 10. 20:09

애플리케이션 레벨 방화벽 구현

1. 개요

Kubernetes 클러스터는 기본적으로 플랫 네트워크(Flat Network) 구조를 사용합니다. 이 구조에서는 클러스터 내 모든 Pod가 네임스페이스와 관계없이 서로 통신할 수 있습니다. 개발 환경에서는 편리하지만, 프로덕션 환경에서는 보안 문제를 야기할 수 있습니다.

 

Network Segmentation 패턴은 NetworkPolicy와 같은 Kubernetes 리소스를 활용하여 Pod 간 통신을 제어하는 방법을 제시합니다. 이를 통해 보안 침해 시 피해 범위(blast radius)를 제한하고, 워크로드 간 격리를 구현할 수 있습니다.

 

이 글에서는 Calico와 Cilium 두 가지 CNI 환경에서 직접 테스트한 결과를 바탕으로 Network Segmentation 패턴의 구현 방법에 대해 설명합니다.

2. 문제 상황

2.1 Kubernetes 기본 네트워크의 보안 문제

flowchart TB
    subgraph cluster["Kubernetes Cluster - 기본 설정"]
        direction TB
        A[Frontend Pod] <--> B[Backend Pod]
        A <--> C[Database Pod]
        B <--> C
        A <--> D[다른 팀의 Pod]
        B <--> D
        C <--> D
    end

    style A fill:#90EE90
    style B fill:#87CEEB
    style C fill:#FFB6C1
    style D fill:#FFA500

 

기본 설정에서 발생하는 보안 문제는 다음과 같습니다.

 

수평 이동(Lateral Movement) 가능: 공격자가 하나의 Pod를 탈취하면 클러스터 내 다른 모든 Pod로 이동할 수 있습니다. 예를 들어 Frontend Pod가 침해되면 Database Pod에 직접 접근이 가능합니다.

 

민감한 데이터 노출: Database와 같은 백엔드 서비스가 불필요한 클라이언트에게 노출됩니다. 모든 Pod가 Database에 접근할 수 있으므로 데이터 유출 위험이 높아집니다.

 

멀티테넌시 격리 부재: 서로 다른 팀이나 애플리케이션의 워크로드가 의도치 않게 상호작용할 수 있습니다.

2.2 실제 테스트 결과: 기본 네트워크 상태

minikube 환경에서 NetworkPolicy 없이 테스트한 결과, 모든 Pod 간 통신이 허용되었습니다.

출발지 목적지 포트 결과
curl-client random-generator 8080 성공
curl-client frontend 80 성공
curl-client database 5432 성공
frontend random-generator 8080 성공

이 결과는 NetworkPolicy가 없는 상태에서 Kubernetes가 기본적으로 모든 트래픽을 허용함을 보여줍니다. 보안 관점에서 이는 심각한 문제이며, Network Segmentation 패턴을 통해 해결해야 합니다.

3. 해결 방법

Network Segmentation은 OSI 계층에 따라 다른 도구를 사용하여 구현합니다.

flowchart LR
    subgraph L3L4["L3/L4 계층"]
        NP[NetworkPolicy]
    end

    subgraph L7["L7 계층"]
        AP[AuthorizationPolicy]
        CNP[CiliumNetworkPolicy]
    end

    REQ[네트워크 요청] --> NP
    NP -->|IP/Port 검증| AP
    AP -->|HTTP Method/Path 검증| POD[대상 Pod]

    NP -->|IP/Port 검증| CNP
    CNP -->|L7 규칙 검증| POD
도구 계층 기능 CNI 요구사항
NetworkPolicy L3/L4 IP, Port 기반 제어 Calico, Cilium, Weave 등
AuthorizationPolicy L7 HTTP Method, Path, Header 제어 Istio 필요
CiliumNetworkPolicy L3-L7 통합 정책, DNS 기반 제어 Cilium 필요

4. NetworkPolicy: L3/L4 네트워크 세그멘테이션

4.1 CNI 플러그인 지원 현황

NetworkPolicy를 사용하려면 이를 지원하는 CNI(Container Network Interface) 플러그인이 필요합니다. CNI 플러그인은 Kubernetes의 네트워크 구현을 담당하는 핵심 컴포넌트로, Pod에 IP를 할당하고 Pod 간 통신을 가능하게 합니다.

CNI 플러그인 NetworkPolicy 지원 특징
Calico 지원 가장 널리 사용됨, eBPF 옵션 제공, GlobalNetworkPolicy 지원
Cilium 지원 eBPF 기반, L7 정책 지원, Hubble 관찰성 도구 제공
Weave Net 지원 자동 암호화, 간단한 설정
Antrea 지원 VMware 지원, Windows 노드 지원 강점
Flannel 미지원 Calico와 조합하여 사용 가능

지원 여부는 다음 명령어로 확인할 수 있습니다.

kubectl api-resources | grep networkpolicies
# 출력 예시: networkpolicies  netpol  networking.k8s.io/v1  true  NetworkPolicy

4.2 Deny-All 기본 정책

Zero Trust 보안 모델의 핵심은 "기본적으로 모든 것을 차단하고, 필요한 것만 허용"하는 것입니다. NetworkPolicy가 없으면 모든 트래픽이 허용되므로, deny-all 정책을 먼저 적용해야 합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: production
spec:
  podSelector: {}      # 빈 셀렉터 = 모든 Pod 선택
  policyTypes:
    - Ingress
  ingress: []          # 빈 배열 = 모든 Ingress 차단

여기서 주의해야 할 중요한 문법적 차이가 있습니다. 빈 배열 []과 빈 객체를 포함한 배열 [{}]는 완전히 다르게 동작합니다.

설정 동작
ingress: [] 모든 Ingress 트래픽 차단
ingress: [{}] 모든 Ingress 트래픽 허용

이 차이를 이해하지 못하면 의도와 반대되는 정책이 적용될 수 있으므로 주의가 필요합니다.

테스트 결과: Deny-All 정책 적용 후

Calico CNI 환경에서 deny-all 정책을 적용한 후 테스트한 결과는 다음과 같습니다.

출발지 목적지 결과 설명
curl-client random-generator 차단됨 timeout (exit code 28)
curl-client frontend 차단됨 timeout (exit code 28)
curl-client database 차단됨 Operation timed out

deny-all 정책 적용 후 모든 Ingress 트래픽이 차단되었습니다. 이로써 Zero Trust의 첫 번째 단계인 "기본 차단"이 구현되었습니다.

4.3 레이블 기반 허용 정책

deny-all 정책을 적용한 후에는 필요한 통신만 선택적으로 허용해야 합니다. Kubernetes에서는 레이블(Label)을 사용하여 트래픽을 허용할 Pod를 지정합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-access-to-random-generator
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: random-generator      # 이 정책이 적용될 대상 Pod
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: random-client  # 이 레이블을 가진 Pod만 접근 허용
      ports:
        - protocol: TCP
          port: 8080
flowchart LR
    subgraph production["production namespace"]
        CL[curl-client<br/>레이블 없음]
        CLB[curl-client-labeled<br/>role: random-client]
        FE[frontend<br/>role: random-client]
        RG[random-generator<br/>app: random-generator]
    end

    CL -.->|"❌ 차단"| RG
    CLB -->|"✅ 허용"| RG
    FE -->|"✅ 허용"| RG

테스트 결과: 레이블 기반 정책

출발지 레이블 목적지 결과
curl-client 없음 random-generator 차단됨
curl-client-labeled role=random-client random-generator 성공
frontend role=random-client random-generator 성공

테스트 결과, role=random-client 레이블을 가진 Pod만 random-generator에 접근할 수 있었습니다. 레이블이 없는 curl-client는 접근이 차단되었습니다. 이처럼 레이블 기반 접근 제어를 통해 필요한 통신만 선택적으로 허용할 수 있습니다.

4.4 podSelector와 namespaceSelector 조합

실제 환경에서는 같은 네임스페이스 내의 Pod뿐만 아니라 다른 네임스페이스의 Pod도 접근을 허용해야 하는 경우가 있습니다. 예를 들어 monitoring 네임스페이스의 Prometheus가 production 네임스페이스의 애플리케이션 메트릭을 수집해야 하는 경우입니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-monitoring-access
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
    - Ingress
  ingress:
    # 규칙 1: monitoring 네임스페이스의 prometheus Pod만 허용
    - from:
        - namespaceSelector:
            matchLabels:
              name: monitoring
          podSelector:
            matchLabels:
              app: prometheus
      ports:
        - protocol: TCP
          port: 9090
    # 규칙 2: 같은 네임스페이스 내 모든 Pod 허용
    - from:
        - podSelector: {}

namespaceSelector와 podSelector를 조합하는 방식에 따라 동작이 달라집니다. 두 셀렉터가 같은 from 항목 내에 있으면 AND 조건으로 동작하고, 별도의 from 항목으로 분리되면 OR 조건으로 동작합니다.

podSelector namespaceSelector 동작
{} {} 모든 네임스페이스의 모든 Pod
{app: x} {} 모든 네임스페이스에서 app=x인 Pod
{} {name: y} name=y 네임스페이스의 모든 Pod
{app: x} {name: y} name=y 네임스페이스에서 app=x인 Pod
{app: x} 미설정 현재 네임스페이스에서만 app=x인 Pod

마지막 행이 특히 중요합니다. namespaceSelector를 설정하지 않으면 현재 NetworkPolicy가 위치한 네임스페이스 내에서만 Pod를 선택합니다.

4.5 Egress 정책

Egress 정책은 Pod에서 나가는 트래픽을 제어합니다. 실용적인 접근법은 클러스터 내부 통신은 허용하고, 외부 인터넷 접근만 제한하는 것입니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-internal-egress-only
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Egress          # 반드시 Egress만 명시해야 합니다
  egress:
    - to:
        - namespaceSelector: {}  # 모든 네임스페이스로의 통신 허용
flowchart TB
    subgraph cluster["Kubernetes Cluster"]
        subgraph ns1["production namespace"]
            P1[Pod A]
            P2[Pod B]
        end
        subgraph ns2["other namespace"]
            P3[Pod C]
        end
    end

    EXT[외부 서비스<br/>인터넷]

    P1 <-->|"✅ 허용"| P2
    P1 <-->|"✅ 허용"| P3
    P1 -.->|"❌ 차단"| EXT

이 정책을 통해 클러스터 내부의 Pod 간 통신은 허용하면서, 외부 인터넷으로의 무분별한 데이터 유출을 방지할 수 있습니다.

4.6 DNS 허용 정책

Egress를 제한할 때 반드시 고려해야 할 사항이 있습니다. DNS 접근을 차단하면 Service Discovery가 동작하지 않아 Pod 간 통신이 전체적으로 실패합니다. 이는 Kubernetes에서 Service 이름으로 통신할 때 내부적으로 DNS 조회가 발생하기 때문입니다.

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
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

DNS는 주로 UDP 53번 포트를 사용하지만, 응답이 512바이트를 초과하는 경우 TCP로 폴백하므로 TCP 53번 포트도 함께 허용하는 것이 좋습니다.

4.7 policyTypes 동작 이해

policyTypes 필드는 NetworkPolicy가 어떤 방향의 트래픽에 적용되는지 결정합니다. 이 필드의 동작 방식을 정확히 이해하지 못하면 의도치 않은 트래픽 차단이 발생할 수 있습니다.

상황 동작
policyTypes 미지정 + ingress 섹션 있음 Ingress만 적용
policyTypes 미지정 + egress 섹션 있음 Ingress와 Egress 모두 적용
policyTypes: [Egress] 명시 Egress만 적용

두 번째 행이 특히 주의가 필요합니다. Egress 섹션만 정의했는데 policyTypes를 명시하지 않으면, Ingress 정책도 함께 적용되어 모든 인입 트래픽이 차단됩니다.

# 잘못된 예시: Egress만 제어하려 했으나 Ingress도 차단됨
spec:
  podSelector: {}
  egress:
    - to:
        - namespaceSelector: {}
  # policyTypes 미지정 시 [Ingress, Egress]로 동작하여 Ingress도 차단

---
# 올바른 예시: Egress만 제어
spec:
  podSelector: {}
  policyTypes:
    - Egress          # 명시적으로 Egress만 지정
  egress:
    - to:
        - namespaceSelector: {}

4.8 ipBlock을 활용한 외부 IP 제어

특정 외부 IP 대역에 대한 접근을 제어해야 하는 경우 ipBlock을 사용합니다. 이는 클러스터 외부의 서비스(예: 외부 API 서버, SaaS 서비스)에 대한 접근을 제어할 때 유용합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-specific-external
  namespace: production
spec:
  podSelector:
    matchLabels:
      needs-external-access: "true"
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0         # 모든 IP 허용
            except:
              - 10.0.0.0/8          # 내부 네트워크 제외
              - 172.16.0.0/12       # 내부 네트워크 제외
              - 192.168.0.0/16      # 내부 네트워크 제외

5. 3-Tier 아키텍처 네트워크 세그멘테이션 실습

5.1 아키텍처 설계

일반적인 3-Tier 웹 애플리케이션의 네트워크 세그멘테이션을 구현합니다. 이 실습에서는 Frontend, Backend(random-generator), Database로 구성된 환경에서 각 계층 간 통신을 제어합니다.

flowchart TB
    subgraph internet["Internet"]
        USER[사용자]
    end

    subgraph cluster["Kubernetes Cluster"]
        subgraph ing["Ingress Layer"]
            INGRESS[Ingress Controller]
        end

        subgraph app["production namespace"]
            FE[Frontend<br/>tier: frontend]
            BE[Backend<br/>tier: backend]
            DB[(Database<br/>tier: database)]
        end
    end

    USER --> INGRESS
    INGRESS -->|port 80| FE
    FE -->|port 8080| BE
    BE -->|port 5432| DB

5.2 트래픽 매트릭스

보안 요구사항에 따른 허용/차단 트래픽 매트릭스입니다.

출발지 Frontend Backend Database 외부
Ingress 허용 차단 차단 -
Frontend - 허용 차단 차단
Backend 차단 - 허용 차단
Database 차단 차단 - 차단

5.3 정책 구현

기본 Deny-All 정책

먼저 모든 트래픽을 차단하는 기본 정책을 적용합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

DNS 허용 정책

Service Discovery를 위해 DNS 접근을 허용합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  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 정책

Frontend는 외부에서 접근을 받고, Backend로만 요청을 보낼 수 있습니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - ports:
        - protocol: TCP
          port: 80
  egress:
    - to:
        - podSelector:
            matchLabels:
              tier: backend
      ports:
        - protocol: TCP
          port: 8080

Backend 정책

Backend는 Frontend로부터 요청을 받고, Database로만 요청을 보낼 수 있습니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              tier: frontend
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              tier: database
      ports:
        - protocol: TCP
          port: 5432

Database 정책

Database는 Backend로부터만 접근을 받고, 외부로 나가는 트래픽은 없습니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              tier: backend
      ports:
        - protocol: TCP
          port: 5432
  egress: []    # 외부 연결 불필요

5.4 테스트 결과

3-Tier 아키텍처에 NetworkPolicy를 적용한 후 테스트한 결과입니다.

허용된 경로

출발지 목적지 결과
frontend random-generator (backend) 성공
curl-client-labeled (role=random-client) random-generator 성공

차단된 경로

출발지 목적지 결과
curl-client (레이블 없음) random-generator 차단됨
frontend database (직접 접근) 차단됨
curl-client database 차단됨
curl-client frontend 차단됨

테스트 결과, 설계한 트래픽 매트릭스대로 네트워크 세그멘테이션이 정상 동작함을 확인했습니다. Frontend는 Database에 직접 접근할 수 없고, 반드시 Backend를 통해서만 데이터에 접근할 수 있습니다.

6. CiliumNetworkPolicy: L7 정책

6.1 Cilium 개요

Cilium은 eBPF(Extended Berkeley Packet Filter) 기술을 활용하여 커널 레벨에서 네트워크 정책을 적용합니다. 표준 NetworkPolicy를 지원하면서 추가로 L7(애플리케이션) 레벨의 정책을 제공합니다.

eBPF는 Linux 커널 내에서 샌드박스 프로그램을 실행할 수 있게 하는 기술입니다. 전통적인 iptables 방식과 비교했을 때, eBPF는 커널 공간에서 직접 패킷을 처리하므로 성능이 우수하고 더 세밀한 제어가 가능합니다.

flowchart TB
    subgraph traditional["기존 방식 (iptables)"]
        U1[사용자 공간] --> K1[커널: iptables 규칙]
        K1 --> N1[네트워크 인터페이스]
    end

    subgraph ebpf["eBPF 방식 (Cilium)"]
        U2[사용자 공간]
        K2[커널: eBPF 프로그램] --> N2[네트워크 인터페이스]
    end

    style K1 fill:#FFB6C1
    style K2 fill:#90EE90

6.2 L7 HTTP 정책

CiliumNetworkPolicy의 가장 강력한 기능은 HTTP 메서드와 경로 기반으로 트래픽을 제어할 수 있다는 점입니다. 이 기능은 표준 NetworkPolicy로는 구현할 수 없습니다.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: random-generator-l7-policy
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: random-generator
  ingress:
    - fromEndpoints:
        - matchLabels:
            role: random-client
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
          rules:
            http:
              - method: GET
                path: "/.*"

이 정책은 role=random-client 레이블을 가진 Pod에서 random-generator로의 GET 요청만 허용하고, POST, PUT, DELETE 등의 요청은 차단합니다.

테스트 결과: L7 HTTP 정책

Cilium CNI 환경에서 L7 HTTP 정책을 적용한 후 테스트한 결과입니다.

HTTP Method 결과 응답
GET 성공 {"random":-1632411309,...}
POST 차단됨 Access denied
DELETE 차단됨 Access denied

L7 정책이 HTTP 메서드 레벨에서 트래픽을 필터링함을 확인했습니다. 이는 RESTful API에서 읽기 전용 접근만 허용하고 수정/삭제 작업을 차단해야 하는 경우에 유용합니다.

6.3 DNS 기반 Egress 정책

Cilium은 FQDN(Fully Qualified Domain Name) 기반의 Egress 제어를 지원합니다. 표준 NetworkPolicy의 ipBlock은 IP 주소를 알아야 하지만, Cilium의 toFQDNs는 도메인 이름으로 외부 접근을 제어할 수 있습니다.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: dns-based-egress
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: random-generator
  egress:
    # DNS 조회 허용
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
          rules:
            dns:
              - matchPattern: "*"
    # 특정 도메인만 허용
    - toFQDNs:
        - matchName: "api.github.com"
        - matchPattern: "*.googleapis.com"
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP

테스트 결과: DNS 기반 Egress

대상 도메인 정책 설정 결과
api.github.com matchName으로 허용 성공 (HTTP 200)
example.com 미등록 차단됨 (timeout)

DNS 기반 Egress 정책이 도메인 레벨에서 외부 접근을 제어함을 확인했습니다. 이 기능은 특정 외부 API만 호출하도록 제한해야 하는 경우에 유용합니다.

6.4 Hubble을 통한 관찰성

Cilium은 Hubble이라는 네트워크 관찰성 도구를 제공합니다. Hubble을 사용하면 실시간으로 네트워크 흐름을 모니터링하고, 정책 적용 결과를 확인할 수 있습니다.

# 실시간 네트워크 흐름 관찰
hubble observe --namespace production

# 차단된 트래픽만 필터링
hubble observe --namespace production --verdict DROPPED

# 특정 Pod 관련 트래픽
hubble observe --namespace production --to-pod random-generator

# Hubble UI 실행
cilium hubble ui

Hubble UI를 통해 서비스 간 의존성 그래프를 시각적으로 확인할 수 있으며, 어떤 트래픽이 허용되고 차단되었는지 실시간으로 모니터링할 수 있습니다.

7. Calico vs Cilium 비교

minikube 환경에서 Calico와 Cilium 두 CNI를 테스트한 결과를 비교합니다.

7.1 기능 비교

기능 Calico Cilium
표준 NetworkPolicy 지원 지원
Deny-All 정책 동작 확인 동작 확인
레이블 기반 접근 제어 동작 확인 동작 확인
namespaceSelector 동작 확인 동작 확인
L7 HTTP 메서드 필터링 미지원 지원 (CiliumNetworkPolicy)
L7 경로 기반 정책 미지원 지원 (CiliumNetworkPolicy)
DNS 기반 Egress 미지원 지원 (toFQDNs)
네트워크 관찰성 제한적 Hubble 제공
클러스터 전역 정책 GlobalNetworkPolicy CiliumClusterwideNetworkPolicy

8. 테스트 환경 구성

8.1 minikube + Calico 설정

# Calico CNI로 클러스터 생성
minikube start --cni=calico --memory=4096 --cpus=2

# Calico 준비 대기
kubectl wait --for=condition=Ready pods -l k8s-app=calico-node \
  -n kube-system --timeout=300s

# NetworkPolicy API 지원 확인
kubectl api-resources | grep networkpolicies

8.2 minikube + Cilium 설정

# Cilium CNI로 클러스터 생성
minikube start --cni=cilium --memory=4096 --cpus=2

# Cilium 준비 대기
kubectl wait --for=condition=Ready pods -l k8s-app=cilium \
  -n kube-system --timeout=300s

# CiliumNetworkPolicy API 지원 확인
kubectl api-resources | grep ciliumnetworkpolicies

8.3 테스트 애플리케이션 배포

# 네임스페이스 생성 및 레이블링
kubectl create namespace production
kubectl label namespace production name=production

# 테스트 애플리케이션 배포
kubectl apply -f deployment.yaml

8.4 연결 테스트 명령어

# Pod 간 HTTP 통신 테스트
kubectl exec -n production deploy/curl-client -- \
  curl -s --connect-timeout 3 http://random-generator:8080/

# TCP 포트 연결 테스트
kubectl exec -n production deploy/curl-client -- \
  nc -zv -w 3 database 5432

# 정책 확인
kubectl get networkpolicies -n production

# Cilium 정책 확인 (Cilium 환경에서)
kubectl get ciliumnetworkpolicies -n production

8.5 디버깅 명령어

# NetworkPolicy 상세 확인
kubectl describe networkpolicy frontend-policy -n production

# Pod 레이블 확인
kubectl get pods -n production --show-labels

# 네임스페이스 레이블 확인
kubectl get namespaces --show-labels

# Cilium 엔드포인트 상태 확인 (Cilium 환경에서)
kubectl -n kube-system exec -ti ds/cilium -- cilium endpoint list

9. 실무 적용 시 주의 사항

  • CNI 플러그인 확인: NetworkPolicy 적용 전에 사용 중인 CNI가 이를 지원하는지 확인해야 합니다. Flannel은 기본적으로 NetworkPolicy를 지원하지 않으며, Calico와 조합하여 사용해야 합니다.
  • 클러스터 전역 정책의 부재: NetworkPolicy는 네임스페이스 범위(namespace-scoped) 리소스입니다. 클러스터 전역 정책이 필요하면 Calico의 GlobalNetworkPolicy나 Cilium의 CiliumClusterwideNetworkPolicy를 사용합니다.
  • L7 정책의 성능 오버헤드: Cilium의 L7 정책은 Envoy 프록시를 통해 동작하므로 추가적인 리소스 사용과 지연이 발생할 수 있습니다. 성능이 중요한 환경에서는 L7 정책의 영향을 사전에 테스트해야 합니다.
  • policyTypes 주의: policyTypes 필드를 명시하지 않으면 예상과 다르게 동작할 수 있습니다. 특히 Egress만 제어하려면 반드시 policyTypes: [Egress]를 명시해야 합니다.

정책 문서화

NetworkPolicy의 목적과 허용되는 트래픽 패턴을 annotation으로 기록하여 유지보수성을 높입니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: production
  annotations:
    description: "Backend 서비스의 네트워크 정책"
    allowed-ingress: "frontend(8080), prometheus(9090)"
    allowed-egress: "database(5432), dns(53)"
    owner: "platform-team"
    last-reviewed: "2026-01-10"
spec:
  # ...

 

10. 참고 자료