Kubernetes Tools/Cilium

EP07. Cilium vs Kubernetes NetworkPolicy 비교 | 동작 차이 완벽 이해

ygtoken 2025. 3. 22. 18:30
728x90

 

이 글에서는 Cilium의 네트워크 정책과 쿠버네티스 기본 NetworkPolicy의 차이점을 상세히 비교해 보겠습니다. 두 정책 유형은 같은 목적을 가지고 있지만, 리소스 정의 방식, 기능 범위, 그리고 내부 동작에 있어 중요한 차이가 있습니다. 이번 글에서는 각 정책 유형의 특징, 문법적 차이, 지원하는 기능의 범위, 그리고 실제 환경에서 두 정책을 함께 사용할 때 고려해야 할 호환성 사항까지 살펴보겠습니다.


📌 네트워크 정책의 기본 개념

쿠버네티스에서 네트워크 정책은 Pod 간의 통신을 제어하는 규칙을 정의합니다. 이를 통해 애플리케이션의 보안을 강화하고, "최소 권한 원칙"을 구현할 수 있습니다.

 

네트워크 정책 구조 비교

 

✅ 네트워크 정책의 필요성

쿠버네티스는 기본적으로 모든 Pod 간 통신을 허용하는 "플랫 네트워크" 모델을 사용합니다:

# 기본 쿠버네티스 네트워킹 특성
# 1. 모든 Pod는 다른 모든 Pod에 제한 없이 접근 가능
#    -> 이는 보안 관점에서 위험할 수 있으며 의도하지 않은 접근을 허용함
# 2. 네임스페이스 구분이 없음 - 다른 네임스페이스의 Pod도 접근 가능
#    -> 논리적 분리가 있어도 네트워크 분리는 기본적으로 없음
# 3. 클러스터 외부에서 오는 트래픽도 기본적으로 제한 없음
#    -> 외부 공격에 취약할 수 있음

이러한 개방적인 모델은 개발 편의성을 제공하지만, 보안 측면에서는 취약점이 될 수 있습니다:

  1. 수평적 이동 위험: 하나의 Pod가 침해되면 클러스터 내 모든 곳으로 공격이 확산될 수 있습니다.
  2. 서비스 간 불필요한 통신: 서비스 간 의존성이 명확하지 않으면 불필요한 트래픽이 발생할 수 있습니다.
  3. 규정 준수 어려움: 많은 보안 표준은 네트워크 세분화를 요구합니다.

네트워크 정책은 이러한 문제를 해결하기 위한 솔루션입니다.


📌 쿠버네티스 기본 NetworkPolicy

쿠버네티스는 NetworkPolicy 리소스를 통해 기본적인 네트워크 정책 기능을 제공합니다.

✅ 기본 구조 및 특징

쿠버네티스 NetworkPolicy의 기본 구조는 다음과 같습니다:

# 기본 쿠버네티스 NetworkPolicy 예시
apiVersion: networking.k8s.io/v1  # 네트워킹 API 그룹의 v1 버전 사용
kind: NetworkPolicy              # 리소스 종류는 NetworkPolicy
metadata:
  name: test-network-policy      # 정책 이름 - 식별을 위한 고유 이름
  namespace: default             # 정책이 적용될 네임스페이스 - 정책은 이 네임스페이스 내에서만 적용됨
spec:
  podSelector:                   # 정책이 적용될 Pod 선택 (레이블 기반)
    matchLabels:
      role: db                   # role=db 레이블이 있는 Pod에 정책 적용 - 다른 Pod에는 적용되지 않음
  policyTypes:                   # 정책 타입 지정 (Ingress, Egress 또는 둘 다)
  - Ingress                      # 들어오는 트래픽에 대한 규칙 적용
  - Egress                       # 나가는 트래픽에 대한 규칙 적용
  ingress:                       # 인그레스(들어오는) 트래픽 규칙
  - from:                        # 허용할 트래픽 출발지 목록 - 여러 조건은 OR 관계로 평가됨
    - ipBlock:                   # IP 기반 허용 - 특정 IP 대역에서 오는 트래픽만 허용
        cidr: 172.17.0.0/16      # 172.17.0.0/16 대역의 IP에서 오는 트래픽 허용
        except:                  # 제외할 IP 대역 - 허용 대역 내에서 특정 부분만 제외
        - 172.17.1.0/24          # 172.17.1.0/24 대역은 허용하지 않음
    - namespaceSelector:         # 네임스페이스 기반 허용 - 특정 레이블의 네임스페이스에서 오는 트래픽
        matchLabels:
          project: myproject     # project=myproject 레이블이 있는 네임스페이스에서 오는 트래픽 허용
    - podSelector:               # Pod 레이블 기반 허용 - 특정 레이블의 Pod에서 오는 트래픽
        matchLabels:
          role: frontend         # role=frontend 레이블이 있는 Pod에서 오는 트래픽 허용
    ports:                       # 허용할 포트 목록 - 위의 출발지에서 이 포트로 들어오는 트래픽만 허용
    - protocol: TCP              # TCP 프로토콜만 허용
      port: 6379                 # 6379 포트만 허용 (Redis 포트)
  egress:                        # 이그레스(나가는) 트래픽 규칙
  - to:                          # 허용할 트래픽 목적지 목록
    - ipBlock:                   # IP 기반 허용 - 특정 IP 대역으로 나가는 트래픽만 허용
        cidr: 10.0.0.0/24        # 10.0.0.0/24 대역으로의 트래픽 허용
    ports:                       # 허용할 포트 목록 - 위의 목적지의 이 포트로 나가는 트래픽만 허용
    - protocol: TCP              # TCP 프로토콜만 허용
      port: 5978                 # 5978 포트만 허용

✅ 주요 특징

쿠버네티스 NetworkPolicy의 주요 특징은 다음과 같습니다:

  1. 표준 쿠버네티스 리소스: 모든 쿠버네티스 클러스터에서 공통적으로 지원하는 API입니다.
  2. 지원하는 선택자 타입:
    • podSelector: 특정 Pod를 선택
    • namespaceSelector: 특정 네임스페이스의 모든 Pod를 선택
    • ipBlock: IP CIDR 블록 기반 선택
  3. 지원하는 트래픽 방향:
    • ingress: Pod로 들어오는 트래픽
    • egress: Pod에서 나가는 트래픽
  4. L3/L4 수준 제어:
    • IP 주소 (CIDR)
    • 포트 번호
    • 프로토콜 (TCP/UDP/SCTP)
  5. '화이트리스트' 방식: 명시적으로 허용된 트래픽만 통과시키고 나머지는 차단합니다.

✅ 제한 사항

쿠버네티스 기본 NetworkPolicy의 주요 제한 사항은 다음과 같습니다:

  1. L7 지원 부재: HTTP 헤더, 경로, 메서드와 같은 애플리케이션 계층(L7) 속성에 기반한 필터링을 지원하지 않습니다.
  2. 선택자 조합의 OR 연산 불가: podSelector와 namespaceSelector를 함께 사용할 때 AND 또는 OR 관계의 명확한 지정이 어려울 수 있습니다.
  3. 네임스페이스 간 정책 적용 어려움: 네임스페이스 기반의 접근 방식으로 인해 클러스터 전체 정책 적용이 복잡합니다.
  4. CNI 구현에 따른 차이: 실제 동작은 사용 중인 CNI 플러그인의 NetworkPolicy 구현에 의존합니다.

📌 Cilium의 NetworkPolicy

Cilium은 자체적인 CiliumNetworkPolicy CRD(Custom Resource Definition)를 제공하여 더 확장된 기능을 제공합니다.

✅ 기본 구조

CiliumNetworkPolicy의 기본 구조는 다음과 같습니다:

# CiliumNetworkPolicy 예시
apiVersion: "cilium.io/v2"           # Cilium의 API 그룹 및 버전 - Cilium 전용 API
kind: CiliumNetworkPolicy            # 리소스 종류는 CiliumNetworkPolicy - Cilium 전용 리소스
metadata:
  name: "cidr-rule"                  # 정책 이름 - 식별을 위한 고유 이름
  namespace: default                 # 정책이 적용될 네임스페이스
spec:
  endpointSelector:                  # 정책이 적용될 대상 Pod 선택 - K8s의 podSelector와 유사하지만 용어가 다름
    matchLabels:
      app: myapp                     # app=myapp 레이블이 있는 Pod에 정책 적용
  egress:                            # 이그레스(나가는) 트래픽 규칙
  - toEndpoints:                     # 특정 엔드포인트로의 트래픽 - K8s의 to.podSelector와 유사
    - matchLabels:                   # 레이블 기반 매칭 - 이 레이블을 가진 Pod로의 트래픽만 허용
        app: redis                   # app=redis 레이블이 있는 Pod로의 트래픽 허용
    toPorts:                         # 허용할 포트 목록 - K8s의 ports와 유사하지만 구조가 다름
    - ports:
      - port: "6379"                 # Redis 포트 - 문자열로 지정해야 함 (K8s는 숫자)
        protocol: TCP                # TCP 프로토콜만 허용
  - toCIDR:                          # 특정 IP CIDR로의 트래픽 - K8s의 to.ipBlock과 유사
    - 172.20.0.0/24                  # 172.20.0.0/24 대역으로의 트래픽 허용
    toPorts:                         # 허용할 포트 목록
    - ports:
      - port: "80"                   # HTTP 포트
        protocol: TCP                # TCP 프로토콜만 허용
  ingress:                           # 인그레스(들어오는) 트래픽 규칙
  - fromEndpoints:                   # 특정 엔드포인트로부터의 트래픽 - K8s의 from.podSelector와 유사
    - matchLabels:
        app: frontend                # app=frontend 레이블이 있는 Pod에서 오는 트래픽 허용
    toPorts:                         # 허용할 포트 목록
    - ports:
      - port: "8000"                 # API 포트
        protocol: TCP                # TCP 프로토콜만 허용
      rules:                         # L7 규칙 (HTTP) - K8s NetworkPolicy에는 없는 Cilium 고유 기능
        http:                        # HTTP 프로토콜에 대한 L7 필터링
        - method: "GET"              # GET 메서드만 허용 - POST, PUT 등은 차단
          path: "/api/v1/.*"         # /api/v1/ 경로만 허용 - 정규식 사용 가능

✅ 고급 기능

Cilium의 네트워크 정책은 쿠버네티스 기본 정책보다 훨씬 많은 기능을 제공합니다:

  1. L7 프로토콜 인식:
    • HTTP/gRPC: 메서드, 경로, 헤더 기반 필터링
    • Kafka: 토픽, 클라이언트 ID 기반 필터링
    • DNS: 도메인 이름 기반 필터링
    • 기타: Cassandra, Memcached, MongoDB 등 지원
  2. 확장된 엔드포인트 식별자:
    • toFQDNs: DNS 이름 기반 필터링
    • toServices: 쿠버네티스 서비스 기반 필터링
    • toEntities: 사전 정의된 엔티티(world, host 등) 기반 필터링
  3. 정밀한 선택자 지원:
    • 복합 레이블 매칭
    • 여러 선택자 간 OR 연산자 지원
  4. 클러스터 전체 정책:
    • CiliumClusterwideNetworkPolicy를 통한 네임스페이스 독립적 정책
  5. 네트워크 정책 상태 피드백:
    • 정책 실행 상태 확인 가능
    • Hubble을 통한 정책 적용 결과 관찰
  6. 암호화 지원:
    • WireGuard 또는 IPsec을 통한 Pod 간 통신 암호화

📌 주요 차이점 비교

이제 두 정책 유형 간의 주요 차이점을 표 형식으로 비교해 보겠습니다.

 

✅ 리소스 정의 비교

특징 쿠버네티스 NetworkPolicy Cilium NetworkPolicy
API 그룹 networking.k8s.io/v1 cilium.io/v2
리소스 종류 NetworkPolicy CiliumNetworkPolicy (또는 CiliumClusterwideNetworkPolicy)
대상 선택자 podSelector endpointSelector
소스/대상 지정 from/to fromEndpoints/toEndpoints, toCIDR 등
포트 지정 ports toPorts
네임스페이스 범위 단일 네임스페이스만 단일 또는 클러스터 전체

✅ 기능 범위 비교 

기능 쿠버네티스 NetworkPolicy Cilium NetworkPolicy
L3/L4 필터링 ✅ 지원 ✅ 지원
L7 필터링 ❌ 미지원 ✅ 지원 (HTTP, gRPC, Kafka, DNS 등)
DNS 기반 필터링 ❌ 미지원 ✅ 지원 (toFQDNs)
서비스 기반 필터링 ❌ 미지원 ✅ 지원 (toServices)
특수 엔티티 ❌ 미지원 ✅ 지원 (world, host, remote-node 등)
클러스터 전체 정책 ❌ 미지원 ✅ 지원 (CiliumClusterwideNetworkPolicy)
정책 상태 피드백 ❌ 미지원 ✅ 지원
멀티 클러스터 지원 ❌ 미지원 ✅ 지원 (Cluster Mesh)

✅ 구문 차이 예시

동일한 정책을 두 가지 방식으로 구현해 보겠습니다:

 

쿠버네티스 NetworkPolicy:

# 쿠버네티스 NetworkPolicy 예시
apiVersion: networking.k8s.io/v1    # 쿠버네티스 네트워킹 API 그룹
kind: NetworkPolicy                 # 쿠버네티스 기본 NetworkPolicy 리소스
metadata:
  name: db-policy                   # 정책 이름
  namespace: default                # 적용될 네임스페이스
spec:
  podSelector:                      # 정책이 적용될 대상 Pod 선택
    matchLabels:
      app: db                       # app=db 레이블이 있는 Pod에 적용
  policyTypes:
  - Ingress                         # 들어오는 트래픽에 대한 정책만 적용
  ingress:                          # 인그레스 규칙 정의
  - from:                           # 허용할 출발지 목록
    - podSelector:                  # Pod 기반 선택
        matchLabels:
          app: backend              # app=backend 레이블이 있는 Pod에서 오는 트래픽만 허용
    ports:                          # 허용할 포트 목록
    - protocol: TCP                 # TCP 프로토콜만 허용
      port: 3306                    # MySQL 포트(3306)만 허용

 

Cilium NetworkPolicy:

# 동일한 정책의 Cilium 버전
apiVersion: cilium.io/v2             # Cilium API 그룹
kind: CiliumNetworkPolicy            # Cilium 전용 NetworkPolicy 리소스
metadata:
  name: db-policy                    # 정책 이름 (쿠버네티스 정책과 동일)
  namespace: default                 # 적용될 네임스페이스
spec:
  endpointSelector:                  # 정책이 적용될 대상 Pod 선택 (쿠버네티스의 podSelector와 동일 역할)
    matchLabels:
      app: db                        # app=db 레이블이 있는 Pod에 적용 (쿠버네티스 정책과 동일)
  ingress:                           # 인그레스 규칙 정의 (쿠버네티스 정책과 유사)
  - fromEndpoints:                   # 허용할 출발지 목록 (쿠버네티스의 from.podSelector와 동일 역할)
    - matchLabels:
        app: backend                 # app=backend 레이블이 있는 Pod에서 오는 트래픽만 허용
    toPorts:                         # 허용할 포트 목록 (쿠버네티스의 ports와 유사하지만 구조가 다름)
    - ports:
      - port: "3306"                 # MySQL 포트(3306)만 허용 - 문자열로 지정해야 함 (쿠버네티스는 숫자)
        protocol: TCP                # TCP 프로토콜만 허용 (쿠버네티스 정책과 동일)

 

두 정책은 기본적으로 같은 기능을 수행하지만, Cilium의 경우 추가 기능을 확장할 수 있습니다. 예를 들어, L7 필터링을 추가하면:

# L7 필터링이 추가된 Cilium 정책
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: db-policy
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: db
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: backend
    toPorts:
    - ports:
      - port: "3306"
        protocol: TCP
      rules:                         # L7 규칙 추가 - 쿠버네티스 NetworkPolicy에서는 불가능한 기능
        mysql:                       # MySQL 프로토콜에 대한 L7 필터링
        - query: "SELECT *"          # SELECT 쿼리만 허용 - INSERT, UPDATE, DELETE는 차단
          database: "prod"           # prod 데이터베이스만 접근 가능 - 다른 DB는 접근 불가

📌 선택자 로직 차이

두 정책 유형의 선택자 처리 방식에는 미묘하지만 중요한 차이가 있습니다.

 

Kubernetes vs Cilium 선택자 로직 차이

 

✅ 쿠버네티스 NetworkPolicy의 선택자 로직

쿠버네티스 NetworkPolicy에서는 from 또는 to 블록 내에서 여러 선택자의 처리 방식이 명확하지 않을 수 있습니다.

# 쿠버네티스 선택자 예시
from:
- podSelector:     # 첫 번째 선택자 - 별도의 항목으로 나열됨
    matchLabels:
      role: frontend
- namespaceSelector:  # 두 번째 선택자 - 별도의 항목으로 나열됨
    matchLabels:
      purpose: testing

 

이 예시에서 두 선택자는 OR 관계로 해석됩니다. 즉, role: frontend 레이블이 있는 Pod 또는 purpose: testing 레이블이 있는 네임스페이스의 모든 Pod로부터의 트래픽이 허용됩니다.

 

그러나 다음과 같이 작성하면:

# 쿠버네티스 복합 선택자 예시
from:
- podSelector:     # 첫 번째 선택자의 일부 - 같은 항목 안에 두 선택자가 함께 있음
    matchLabels:
      role: frontend
  namespaceSelector:  # 첫 번째 선택자의 일부 - 같은 항목 안에 두 선택자가 함께 있음
    matchLabels:
      purpose: testing

두 선택자는 AND 관계로 해석됩니다. role: frontend 레이블이 있고, purpose: testing 레이블이 있는 네임스페이스에 속한 Pod만 허용됩니다.

 

이 미묘한 차이는 혼란을 야기할 수 있습니다.

✅ Cilium의 선택자 로직

Cilium의 선택자 로직은 더 명확하고 직관적입니다:

# Cilium 선택자 예시
fromEndpoints:
- matchLabels:    # 첫 번째 엔드포인트 선택자 - 명확히 구분된 항목
    role: frontend
- matchLabels:    # 두 번째 엔드포인트 선택자 - 명확히 구분된 항목
    app: monitoring

여기서 두 선택자는 명확히 OR 관계로 해석됩니다. role: frontend 또는 app: monitoring 레이블이 있는 Pod로부터의 트래픽이 허용됩니다.

 

AND 관계를 표현하려면 단일 선택자에 여러 레이블을 포함시킵니다:

# Cilium AND 관계 선택자
fromEndpoints:
- matchLabels:    # 하나의 선택자에 여러 레이블 - AND 관계 명확
    role: frontend    # role=frontend AND environment=production을 만족해야 함
    environment: production

이 예시에서는 role: frontend와 environment: production 레이블이 모두 있는 Pod만 허용됩니다.


📌 실습: 두 정책 타입 비교

이제 실습을 통해 두 정책 타입을 비교해 보겠습니다. 먼저 테스트 환경을 설정합니다.

✅ 테스트 환경 설정

# 테스트 네임스페이스 생성
# 모든 테스트를 이 네임스페이스 내에서 진행하여 기존 워크로드에 영향을 주지 않음
kubectl create namespace policy-test

# 백엔드 애플리케이션 배포
kubectl -n policy-test apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend                         # 백엔드 애플리케이션 이름
  namespace: policy-test                # 배포할 네임스페이스
spec:
  selector:
    matchLabels:
      app: backend                      # 이 레이블로 Pod 선택
  replicas: 1                           # 1개의 복제본만 실행
  template:
    metadata:
      labels:
        app: backend                    # Pod에 적용할 레이블 - 정책 타겟팅에 사용됨
    spec:
      containers:
      - name: backend
        image: nginx:1.19.6             # 간단한 웹 서버로 Nginx 사용
        ports:
        - containerPort: 80             # 80 포트 노출 (HTTP)
---
apiVersion: v1
kind: Service
metadata:
  name: frontend                        # 프론트엔드 서비스 이름
  namespace: policy-test                # 서비스가 생성될 네임스페이스
spec:
  selector:
    app: frontend                       # 이 레이블을 가진 Pod를 서비스의 엔드포인트로 등록
  ports:
  - port: 80                            # 서비스 포트
    targetPort: 80                      # 대상 Pod 포트
EOF

# 테스트 클라이언트 Pod 배포
kubectl -n policy-test apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: client                          # 클라이언트 Pod 이름
  namespace: policy-test                # 배포할 네임스페이스
  labels:
    app: client                         # Pod에 적용할 레이블 - 정책 타겟팅에 사용됨
spec:
  containers:
  - name: client
    image: curlimages/curl:7.82.0       # curl 명령어가 포함된 이미지 - 네트워크 연결 테스트용
    command: [ "/bin/sh", "-c", "--" ]  # 컨테이너 시작 시 실행할 명령어
    args: [ "while true; do sleep 30; done;" ]  # 컨테이너를 계속 실행 상태로 유지
EOF

# 외부 테스트 Pod 배포 (다른 네임스페이스)
kubectl create namespace outside        # 다른 네임스페이스 생성 - 네임스페이스 간 정책 테스트용
kubectl -n outside apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: external-client                 # 외부 클라이언트 Pod 이름
  namespace: outside                    # 다른 네임스페이스에 배포
  labels:
    app: external-client                # Pod에 적용할 레이블
spec:
  containers:
  - name: client
    image: curlimages/curl:7.82.0       # curl 명령어가 포함된 이미지 - 네트워크 연결 테스트용
    command: [ "/bin/sh", "-c", "--" ]  # 컨테이너 시작 시 실행할 명령어
    args: [ "while true; do sleep 30; done;" ]  # 컨테이너를 계속 실행 상태로 유지
EOF

 

✅ 쿠버네티스 NetworkPolicy 테스트

쿠버네티스 기본 NetworkPolicy를 적용해 보겠습니다:

# 쿠버네티스 NetworkPolicy 예시
apiVersion: networking.k8s.io/v1        # 쿠버네티스 네트워킹 API 그룹
kind: NetworkPolicy                     # 쿠버네티스 기본 NetworkPolicy 리소스
metadata:
  name: backend-policy                  # 정책 이름
  namespace: policy-test                # 정책이 적용될 네임스페이스
spec:
  podSelector:                          # 정책이 적용될 Pod 선택
    matchLabels:
      app: backend                      # app=backend 레이블이 있는 Pod에 적용 (백엔드 앱)
  policyTypes:
  - Ingress                             # 들어오는 트래픽에 대한 정책만 정의
  ingress:                              # 인그레스 규칙 정의
  - from:                               # 허용할 출발지 목록
    - podSelector:                      # Pod 기반 선택
        matchLabels:
          app: frontend                 # app=frontend 레이블이 있는 Pod에서 오는 트래픽만 허용
    ports:                              # 허용할 포트 목록
    - protocol: TCP                     # TCP 프로토콜만 허용
      port: 80                          # 80 포트만 허용 (HTTP)

 

이 정책을 적용한 후 테스트 결과:

# 프론트엔드에서 백엔드로의 연결 (성공해야 함)
# 정책에서 app=frontend 레이블을 가진 Pod에서 app=backend로의 트래픽을 허용했기 때문
kubectl -n policy-test exec frontend-xxxx -- curl -s backend

# 클라이언트에서 백엔드로의 연결 (실패해야 함)
# app=client 레이블을 가진 Pod는 정책에서 허용되지 않았기 때문
kubectl -n policy-test exec client -- curl -s --connect-timeout 5 backend

# 외부 클라이언트에서의 연결 (실패해야 함)
# 다른 네임스페이스(outside)에 있는 Pod도 정책에서 허용되지 않았기 때문
kubectl -n outside exec external-client -- curl -s --connect-timeout 5 backend.policy-test

✅ Cilium NetworkPolicy 테스트

이번에는 Cilium NetworkPolicy를 적용해 보겠습니다:

# Cilium NetworkPolicy 예시
apiVersion: cilium.io/v2                # Cilium API 그룹
kind: CiliumNetworkPolicy               # Cilium 전용 NetworkPolicy 리소스
metadata:
  name: backend-policy                  # 정책 이름
  namespace: policy-test                # 정책이 적용될 네임스페이스
spec:
  endpointSelector:                     # 정책이 적용될 Pod 선택 (쿠버네티스의 podSelector와 동일 역할)
    matchLabels:
      app: backend                      # app=backend 레이블이 있는 Pod에 적용 (백엔드 앱)
  ingress:                              # 인그레스 규칙 정의
  - fromEndpoints:                      # 허용할 출발지 목록 (쿠버네티스의 from.podSelector와 동일 역할)
    - matchLabels:
        app: frontend                   # app=frontend 레이블이 있는 Pod에서 오는 트래픽만 허용
    toPorts:                            # 허용할 포트 목록 (쿠버네티스의 ports와 유사하지만 구조가 다름)
    - ports:
      - port: "80"                      # 80 포트만 허용 (HTTP) - 문자열로 지정해야 함
        protocol: TCP                   # TCP 프로토콜만 허용
      rules:                            # L7 규칙 (HTTP) - 쿠버네티스 NetworkPolicy에는 없는 추가 기능
        http:                           # HTTP 프로토콜에 대한 L7 필터링
        - method: "GET"                 # GET 메서드만 허용 (POST, PUT 등은 차단)
          path: "/api/.*"               # /api/ 경로만 허용 - 정규식 사용 가능

 

이 정책은 기본 NetworkPolicy와 유사하지만 L7 필터링을 추가했습니다. 결과는:

# GET /api/ 요청 (성공해야 함)
# 정책에서 허용한 GET 메서드와 /api/ 경로에 매칭됨
kubectl -n policy-test exec frontend-xxxx -- curl -s backend/api/v1/status

# GET / 요청 (실패해야 함 - 경로 불일치)
# 정책에서 /api/ 경로만 허용했기 때문에 루트 경로(/)는 차단됨
kubectl -n policy-test exec frontend-xxxx -- curl -s backend/

# POST 요청 (실패해야 함 - 메서드 불일치)
# 정책에서 GET 메서드만 허용했기 때문에 POST 요청은 차단됨
kubectl -n policy-test exec frontend-xxxx -- curl -s -X POST backend/api/v1/data

 

L7 필터링 개념

 

✅ 혼합 정책 적용 테스트

 

정책 혼합 사용 시 평가 흐름도

 

두 정책 유형을 함께 적용할 때의 동작을 살펴보겠습니다:

  1. 먼저 쿠버네티스 NetworkPolicy 적용:
# 쿠버네티스 NetworkPolicy 적용
# 이 정책은 app=frontend에서 app=backend로의 모든 HTTP 트래픽 허용
kubectl apply -f kubernetes-policy.yaml
  1. 그 다음 Cilium NetworkPolicy 적용:
# Cilium NetworkPolicy 적용
# 이 정책은 app=frontend에서 app=backend로의 GET /api/ 요청만 허용
kubectl apply -f cilium-policy.yaml

결과:

  • 두 정책은 독립적으로 평가됩니다.
  • 더 제한적인 정책이 우선됩니다.
  • 예를 들어, 쿠버네티스 정책이 모든 HTTP 트래픽을 허용하고 Cilium 정책이 GET 메서드만 허용하면, 결과적으로 GET 메서드만 허용됩니다.

📌 호환성 및 최적 사용 전략

두 정책 타입을 효과적으로 함께 사용하기 위한 전략을 알아보겠습니다.

✅ 호환성 고려사항

  1. 정책 평가 순서:
    • 두 정책 타입은 독립적으로 평가됩니다.
    • 두 정책 모두에서 허용되어야 트래픽이 통과합니다.
  2. 기능 중복 관리:
    • L3/L4 수준에서 중복된 정책을 정의하면 혼란을 야기할 수 있습니다.
    • 각 정책 타입의 강점에 집중하는 것이 좋습니다.
  3. 디버깅 복잡성:
    • 두 정책 타입을 혼합하면 문제 발생 시 디버깅이 더 복잡해질 수 있습니다.

✅ 권장 사용 패턴

  1. 기본 정책에 쿠버네티스 NetworkPolicy 사용:
    • 기본적인 L3/L4 차단을 위해 쿠버네티스 표준 NetworkPolicy 사용
    • 이는 이식성과 호환성을 높여줌
  2. 고급 기능에 Cilium NetworkPolicy 사용:
    • L7 필터링, DNS 기반 정책 등 고급 기능이 필요할 때 Cilium 정책 사용
    • 특정 서비스나 애플리케이션에 대해 더 세밀한 제어가 필요한 경우 사용
  3. 클러스터 전체 정책에 Cilium 사용:
    • 네임스페이스를 초월한 정책이나 클러스터 전체 규칙에는 CiliumClusterwideNetworkPolicy 사용
  4. 마이그레이션 전략:
    • 기존 쿠버네티스 NetworkPolicy에서 Cilium 정책으로 점진적으로 마이그레이션
    • 기존 정책을 유지하면서 Cilium 정책으로 기능 확장

✅ 문서화 및 레이블링 전략

정책이 많아질수록 관리가 복잡해질 수 있으므로, 효과적인 문서화 및 레이블링이 중요합니다:

  1. 일관된 네이밍 규칙:
  2. metadata: name: "tier-backend-policy" # 대상 계층을 이름에 포함 - 쉽게 식별 가능
  3. 주석을 통한 문서화:
  4. metadata: annotations: description: "Frontend에서 Backend API로의 접근 제어" # 정책의 목적 설명 owner: "platform-team" # 관리 책임자/팀 명시 last-updated: "2023-03-15" # 마지막 업데이트 날짜 기록
  5. 레이블을 통한 분류:
  6. metadata: labels: policy-type: "security" # 정책 목적 (보안, 격리, 모니터링 등) tier: "backend" # 대상 계층 (백엔드, 프론트엔드, 데이터베이스 등) environment: "production" # 환경 구분 (개발, 테스트, 프로덕션 등)

📌 실제 운영에서의 선택 가이드

실제 운영 환경에서 어떤 정책 타입을 선택해야 할지 가이드를 제공합니다.

✅ 쿠버네티스 NetworkPolicy를 선택해야 할 때

다음과 같은 경우 쿠버네티스 NetworkPolicy를 선택하는 것이 좋습니다:

  1. 다양한 CNI와의 호환성이 필요한 경우:
    • 여러 클러스터에서 동일한 정책을 사용해야 하는 경우
    • CNI에 관계없이 일관된 정책 적용이 필요한 경우
  2. 기본적인 L3/L4 제어만 필요한 경우:
    • IP, 포트, 프로토콜 기반의 단순한 정책만 필요한 경우
    • 복잡한 애플리케이션 계층 필터링이 필요하지 않은 경우
  3. 표준 컴플라이언스가 중요한 경우:
    • 쿠버네티스 표준 API만 사용해야 하는 환경
    • 벤더 중립적인 접근이 필요한 경우

✅ Cilium NetworkPolicy를 선택해야 할 때

다음과 같은 경우 Cilium NetworkPolicy를 선택하는 것이 좋습니다:

  1. L7 필터링이 필요한 경우:
    • HTTP 경로, 메서드, 헤더 기반 필터링 필요
    • Kafka 토픽, DNS 이름 기반 필터링 필요
  2. 고급 네트워크 보안 기능이 필요한 경우:
    • 마이크로서비스 간 세밀한 액세스 제어 필요
    • 암호화된 통신 필요
    • 네트워크 트래픽 가시성 향상 필요
  3. 클러스터 전체 또는 멀티 클러스터 정책이 필요한 경우:
    • 네임스페이스 경계를 넘어서는 정책 적용 필요
    • 여러 클러스터 간 일관된 정책 적용 필요
  4. DNS 기반 필터링이 필요한 경우:
    • 도메인 이름 기반 외부 액세스 제어 필요
    • FQDN 기반 이그레스 정책 필요

✅ 두 정책 타입을 함께 사용해야 할 때

다음과 같은 경우 두 정책 타입을 함께 사용하는 것이 좋습니다:

  1. 점진적인 마이그레이션 과정에서:
    • 기존 쿠버네티스 정책에서 Cilium으로 단계적 전환
    • 호환성 보장과 함께 새로운 기능 도입
  2. 다층 방어 전략을 구현할 때:
    • 기본 정책은 쿠버네티스 NetworkPolicy로 구현
    • 추가적인 특수 정책은 Cilium으로 구현
  3. 팀 간 책임 분담 시:
    • 플랫폼 팀: 기본 쿠버네티스 정책 관리
    • 앱 팀: 애플리케이션별 Cilium 정책 관리

📌 Summary

이번 글에서는 쿠버네티스 NetworkPolicy와 Cilium NetworkPolicy의 차이점을 상세히 비교해 보았습니다. 주요 내용을 정리하면 다음과 같습니다:

  • 쿠버네티스 NetworkPolicy는 표준 API로, L3/L4 수준의 네트워크 정책을 제공합니다.
  • Cilium NetworkPolicy는 확장된 기능을 제공하며, 특히 L7 필터링, DNS 기반 필터링, 클러스터 전체 정책 등 더 다양한 기능을 지원합니다.
  • 두 정책 타입은 구문과 선택자 로직에 차이가 있으며, Cilium의 선택자 로직이 더 명확하고 직관적입니다.
  • 실제 운영 환경에서는 상황에 맞게 두 정책 타입을 선택하거나 함께 사용하는 전략이 필요합니다.
  • 효과적인 정책 관리를 위해서는 일관된 네이밍, 문서화, 레이블링 전략이 중요합니다.
728x90