Skip to content
Published on

Cilium 네트워크 정책 엔진: L3/L4/L7 필터링 구현

Authors

Cilium 네트워크 정책 엔진: L3/L4/L7 필터링 구현

개요

Cilium의 네트워크 정책 엔진은 쿠버네티스 NetworkPolicy를 확장하여 L3/L4/L7 수준의 세밀한 트래픽 제어를 제공합니다. eBPF와 Envoy 프록시를 결합한 하이브리드 아키텍처로 고성능과 유연성을 동시에 달성합니다.

1. 정책 리포지토리와 규칙 컴파일

1.1 정책 소스

Cilium은 여러 소스에서 네트워크 정책을 수집합니다.

정책 소스:
1. Kubernetes NetworkPolicy
   - 표준 L3/L4 정책
   - Cilium이 자동으로 변환하여 적용

2. CiliumNetworkPolicy (CNP)
   - 네임스페이스 범위 Cilium 확장 정책
   - L7, FQDN, Identity 기반 등 고급 기능

3. CiliumClusterwideNetworkPolicy (CCNP)
   - 클러스터 전체에 적용되는 정책
   - 기본 거부 정책, 공통 보안 규칙

4. CiliumEnvoyConfig (CEC)
   - Envoy 프록시의 L7 트래픽 관리 규칙

1.2 정책 리포지토리

Agent 내부의 정책 리포지토리가 모든 정책을 통합 관리합니다.

정책 수집 흐름:

K8s API Server
    |
    v
[Watcher: NetworkPolicy]  ->  정책 리포지토리
[Watcher: CNP]             ->  정책 리포지토리
[Watcher: CCNP]            ->  정책 리포지토리
                                    |
                                    v
                               [정책 계산 엔진]
                                    |
                                    v
                               [엔드포인트별 정책 집합]
                                    |
                                    v
                               [BPF 프로그램 컴파일]

1.3 정책에서 BPF 맵으로의 변환

CiliumNetworkPolicy YAML
    |
    v
정책 파싱 및 정규화
    |
    v
셀렉터 매칭: 영향받는 엔드포인트 결정
    |
    v
Identity 기반 허용 목록 생성
    |
    v
BPF 정책 맵 업데이트:
  cilium_policy_<endpoint_id> 맵에 항목 추가
  : (Identity, 포트, 프로토콜)
  : (허용/거부, 프록시 포트)
    |
    v
엔드포인트 BPF 프로그램 재생성 (필요시)

2. Identity 기반 적용 vs IP 기반 적용

2.1 Identity 기반 적용

Cilium의 기본 정책 적용 방식입니다. IP 주소 대신 수치 Identity를 사용합니다.

전통적 IP 기반 방화벽:
  허용: 10.244.1.5 -> 10.244.2.10:8080
  문제: Pod가 재시작되면 IP가 변경됨

Cilium Identity 기반:
  허용: Identity 48291 (app=frontend) -> Identity 52103 (app=backend):8080
  장점: IP 변경에 무관하게 정책 유지
# 정책 맵 내용 확인 (엔드포인트 ID 기준)
cilium bpf policy get 1234

# 출력 예시:
# POLICY   DIRECTION   IDENTITY   PORT/PROTO   PROXY PORT   ENTRY TYPE
# Allow    Ingress     48291      8080/TCP     0            allow
# Allow    Ingress     52103      443/TCP      0            allow
# Allow    Egress      0          53/UDP       0            allow (DNS)

2.2 정책 맵 구조

// 정책 맵 키 (개념적)
struct policy_key {
    __u32 identity;      // 소스/목적지 Identity
    __u16 dport;         // 목적지 포트 (0 = 모든 포트)
    __u8  protocol;      // TCP, UDP, ICMP
    __u8  direction;     // ingress(1), egress(2)
};

// 정책 맵 값
struct policy_entry {
    __u8  action;        // allow(1), deny(2), audit(3)
    __u16 proxy_port;    // L7 프록시 포트 (0 = 프록시 없음)
    __u8  auth_type;     // 인증 타입 (mTLS 등)
    __u64 packets;       // 매칭 패킷 카운터
    __u64 bytes;         // 매칭 바이트 카운터
};

2.3 정책 룩업 알고리즘

패킷 수신 시 정책 룩업:

1. 소스 IP에서 Identity 조회 (ipcache)
2. 정책 맵에서 (Identity, Port, Protocol) 조합 룩업
3. 정확한 매칭 시도:
   - (src_identity, dst_port, protocol) 확인
4. 와일드카드 매칭:
   - (src_identity, ANY_PORT, protocol) 확인
   - (ANY_IDENTITY, dst_port, protocol) 확인
5. Deny 규칙 우선 확인:
   - Deny가 있으면 무조건 거부
6. 결과: Allow / Deny / Audit

3. L3/L4 적용: eBPF에서의 고속 필터링

3.1 L3 정책 (네트워크 레이어)

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l3-policy-example
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
    - fromCIDR:
        - 10.0.0.0/8
    - fromEntities:
        - world
  egress:
    - toEndpoints:
        - matchLabels:
            app: database
    - toCIDR:
        - 0.0.0.0/0
      toCIDRSet:
        - cidr: 0.0.0.0/0
          except:
            - 169.254.169.254/32

3.2 L4 정책 (전송 레이어)

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l4-policy-example
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: '8080'
              protocol: TCP
            - port: '8443'
              protocol: TCP
  egress:
    - toEndpoints:
        - matchLabels:
            app: database
      toPorts:
        - ports:
            - port: '5432'
              protocol: TCP
    - toCIDR:
        - 0.0.0.0/0
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP

3.3 eBPF에서의 L3/L4 적용 흐름

패킷: src=10.244.1.5:34567 dst=10.244.2.10:8080 TCP

1. [from-container 또는 to-container BPF 프로그램]

2. 소스 Identity 조회:
   ipcache[10.244.1.5] -> Identity: 48291

3. 정책 맵 룩업:
   policy_map[endpoint_id] 에서 검색:
   key = (identity=48291, port=8080, proto=TCP, dir=ingress)

4. 결과:
   - Allow: 패킷 전달 계속
   - Deny: 패킷 드롭 + 모니터 이벤트
   - L7 Redirect: Envoy 프록시 포트로 리디렉션

4. L7 적용: Envoy 프록시 통합

4.1 L7 정책 개요

L7 정책은 애플리케이션 프로토콜 수준의 필터링을 제공합니다.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-http-policy
spec:
  endpointSelector:
    matchLabels:
      app: api-server
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: '8080'
              protocol: TCP
          rules:
            http:
              - method: GET
                path: '/api/v1/users'
              - method: GET
                path: '/api/v1/products'
              - method: POST
                path: '/api/v1/orders'
                headers:
                  - 'Content-Type: application/json'

4.2 L7 리디렉션 메커니즘

L7 정책이 적용된 트래픽 흐름:

Pod A -> [from-container BPF]
    |
    v (정책 맵: L7 프록시 리디렉션 필요)
    |
    v
[tc redirect to Envoy proxy port]
    |
    v
[Envoy Proxy (노드당 1)]
  - HTTP/gRPC/Kafka 파싱
  - L7 규칙 매칭
  - 허용/거부 결정
    |
    v (허용된 경우)
    |
    v
[BPF를 통해 목적지로 전달]
    |
    v
Pod B

4.3 지원 프로토콜

프로토콜필터링 가능 필드
HTTPmethod, path, headers, host
gRPCservice, method
Kafkatopic, clientID, apiKey, apiVersion
DNSquery name pattern (matchName, matchPattern)

4.4 Kafka L7 정책 예시

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: kafka-policy
spec:
  endpointSelector:
    matchLabels:
      app: kafka-consumer
  egress:
    - toEndpoints:
        - matchLabels:
            app: kafka-broker
      toPorts:
        - ports:
            - port: '9092'
              protocol: TCP
          rules:
            kafka:
              - role: consume
                topic: 'orders'
              - role: consume
                topic: 'events'

5. FQDN 정책: DNS 프록시 연동

5.1 FQDN 정책 동작 원리

FQDN 정책 흐름:

1. 정책 정의:
   toFQDNs:
     - matchName: "api.example.com"

2. Cilium DNS 프록시 활성화:
   - Pod의 DNS 트래픽을 투명하게 인터셉트
   - DNS 응답에서 IP 주소 학습

3. IP 캐시 업데이트:
   DNS 응답: api.example.com -> 203.0.113.10, 203.0.113.11
   |
   v
   ipcache에 IP -> FQDN 매핑 추가
   BPF 정책 맵에 해당 IP에 대한 허용 규칙 추가

4. 트래픽 허용/차단:
   - 학습된 IP로의 트래픽만 허용
   - DNS TTL에 따라 매핑 만료 및 갱신

5.2 FQDN 정책 예시

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: fqdn-policy
spec:
  endpointSelector:
    matchLabels:
      app: backend
  egress:
    - toFQDNs:
        - matchName: 'api.external-service.com'
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP
    - toFQDNs:
        - matchPattern: '*.storage.googleapis.com'
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: '53'
              protocol: UDP
          rules:
            dns:
              - matchPattern: '*'

5.3 DNS 프록시 내부 동작

DNS 쿼리 처리:

Pod -> DNS 쿼리 (api.example.com)
    |
    v
[from-container BPF: DNS 포트 감지]
    |
    v (DNS 트래픽을 Cilium DNS 프록시로 리디렉션)
    |
    v
[Cilium DNS 프록시]
  - 쿼리를 업스트림 DNS 서버로 전달
  - 응답 수신
  - IP 주소 학습 (A/AAAA 레코드)
  - FQDN-to-IP 매핑 업데이트
  - BPF 맵 업데이트
  - 응답을 Pod에 전달
    |
    v
Pod <- DNS 응답 수신

6. CiliumNetworkPolicy vs CiliumClusterwideNetworkPolicy

6.1 범위 차이

CiliumNetworkPolicy (CNP):
  - 네임스페이스 범위
  - endpointSelector로 같은 네임스페이스의 Pod 선택
  - fromEndpoints/toEndpoints에 namespaceSelector로 교차 네임스페이스 참조

CiliumClusterwideNetworkPolicy (CCNP):
  - 클러스터 범위
  - nodeSelector로 특정 노드 선택 가능
  - 모든 네임스페이스에 적용
  - 클러스터 수준 기본 정책에 적합

6.2 CCNP 활용 예시

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  endpointSelector: {}
  ingress:
    - fromEntities:
        - cluster
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: allow-dns
spec:
  endpointSelector: {}
  egress:
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: '53'
              protocol: UDP
          rules:
            dns:
              - matchPattern: '*'

6.3 호스트 정책

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: host-firewall
spec:
  nodeSelector:
    matchLabels:
      node-role.kubernetes.io/worker: ''
  ingress:
    - fromEntities:
        - remote-node
        - health
      toPorts:
        - ports:
            - port: '10250'
              protocol: TCP
    - fromCIDR:
        - 10.0.0.0/8
      toPorts:
        - ports:
            - port: '22'
              protocol: TCP

7. 정책 감사 모드 (Policy Audit Mode)

7.1 감사 모드 동작

감사 모드에서는 정책 위반 트래픽을 차단하지 않고 로그만 기록합니다.

# 엔드포인트를 감사 모드로 설정
cilium endpoint config 1234 PolicyAuditMode=Enabled

# 전역 감사 모드 설정
cilium config PolicyAuditMode=true

# 감사 로그 확인
cilium monitor --type policy-verdict

# 출력 예시:
# Policy verdict log: flow ... action audit
# -> Would be DROPPED by policy (ingress)
# Identity: 48291 -> 52103, port 8080/TCP

7.2 감사에서 적용으로 전환

감사 모드 활용 워크플로:

1단계: 감사 모드 활성화
  -> 모든 트래픽 허용, 위반 기록

2단계: Hubble로 트래픽 패턴 분석
  -> 실제 필요한 통신 경로 파악

3단계: 정책 작성 및 감사 결과와 비교
  -> 의도하지 않은 차단이 없는지 확인

4단계: 감사 모드 비활성화
  -> 실제 정책 적용 시작

8. 엔드포인트 재생성과 정책 변경

8.1 정책 변경 시 재생성 프로세스

정책 변경 감지:
    |
    v
영향받는 엔드포인트 결정:
  - 셀렉터가 매칭하는 모든 엔드포인트
  - Identity 참조를 통한 간접 영향도 포함
    |
    v
정책 맵 재계산:
  - 새 허용/거부 규칙 집합 생성
  - 기존 정책 맵과 비교 (변경분만 적용)
    |
    v
BPF 맵 업데이트:
  - cilium_policy 맵에 새 항목 추가/삭제
  - 원자적 업데이트로 패킷 손실 최소화
    |
    v
BPF 프로그램 재컴파일 (필요시):
  - L7 리디렉션 추가/제거 시
  - 프로그램 로직 변경이 필요한 경우
    |
    v
엔드포인트 상태 업데이트: Ready

8.2 재생성 성능 최적화

최적화 기법:

1. 증분 업데이트:
   - 전체 재컴파일 대신 BPF 맵만 업데이트
   - 대부분의 정책 변경은 맵 업데이트만으로 충분

2. 배치 재생성:
   - 짧은 시간 내 여러 정책 변경을 배치 처리
   - 불필요한 중복 재생성 방지

3. 선택적 재생성:
   - 영향받는 엔드포인트만 재생성
   - Identity 기반으로 영향 범위 정확히 계산
# 재생성 상태 모니터링
cilium endpoint list

# 재생성 통계
cilium metrics list | grep regeneration

# 주요 메트릭:
# cilium_endpoint_regenerations_total
# cilium_endpoint_regeneration_time_stats_seconds
# cilium_policy_regeneration_total

9. Deny 정책

9.1 Deny 규칙 동작

Cilium은 명시적 Deny 규칙을 지원하며, Deny는 항상 Allow보다 우선합니다.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: deny-specific-cidr
spec:
  endpointSelector:
    matchLabels:
      app: backend
  egressDeny:
    - toCIDR:
        - 169.254.169.254/32
      toPorts:
        - ports:
            - port: '80'
              protocol: TCP
  egress:
    - toCIDR:
        - 0.0.0.0/0
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP

9.2 정책 우선순위

정책 평가 순서:

1. Deny 규칙 확인
   - 매칭하는 Deny 규칙이 있으면 즉시 거부
   - Allow 규칙 무시

2. Allow 규칙 확인
   - 매칭하는 Allow 규칙이 있으면 허용

3. 기본 동작
   - 해당 방향(ingress/egress)에 정책이 있으면: 기본 거부
   - 정책이 전혀 없으면: 기본 허용

10. 정책 트러블슈팅

10.1 디버깅 명령

# 적용된 정책 확인
cilium policy get

# 엔드포인트별 정책 상태
cilium endpoint get 1234

# 정책 맵 내용 확인
cilium bpf policy get 1234

# Identity에서 레이블 확인
cilium identity get 48291

# 정책 verdict 모니터링
cilium monitor --type policy-verdict

# 드롭된 패킷 확인
cilium monitor --type drop

10.2 일반적인 문제와 해결

문제: Pod 간 통신이 차단됨
원인 가능성:
1. Identity가 올바르게 할당되지 않음
   -> cilium identity list로 확인
2. 정책 셀렉터가 올바르지 않음
   -> cilium policy get으로 적용 정책 확인
3. DNS 이그레스 정책이 누락됨
   -> FQDN 정책 사용 시 DNS 허용 필수

문제: L7 정책이 적용되지 않음
원인 가능성:
1. Envoy 프록시가 정상 동작하지 않음
   -> cilium status에서 Proxy 상태 확인
2. toPorts 아래 rules 구문 오류
   -> cilium policy get으로 파싱 결과 확인

정리

Cilium의 네트워크 정책 엔진은 다층적 보안 모델을 통해 강력한 트래픽 제어를 제공합니다.

  • Identity 기반 적용: IP 주소가 아닌 레이블 기반으로 정책을 적용하여 동적 환경에서도 안정적
  • eBPF 고속 필터링: L3/L4 정책을 커널에서 직접 적용하여 최소 지연
  • Envoy L7 통합: HTTP, gRPC, Kafka 등 애플리케이션 수준 필터링
  • FQDN 정책: DNS 프록시를 통한 도메인 기반 이그레스 제어
  • Deny 우선: 명시적 거부 규칙이 항상 우선하여 보안 강화
  • 감사 모드: 정책 적용 전 영향도 사전 파악 가능
  • 증분 업데이트: 최소한의 재생성으로 정책 변경 적용