Kubernetes Tools/Cilium

EP06. 기본 L3/L4 정책 설정 | CiliumNetworkPolicy 기초 실습

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

이 글에서는 Cilium의 핵심 기능 중 하나인 네트워크 정책 설정에 대해 알아보겠습니다. 특히 L3(IP) 및 L4(포트) 수준에서 트래픽을 제어하는 CiliumNetworkPolicy 리소스의 기본 사용법과 실제 적용 방법을 실습을 통해 상세히 다룹니다. 전체 트래픽을 차단하는 기본 정책부터 시작하여 특정 Pod와 포트 기반의 허용 정책 작성, 그리고 정책 적용 후 상태 확인 및 로그 분석 방법까지 실무에 바로 적용할 수 있는 내용을 소개합니다.


📌 네트워크 정책의 필요성

쿠버네티스 환경에서는 기본적으로 모든 Pod 간 통신이 허용됩니다. 이는 개발 편의성을 제공하지만, 보안 측면에서는 큰 위험 요소가 될 수 있습니다.

✅ 기본 통신 정책의 문제점

쿠버네티스의 기본 네트워킹 모델은 다음과 같은 특징을 가집니다:

# 쿠버네티스 기본 네트워킹 특성
# 1. 모든 Pod는 NAT 없이 다른 모든 Pod에 접근 가능
#    -> 어떤 Pod든 기본적으로 다른 모든 Pod와 자유롭게 통신 가능함
# 2. 노드의 에이전트(kubelet 등)는 해당 노드의 모든 Pod와 통신 가능
#    -> 노드에서 실행되는 시스템 구성요소가 모든 Pod에 접근 가능함
# 3. 호스트 네트워크에서 실행되는 Pod는 다른 모든 Pod와 통신 가능
#    -> hostNetwork: true로 설정된 Pod는 제한 없이 통신 가능함

이러한 "기본 허용(Default Allow)" 정책은 다음과 같은 보안 문제를 야기할 수 있습니다:

  1. 수평적 이동 위험: 하나의 Pod가 침해되면 클러스터 내 다른 모든 Pod로 공격이 확산될 수 있습니다.
  2. 불필요한 통신 허용: 애플리케이션 로직상 필요하지 않은 통신 경로가 열려 있습니다.
  3. 규정 준수 문제: 많은 보안 규정은 최소 권한 원칙(Principle of Least Privilege)을 요구합니다.

✅ Cilium의 네트워크 정책 접근 방식

Cilium은 eBPF를 기반으로 한 고성능 네트워크 정책을 제공합니다:

  1. 마이크로서비스 지향: 서비스 간 통신을 세밀하게 제어할 수 있습니다.
  2. 다층적 보호: L3/L4(IP, 포트) 뿐만 아니라 L7(애플리케이션 계층)까지 정책 적용이 가능합니다.
  3. 최소 오버헤드: eBPF를 활용하여 커널 레벨에서 정책을 적용함으로써 성능 저하를 최소화합니다.

📌 CiliumNetworkPolicy 개요

CiliumNetworkPolicy는 Cilium에서 네트워크 정책을 정의하는 주요 리소스입니다.

 

CiliumNetworkPolicy 기본구조

 

✅ 기본 구조

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

# CiliumNetworkPolicy의 기본 구조
apiVersion: "cilium.io/v2"  # Cilium API 버전 - v2는 현재 안정화된 API 버전
kind: CiliumNetworkPolicy   # 리소스 종류 - Cilium 고유의 네트워크 정책 리소스
metadata:
  name: "policy-name"       # 정책 이름 - 해당 네임스페이스 내에서 고유한 이름
  namespace: "namespace"    # 정책이 적용될 네임스페이스 - 정책의 적용 범위 지정
spec:
  endpointSelector:         # 정책이 적용될 대상 Pod 선택 - 이 부분이 정책의 핵심
    matchLabels:            # 레이블 기반 선택 - 쿠버네티스 레이블로 Pod 대상 지정
      app: "app-name"       # app=app-name 레이블을 가진 Pod에 정책 적용
  
  ingress:                  # 인바운드 트래픽 규칙 (들어오는 트래픽) - 생략 시 모든 인바운드 트래픽 차단
  - fromEndpoints:          # 어떤 출발지로부터 오는 트래픽인지 - Pod 간 통신 정의
    - matchLabels:          # 레이블로 출발지 Pod 선택
        app: "client-app"   # app=client-app 레이블을 가진 Pod의 트래픽만 허용
    toPorts:                # 허용할 포트와 프로토콜 - 없으면 모든 포트 허용
    - ports:                # 포트 목록 정의
      - port: "80"          # 포트 번호 - 문자열로 작성 (숫자 또는 이름)
        protocol: TCP       # 프로토콜(TCP/UDP) - 명시적으로 프로토콜 지정
  
  egress:                   # 아웃바운드 트래픽 규칙 (나가는 트래픽) - 생략 시 모든 아웃바운드 트래픽 차단
  - toEndpoints:            # 어떤 목적지로 가는 트래픽인지 - Pod 간 통신 정의
    - matchLabels:          # 레이블로 목적지 Pod 선택
        app: "service-app"  # app=service-app 레이블을 가진 Pod로의 트래픽만 허용
    toPorts:                # 허용할 포트와 프로토콜 - 없으면 모든 포트 허용
    - ports:                # 포트 목록 정의
      - port: "80"          # 포트 번호 - 문자열로 작성
        protocol: TCP       # 프로토콜 - TCP 또는 UDP 지정

✅ 핵심 구성 요소

CiliumNetworkPolicy의 주요 구성 요소를 자세히 살펴보겠습니다:

  1. EndpointSelector: 정책이 적용될 대상 Pod를 지정합니다.
    • 쿠버네티스 레이블을 기반으로 선택합니다.
    • 정책의 영향을 받을 Pod를 정확히 타겟팅할 수 있습니다.
  2. Ingress 규칙: Pod로 들어오는 트래픽을 제어합니다.
    • fromEndpoints: 특정 출발지에서 오는 트래픽만 허용
    • fromCIDR: 특정 IP 대역에서 오는 트래픽 허용
    • toPorts: 특정 포트 및 프로토콜 허용
  3. Egress 규칙: Pod에서 나가는 트래픽을 제어합니다.
    • toEndpoints: 특정 목적지로 가는 트래픽만 허용
    • toCIDR: 특정 IP 대역으로 가는 트래픽 허용
    • toPorts: 특정 포트 및 프로토콜 허용
  4. Labels: 정책 자체를 식별하는 레이블도 지정할 수 있습니다.
    • 다른 정책에서 이 정책을 참조할 때 사용 가능합니다.

✅ 정책 평가 방식

Cilium이 네트워크 정책을 평가하는 방식을 이해하는 것이 중요합니다:

  1. 화이트리스트 방식: 명시적으로 허용된 트래픽만 통과하고 나머지는 차단됩니다.
  2. 누적 평가: 여러 정책이 있는 경우, 각 정책의 규칙을 모두 검사하여 하나라도 매치되면 허용합니다.
  3. 빈 정책 처리: ingress/egress 섹션이 비어있는 경우 해당 방향의 모든 트래픽을 차단합니다.

📌 실습 환경 구성

실습을 위한 샘플 애플리케이션을 배포하겠습니다.

✅ 테스트 네임스페이스 생성

# 네트워크 정책 테스트를 위한 네임스페이스 생성
# 이 네임스페이스에서 모든 실습이 진행됩니다
# 별도의 네임스페이스를 사용하면 기존 워크로드에 영향을 주지 않고 안전하게 실습 가능합니다
kubectl create namespace cilium-test

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

다양한 유형의 트래픽을 테스트할 수 있는 애플리케이션을 배포합니다:

# 백엔드 웹 서버 배포
kubectl -n cilium-test apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app        # 배포 이름
  namespace: cilium-test  # 배포할 네임스페이스
spec:
  selector:
    matchLabels:
      app: web         # 이 레이블을 가진 Pod를 관리
  replicas: 2          # 2개의 복제본 실행 (고가용성)
  template:
    metadata:
      labels:
        app: web       # Pod에 적용할 레이블 - 네트워크 정책에서 이 레이블로 Pod 선택
    spec:
      containers:
      - name: web
        image: nginx:1.19.6  # Nginx 웹 서버 이미지 사용
        ports:
        - containerPort: 80  # 80 포트 노출 (HTTP)
---
apiVersion: v1
kind: Service
metadata:
  name: web-service    # 서비스 이름
  namespace: cilium-test
spec:
  selector:
    app: web           # app=web 레이블을 가진 Pod를 타겟팅
  ports:
  - port: 80           # 서비스 포트
    targetPort: 80     # 목적지 Pod 포트
EOF

# API 서버 배포
kubectl -n cilium-test apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-app       # 배포 이름
  namespace: cilium-test
spec:
  selector:
    matchLabels:
      app: api        # 이 레이블을 가진 Pod를 관리
  replicas: 2         # 2개의 복제본 실행
  template:
    metadata:
      labels:
        app: api      # 기본 앱 레이블
        tier: backend # 추가 레이블 - 복합 선택자 테스트에 사용
    spec:
      containers:
      - name: api
        image: mendhak/http-https-echo:29  # HTTP 요청을 에코하는 간단한 API 서버
        ports:
        - containerPort: 8080  # 8080 포트 노출 (HTTP)
---
apiVersion: v1
kind: Service
metadata:
  name: api-service   # 서비스 이름
  namespace: cilium-test
spec:
  selector:
    app: api          # app=api 레이블을 가진 Pod를 타겟팅
  ports:
  - port: 8080        # 서비스 포트
    targetPort: 8080  # 목적지 Pod 포트
EOF

# 데이터베이스 배포
kubectl -n cilium-test apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-app       # 배포 이름
  namespace: cilium-test
spec:
  selector:
    matchLabels:
      app: db        # 이 레이블을 가진 Pod를 관리
  replicas: 1        # DB는 1개 복제본만 실행 (상태 유지형 애플리케이션)
  template:
    metadata:
      labels:
        app: db      # 기본 앱 레이블
        tier: database  # 추가 레이블 - 데이터베이스 계층 식별
    spec:
      containers:
      - name: db
        image: mongo:4.4  # MongoDB 데이터베이스 이미지
        ports:
        - containerPort: 27017  # MongoDB 기본 포트
---
apiVersion: v1
kind: Service
metadata:
  name: db-service    # 서비스 이름
  namespace: cilium-test
spec:
  selector:
    app: db           # app=db 레이블을 가진 Pod를 타겟팅
  ports:
  - port: 27017       # 서비스 포트
    targetPort: 27017 # 목적지 Pod 포트
EOF

# 클라이언트 Pod 배포
kubectl -n cilium-test apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: client       # Pod 이름
  namespace: cilium-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;" ]  # Pod를 계속 실행 상태로 유지
EOF

✅ 애플리케이션 상태 확인

# Pod 상태 확인
# 모든 Pod가 Running 상태인지 확인
kubectl get pods -n cilium-test

# 서비스 상태 확인
# 모든 서비스가 올바른 포트와 타겟으로 구성되었는지 확인
kubectl get svc -n cilium-test

✅ 초기 연결성 테스트

정책을 적용하기 전에 기본 연결성을 테스트합니다. 기본적으로 모든 통신이 허용되어 있어야 합니다:

# client Pod에서 web-service 연결 테스트
# 웹 서버에 HTTP 요청을 보내 응답 확인
kubectl -n cilium-test exec client -- curl -s web-service

# client Pod에서 api-service 연결 테스트
# API 서버에 HTTP 요청을 보내 응답 확인
kubectl -n cilium-test exec client -- curl -s api-service:8080

# client Pod에서 db-service 연결 테스트
# MongoDB 서버에 연결 확인 (인증 없이는 접속이 거부될 수 있음)
kubectl -n cilium-test exec client -- curl -s db-service:27017

모든 서비스에 정상적으로 연결되는 것을 확인할 수 있습니다(MongoDB는 연결은 되지만 인증 오류가 발생할 수 있습니다).


📌 전체 차단 정책 적용하기

먼저 모든 트래픽을 차단하는 기본 정책을 적용해 보겠습니다. 이는 "기본 거부(Default Deny)" 정책의 시작점입니다.

 

전체 차단 정책 (Deny-All) 적용 전/후 비교

 

✅ 전체 차단 정책 작성

# deny-all.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # Cilium 네트워크 정책 리소스
metadata:
  name: "deny-all"          # 정책 이름 - 해당 네임스페이스에서 고유해야 함
  namespace: cilium-test    # 정책이 적용될 네임스페이스
spec:
  # 모든 Pod에 적용되도록 빈 endpointSelector 사용
  endpointSelector:
    matchLabels:
      # 기존에 배포한 모든 앱을 포함하기 위해 빈 셀렉터 사용
      # 빈 셀렉터는 네임스페이스 내 모든 Pod에 매치됨
      # 특정 레이블을 명시하지 않아 네임스페이스 내 모든 Pod에 적용됨
  
  # 인그레스 규칙 없음 - 모든 들어오는 트래픽 차단
  # 빈 배열은 "아무 규칙 없음"을 의미하여 모든 인그레스 트래픽을 차단함
  ingress: []
  
  # 이그레스 규칙 없음 - 모든 나가는 트래픽 차단
  # 빈 배열은 "아무 규칙 없음"을 의미하여 모든 이그레스 트래픽을 차단함
  egress: []
# 정책 적용
# 이 명령으로 위의 deny-all.yaml 파일을 클러스터에 적용
kubectl apply -f deny-all.yaml

✅ 차단 효과 확인

# web-service 연결 테스트 (실패해야 함)
# 타임아웃 설정은 실패 시 무한정 기다리는 것을 방지하기 위함
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 web-service

# api-service 연결 테스트 (실패해야 함)
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 api-service:8080

# db-service 연결 테스트 (실패해야 함)
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 db-service:27017

모든 요청이 타임아웃 되는 것을 확인할 수 있습니다. 이는 정책이 성공적으로 모든 트래픽을 차단하고 있음을 의미합니다.

✅ Hubble로 차단된 트래픽 관찰

Hubble을 사용하여 차단된 트래픽을 관찰해 봅시다:

# 차단된 트래픽 관찰
# --namespace: 특정 네임스페이스의 트래픽만 필터링
# --verdict DROPPED: 차단된 트래픽만 필터링하여 표시
hubble observe --namespace cilium-test --verdict DROPPED

다음과 같은 출력을 볼 수 있습니다:

Dec 7 15:23:45.634: client:34651 -> web-service:80 Policy denied DROPPED
Dec 7 15:23:47.123: client:34652 -> api-service:8080 Policy denied DROPPED
Dec 7 15:23:48.456: client:34653 -> db-service:27017 Policy denied DROPPED

📌 특정 Pod에 대한 인그레스(Ingress) 정책 설정

이제 특정 Pod로의 인그레스 트래픽을 허용하는 정책을 작성해 보겠습니다.

인그레스와 이그레스 정책 개념

 

✅ Web 서버에 대한 접근 허용 정책

# allow-web-ingress.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # 리소스 종류
metadata:
  name: "allow-web-ingress"  # 정책 이름
  namespace: cilium-test     # 정책이 적용될 네임스페이스
spec:
  # 정책을 적용할 대상 - app=web 레이블을 가진 Pod
  # 이 정책은 웹 서버 Pod에만 적용됨 (다른 Pod는 영향 받지 않음)
  endpointSelector:
    matchLabels:
      app: web
  
  # 인그레스 규칙 - 들어오는 트래픽 허용 조건
  ingress:
  - fromEndpoints:  # 어떤 출발지로부터의 트래픽을 허용할지
    - matchLabels:  # app=client 레이블을 가진 Pod로부터의 트래픽만 허용
        app: client  # client 앱에서 오는 트래픽만 허용 (다른 Pod에서 오는 트래픽은 계속 차단)
    toPorts:        # 허용할 포트 지정
    - ports:
      - port: "80"  # 80 포트로의 트래픽 허용 (HTTP)
        protocol: TCP  # TCP 프로토콜만 허용 (UDP는 차단)
# 정책 적용
kubectl apply -f allow-web-ingress.yaml

✅ 정책 적용 확인

# client Pod에서 web-service 연결 테스트 (성공해야 함)
# 정책에 의해 이 연결은 허용되어야 함
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 web-service

# client Pod에서 api-service 연결 테스트 (실패해야 함)
# api-service로의 통신을 허용하는 정책이 아직 없으므로 실패해야 함
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 api-service:8080

client Pod에서 web-service로의 연결은 성공하지만, api-service로의 연결은 여전히 실패합니다. 이는 우리가 설정한 정책이 정확히 적용되고 있음을 의미합니다.

✅ API 서버에 대한 접근 허용 정책 추가

이제 API 서버에 대한 액세스도 허용해 보겠습니다:

# allow-api-ingress.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # 리소스 종류
metadata:
  name: "allow-api-ingress"  # 정책 이름
  namespace: cilium-test     # 정책이 적용될 네임스페이스
spec:
  # 정책을 적용할 대상 - app=api 레이블을 가진 Pod
  # 이 정책은 API 서버 Pod에만 적용됨
  endpointSelector:
    matchLabels:
      app: api
  
  # 인그레스 규칙
  ingress:
  - fromEndpoints:  # client Pod로부터의 트래픽 허용
    - matchLabels:
        app: client  # client 앱에서 오는 트래픽만 허용
    toPorts:        # 8080 포트로의 연결 허용
    - ports:
      - port: "8080"  # API 서버 포트
        protocol: TCP  # TCP 프로토콜만 허용
# 정책 적용
kubectl apply -f allow-api-ingress.yaml
# client Pod에서 api-service 연결 테스트 (성공해야 함)
# 새로 추가한 정책에 의해 이 연결은 이제 허용되어야 함
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 api-service:8080

이제 API 서비스로의 연결도 성공합니다.


📌 이그레스(Egress) 정책 설정

이번에는 특정 Pod에서 나가는 트래픽을 제어하는 이그레스 정책을 설정해 보겠습니다.

✅ Client Pod의 이그레스 트래픽 제어

# allow-client-egress.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # 리소스 종류
metadata:
  name: "allow-client-egress"  # 정책 이름
  namespace: cilium-test      # 정책이 적용될 네임스페이스
spec:
  # 정책을 적용할 대상 - app=client 레이블을 가진 Pod
  # 이 정책은 클라이언트 Pod에서 나가는 트래픽을 제어
  endpointSelector:
    matchLabels:
      app: client
  
  # 이그레스 규칙 - 나가는 트래픽 허용 조건
  egress:
  - toEndpoints:    # 어떤 목적지로 가는 트래픽을 허용할지
    - matchLabels:  # app=web 레이블을 가진 Pod로의 트래픽 허용
        app: web    # 웹 서버로의 트래픽 허용
    toPorts:        # 허용할 포트 지정
    - ports:
      - port: "80"  # 80 포트로의 트래픽 허용 (HTTP)
        protocol: TCP
  
  - toEndpoints:    # app=api 레이블을 가진 Pod로의 트래픽도 허용
    - matchLabels:
        app: api    # API 서버로의 트래픽 허용
    toPorts:
    - ports:
      - port: "8080"  # 8080 포트로의 트래픽 허용 (API 서버 포트)
        protocol: TCP
  
  # kube-dns로의 트래픽 허용 (DNS 해결을 위해 필요)
  # DNS 요청이 차단되면 서비스 이름 해석이 불가능하므로 반드시 허용해야 함
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: kube-system  # kube-system 네임스페이스
        k8s-app: kube-dns                           # kube-dns 앱 레이블
    toPorts:
    - ports:
      - port: "53"  # DNS UDP 포트
        protocol: UDP
      - port: "53"  # DNS TCP 포트
        protocol: TCP
# 정책 적용
kubectl apply -f allow-client-egress.yaml

✅ 이그레스 정책 효과 확인

# client Pod에서 web-service 연결 테스트 (성공해야 함)
# 이그레스 정책에서 web 서비스로의 트래픽을 허용했으므로 성공해야 함
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 web-service

# client Pod에서 api-service 연결 테스트 (성공해야 함)
# 이그레스 정책에서 api 서비스로의 트래픽을 허용했으므로 성공해야 함
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 api-service:8080

# client Pod에서 db-service 연결 테스트 (실패해야 함)
# 이그레스 정책에서 db 서비스로의 트래픽을 허용하지 않았으므로 실패해야 함
kubectl -n cilium-test exec client -- curl -s --connect-timeout 5 db-service:27017

web-service와 api-service로의 연결은 성공하지만, db-service로의 연결은 실패합니다. 이는 이그레스 정책이 의도한 대로 작동하고 있음을 보여줍니다.


📌 포트 기반 정책 설정

특정 포트와 프로토콜에 대한 더 세밀한 제어가 필요한 경우가 많습니다. 이제 포트 기반 정책을 설정해 보겠습니다.

포트 기반 정책 예시

 

✅ API 서버의 다중 포트 허용

API 서버에 여러 포트를 개방하는 정책을 설정해 보겠습니다:

# multi-port-api.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # 리소스 종류
metadata:
  name: "multi-port-api"    # 정책 이름
  namespace: cilium-test    # 정책이 적용될 네임스페이스
spec:
  # 정책을 적용할 대상 - app=api 레이블을 가진 Pod
  # API 서버 Pod에만 적용되는 정책
  endpointSelector:
    matchLabels:
      app: api
  
  # 인그레스 규칙 - 복수 포트 허용
  ingress:
  - fromEndpoints:  # client Pod로부터의 트래픽만 허용
    - matchLabels:
        app: client
    toPorts:
    - ports:
      - port: "8080"  # 주 API 포트 - REST API 요청용
        protocol: TCP
      - port: "8443"  # HTTPS API 포트 - 보안 연결용
        protocol: TCP
      - port: "9090"  # 메트릭 포트 - Prometheus 메트릭 수집용
        protocol: TCP
# 정책 적용
kubectl apply -f multi-port-api.yaml

✅ 포트 범위 정책 설정

포트 범위를 지정하는 정책도 작성할 수 있습니다:

# port-range-policy.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # 리소스 종류
metadata:
  name: "port-range-policy"  # 정책 이름
  namespace: cilium-test     # 정책이 적용될 네임스페이스
spec:
  endpointSelector:          # API 서버 Pod 선택
    matchLabels:
      app: api
  
  ingress:
  - fromEndpoints:           # client Pod로부터의 트래픽만 허용
    - matchLabels:
        app: client
    toPorts:
    - ports:
      - port: "8000-9000"    # 8000부터 9000까지의 포트 범위 허용
        # 이 범위는 다양한 마이크로서비스나 디버깅 포트를 포함할 수 있음
        protocol: TCP        # TCP 프로토콜만 허용
# 정책 적용
kubectl apply -f port-range-policy.yaml

📌 레이블 및 표현식을 활용한 고급 선택자

보다 복잡한 애플리케이션 환경에서는 다양한 선택자를 활용하여 정책을 세밀하게 제어할 필요가 있습니다.

 

복합 레이블 선택자 작동 방식

 

✅ 복합 레이블 선택자 사용

여러 레이블 조건을 조합하여 더 구체적인 Pod 선택이 가능합니다:

# complex-selector.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # 리소스 종류
metadata:
  name: "complex-selector"  # 정책 이름
  namespace: cilium-test    # 정책이 적용될 네임스페이스
spec:
  # 복합 선택자 - app=api AND tier=backend 레이블을 가진 Pod 선택
  # 두 조건을 모두 만족하는 Pod에만 정책 적용 (AND 조건)
  endpointSelector:
    matchLabels:
      app: api       # API 앱 레이블
      tier: backend  # 백엔드 계층 레이블
  
  ingress:
  - fromEndpoints:
    - matchLabels:  # app=client 레이블을 가진 Pod로부터의 트래픽 허용
        app: client
    toPorts:
    - ports:
      - port: "8080"  # 8080 포트 허용
        protocol: TCP

 

# 정책 적용
kubectl apply -f complex-selector.yaml

✅ 부정 매치 표현식 사용

특정 레이블을 가지지 않은 Pod를 선택하는 정책도 작성할 수 있습니다:

# not-match-expression.yaml
apiVersion: "cilium.io/v2"  # Cilium API 버전
kind: CiliumNetworkPolicy   # 리소스 종류
metadata:
  name: "not-match-expression"  # 정책 이름
  namespace: cilium-test        # 정책이 적용될 네임스페이스
spec:
  # tier=database 레이블이 없는 Pod 선택
  # matchExpressions는 보다 복잡한 레이블 선택 조건을 지정할 수 있음
  endpointSelector:
    matchExpressions:
    - key: tier          # 레이블 키
      operator: NotIn    # NotIn 연산자 - 지정된 값이 없어야 함
      values:
      - "database"       # database 값이 없어야 함
  
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: client      # client Pod로부터의 트래픽 허용
# 정책 적용
kubectl apply -f not-match-expression.yaml

이 정책은 tier: database 레이블이 없는 모든 Pod에 적용됩니다.


📌 정책 상태 확인 및 로그 분석

네트워크 정책을 적용한 후에는 정책이 제대로 작동하는지 확인하고 문제를 진단하는 것이 중요합니다.

 

Cilium 네트워크 정책 평가 흐름도

 

✅ 정책 상태 확인

# 적용된 CiliumNetworkPolicy 목록 확인
# 현재 네임스페이스에 적용된 모든 Cilium 네트워크 정책 조회
kubectl get ciliumnetworkpolicies -n cilium-test

# 특정 정책의 상세 정보 확인
# 정책의 상세 내용과 상태 확인
kubectl describe ciliumnetworkpolicy allow-web-ingress -n cilium-test

✅ Cilium 엔드포인트 확인

# Cilium 엔드포인트 목록 확인
# Cilium에서 관리하는 모든 엔드포인트(Pod) 확인
cilium endpoint list -n cilium-test

# 특정 Pod의 엔드포인트 ID 확인
# 1. 클라이언트 Pod 이름 가져오기
CLIENT_POD=$(kubectl get pods -n cilium-test -l app=client -o jsonpath='{.items[0].metadata.name}')
# 2. 해당 Pod의 엔드포인트 ID 가져오기
ENDPOINT_ID=$(cilium endpoint list -n cilium-test | grep $CLIENT_POD | awk '{print $1}')

# 엔드포인트 상세 정보 확인
# 정책 식별자, 레이블, 상태 등 자세한 정보 확인
cilium endpoint get $ENDPOINT_ID

이 명령은 해당 Pod에 적용된 정책 및 식별자 정보를 보여줍니다.

✅ Hubble을 사용한 트래픽 모니터링

Hubble을 사용하여 정책에 의해 허용되거나 차단된 트래픽을 관찰할 수 있습니다:

# 허용된 트래픽 확인
# 정책에 의해 허용된 트래픽 흐름만 필터링
hubble observe --namespace cilium-test --verdict FORWARDED

# 차단된 트래픽 확인
# 정책에 의해 차단된 트래픽 흐름만 필터링
hubble observe --namespace cilium-test --verdict DROPPED

# 특정 Pod 간 트래픽 확인
# 출발지와 목적지를 레이블 기반으로 필터링
hubble observe --namespace cilium-test --from-label app=client --to-label app=web

✅ 정책 문제 해결

정책이 예상대로 작동하지 않을 때 문제를 해결하는 방법:

 

정책 문제 해결 절차

  1. 로그 확인:
# Cilium 에이전트 로그 확인
# 정책 처리 중 발생할 수 있는 오류나 경고 확인
kubectl logs -n kube-system -l k8s-app=cilium --tail=100
  1. 정책 추적 활성화:
# 특정 엔드포인트에 대한 정책 추적 활성화
# 해당 엔드포인트와 관련된 정책 결정 과정을 추적하도록 설정
cilium endpoint config $ENDPOINT_ID PolicyTracing=Enabled

# 추적 결과 확인
# 특정 통신 경로에 대한 정책 평가 결과 추적
# src-k8s-pod: 출발지 Pod
# dst-k8s-pod: 목적지 Pod
# dport: 목적지 포트
cilium policy trace --src-k8s-pod cilium-test/client --dst-k8s-pod cilium-test/web-app-xyz --dport 80

📌 정책 관리 우수 사례

실무에서 네트워크 정책을 효과적으로 관리하기 위한 몇 가지 우수 사례를 소개합니다.

✅ 정책 단계적 적용

프로덕션 환경에서는 정책을 점진적으로 적용하는 것이 안전합니다:

  1. 관찰 모드 사용: 정책을 실제로 적용하기 전에 어떤 트래픽이 차단될지 확인합니다.
  2. 테스트 환경에서 먼저 적용: 프로덕션에 적용하기 전에 테스트 환경에서 충분히 검증합니다.
  3. 작은 범위부터 시작: 전체 환경에 적용하기 전에 작은 서브셋에 먼저 적용합니다.

✅ 정책 템플릿화 및 자동화

대규모 환경에서는 정책 관리를 자동화하는 것이 중요합니다:

  1. Helm 차트 사용: 애플리케이션 배포와 함께 네트워크 정책을 패키징합니다.
  2. GitOps 활용: 정책을 코드로 관리하고 Git 기반 워크플로우로 적용합니다.
  3. CI/CD 파이프라인 통합: 정책 테스트 및 배포를 자동화합니다.

✅ 정책 문서화 및 감사

정책의 목적과 효과를 문서화하고 정기적으로 검토합니다:

  1. 주석 사용: 정책 YAML 파일에 상세한 주석을 추가합니다.
  2. 정기적 검토: 불필요하거나 중복된 정책이 없는지 검토합니다.
  3. 정책 테스트 자동화: 예상대로 작동하는지 자동으로 검증합니다.

📌 Summary

이번 글에서는 Cilium의 L3/L4 네트워크 정책 설정에 대해 알아보았습니다. 주요 내용을 정리하면 다음과 같습니다:

  • CiliumNetworkPolicy는 Cilium에서 네트워크 트래픽을 제어하는 주요 리소스입니다.
  • 기본적으로 화이트리스트 방식으로 작동하여, 명시적으로 허용된 트래픽만 통과시킵니다.
  • endpointSelector를 통해 정책이 적용될 Pod를 레이블 기반으로 선택합니다.
  • ingress 규칙은 Pod로 들어오는 트래픽을, egress 규칙은 Pod에서 나가는 트래픽을 제어합니다.
  • 포트 및 프로토콜 수준까지 세밀하게 트래픽을 제어할 수 있습니다.
  • 복합 레이블 선택자 및 표현식을 통해 더 정교한 정책을 작성할 수 있습니다.
  • Hubble을 사용하여 정책 적용 결과를 실시간으로 관찰하고 문제를 진단할 수 있습니다.
  • 실무에서는 단계적 적용, 템플릿화, 자동화 등의 우수 사례를 따르는 것이 좋습니다.

 

728x90