Kubernetes Tools/Cilium

EP12. ID 기반 정책과 보안 강화 | Identity 기반 접근 제어 이해

ygtoken 2025. 3. 23. 00:17
728x90

이 글에서는 Cilium의 ID 기반 정책과 보안 강화 방법에 대해 알아보겠습니다. Cilium은 단순한 IP와 포트 기반의 네트워크 정책이 아닌, 워크로드의 정체성(Identity)에 기반한 강력한 접근 제어를 제공합니다. 쿠버네티스 Pod의 라벨을 기반으로 생성되는 Identity의 작동 원리와 Pod 간 ID 맵핑 구조를 이해하고, 실무에서 활용할 수 있는 ID 기반 보안 정책 구성 방법을 살펴보겠습니다. Identity 기반 접근 제어를 통해 동적으로 변화하는 클라우드 네이티브 환경에서도 일관된 보안 정책을 유지하는 방법을 배워봅시다.


📌 Cilium Identity의 개념

✅ 기존 네트워크 정책의 한계

전통적인 네트워크 정책은 주로 다음과 같은 요소를 기반으로 합니다:

  • IP 주소 및 CIDR 범위
  • 포트 번호
  • 프로토콜(TCP, UDP 등)

이러한 접근 방식은 다음과 같은 한계가 있습니다:

  1. IP 기반 정책의 불안정성: 클라우드 환경에서 IP는 동적으로 변경될 수 있어 안정적인 정책 적용이 어렵습니다.
  2. 확장성 문제: 수많은 IP 주소와 포트 조합을 관리하기 어렵습니다.
  3. 의미론적 표현 부족: IP와 포트만으로는 워크로드의 실제 목적과 역할을 표현하기 어렵습니다.
  4. 동적 환경 대응 부족: 컨테이너와 Pod의 생성 및 삭제가 빈번한 환경에서 정책 일관성 유지가 어렵습니다.

 

Cilium Identity 개념 다이어그램

 

✅ Cilium Identity란?

Cilium은 이러한 한계를 극복하기 위해 워크로드의 "Identity"라는 개념을 도입했습니다:

  • Identity의 정의: 워크로드의 특성과 역할을 나타내는 고유 식별자
  • 생성 방식: 주로 쿠버네티스 Pod의 라벨 집합을 기반으로 생성
  • 형태: 내부적으로 32비트 정수 값으로 표현
  • 매핑: 동일한 라벨 집합을 가진 워크로드는 동일한 Identity 공유

Identity는 다음과 같은 이점을 제공합니다:

  1. 불변성: IP가 변경되어도 워크로드의 Identity는 유지됩니다.
  2. 의미론적 분류: 워크로드의 실제 목적과 기능을 반영합니다.
  3. 확장성: 수천 개의 워크로드도 비교적 적은 수의 Identity로 관리 가능합니다.
  4. 효율성: eBPF 맵에서 빠르게 조회하고 처리할 수 있습니다.

📌 Cilium Identity의 작동 원리

✅ Identity 생성 과정

Identity 생성 및 할당 프로세스

 

Cilium은 다음과 같은 과정을 통해 Identity를 생성하고 관리합니다:

  1. 라벨 추출: Pod가 생성될 때 해당 Pod의 라벨을 추출합니다.
  2. 보안 관련 라벨 필터링: 네트워크 정책에 관련된 보안 라벨만 선택합니다.
  3. Identity 해시 계산: 선택된 라벨 집합에서 해시 값을 계산합니다.
  4. ID 할당: 해시 값을 기반으로 고유한 32비트 ID 값을 할당합니다.
  5. 저장 및 공유: 할당된 ID를 Cilium 에이전트 간에 공유합니다.

이 과정을 코드로 나타내면 다음과 같습니다(개념적인 의사 코드):

// allocateIdentity 함수는 Pod의 라벨을 기반으로 Identity를 할당합니다
func allocateIdentity(labels map[string]string) uint32 {
    // 보안 관련 라벨만 필터링
    // 모든 라벨이 Identity 계산에 사용되는 것이 아니라, 보안과 관련된 라벨만 선택됨
    securityLabels := filterSecurityLabels(labels)
    
    // 라벨 집합으로부터 해시 계산
    // 고유한 Identity를 보장하기 위해 선택된 라벨의 해시값을 계산
    labelHash := computeHash(securityLabels)
    
    // 해시를 기반으로 Identity 조회 또는 생성
    // 이미 동일한 해시를 가진 Identity가 있다면 재사용, 없으면 새로 생성
    identity, exists := identityCache[labelHash]
    if !exists {
        identity = generateNewIdentity()  // 새로운 32비트 ID 생성
        identityCache[labelHash] = identity  // 캐시에 저장
    }
    
    return identity  // 할당된 Identity 반환
}

✅ Identity 저장 및 관리

Cilium은 Identity 정보를 다음과 같은 방식으로 저장하고 관리합니다:

  1. 로컬 캐시: 각 Cilium 에이전트는 로컬 메모리에 Identity 정보를 캐싱합니다.
  2. 분산 저장소: 클러스터 전체에서 일관된 Identity 관리를 위해 분산 저장소(기본적으로 쿠버네티스 CRD) 사용합니다.
  3. eBPF 맵: 빠른 조회를 위해 Identity 정보를 eBPF 맵에 저장합니다.

Identity 정보를 조회하기 위한 명령어:

# Cilium 관리 Pod에서 실행
# 클러스터에 있는 모든 Identity 목록 조회
kubectl exec -n kube-system cilium-xxxx -- cilium identity list

# 특정 Identity의 상세 정보 조회
# 12345는 조회하려는 Identity ID 번호
kubectl exec -n kube-system cilium-xxxx -- cilium identity get 12345

✅ Identity와 Endpoint의 관계

Cilium에서 "Endpoint"는 네트워크 정책이 적용될 수 있는 개체(주로 Pod)를 가리킵니다:

  • Endpoint 생성: Pod가 생성될 때 Cilium은 해당 Pod를 Endpoint로 등록합니다.
  • Identity 할당: 각 Endpoint는 라벨을 기반으로 계산된 Identity를 할당받습니다.
  • 매핑 테이블: Cilium은 Endpoint ID와 Identity 간의 매핑 테이블을 유지합니다.

Endpoint의 Identity 정보를 확인하는 명령어:

# 모든 Endpoint 정보 조회
# Pod, IP, Identity 등의 연관 정보 확인 가능
kubectl exec -n kube-system cilium-xxxx -- cilium endpoint list

# 특정 Endpoint의 상세 정보 조회
# 1234는 조회하려는 Endpoint ID 번호
kubectl exec -n kube-system cilium-xxxx -- cilium endpoint get 1234

📌 Identity 기반 네트워크 정책 구성

Pod 간 ID 맵핑 구조 #1

 

Pod 간 ID 맵핑 구조 #2

 

✅ 기본 Identity 기반 정책 작성법

Cilium에서는 다음과 같이 Identity 기반 정책을 작성할 수 있습니다:

# identity-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "identity-based-policy"  # 정책 이름
  namespace: default  # 정책이 적용될 네임스페이스
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      app: backend  # backend 라벨을 가진 Pod에 적용
  ingress:  # 인바운드(들어오는) 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchLabels:
        app: frontend  # frontend 라벨을 가진 Pod의 접근만 허용
    toPorts:  # 대상 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "8080"  # 8080 포트만 허용
        protocol: TCP  # TCP 프로토콜만 허용

위 정책은 다음과 같은 의미를 갖습니다:

  • app: backend 라벨을 가진 Pod(Identity)에 대해
  • app: frontend 라벨을 가진 Pod(Identity)로부터의 접근만 허용
  • 접근 포트는 TCP 8080으로 제한

이 정책은 IP가 아닌 Identity를 기반으로 하므로, Pod의 IP가 변경되어도 계속 올바르게 적용됩니다.

✅ 복합 라벨 및 연산자를 활용한 정책

더 복잡한 Identity 조건을 정의하기 위해 여러 라벨과 연산자를 활용할 수 있습니다:

# complex-identity-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "complex-identity-policy"  # 정책 이름
  namespace: default  # 정책이 적용될 네임스페이스
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      app: database  # app=database 라벨을 가진 Pod 선택
      environment: production  # environment=production 라벨도 가진 Pod만 선택
  ingress:  # 인바운드 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchExpressions:  # 복합 표현식으로 Pod 선택
      - key: role  # role 라벨에 대해
        operator: In  # In 연산자 사용 (포함되는지 확인)
        values:  # 다음 값 중 하나라도 포함되면 선택
        - backend  # role=backend 또는
        - api      # role=api
      - key: environment  # environment 라벨에 대해
        operator: In  # In 연산자 사용
        values:
        - production  # environment=production 또는
        - staging     # environment=staging
      - key: version  # version 라벨에 대해
        operator: NotIn  # NotIn 연산자 사용 (포함되지 않는지 확인)
        values:
        - deprecated  # version=deprecated가 아니고
        - beta        # version=beta가 아닌 Pod만 선택
    toPorts:  # 대상 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "5432"  # PostgreSQL 기본 포트
        protocol: TCP  # TCP 프로토콜만 허용

이 정책은:

  • app: database 및 environment: production 라벨을 모두 가진 Pod에 적용됩니다.
  • role: backend 또는 role: api 라벨을 가지고
  • environment: production 또는 environment: staging 라벨을 가지면서
  • version: deprecated 또는 version: beta 라벨을 가지지 않는 Pod의 접근만 허용합니다.
  • 접근 포트는 TCP 5432로 제한합니다.

✅ 예약된 Identity 활용하기

Cilium은 특정 목적을 위한 예약된 Identity를 제공합니다:

  1. host: 호스트 네트워크를 가리키는 Identity
  2. remote-node: 다른 노드를 가리키는 Identity
  3. cluster: 클러스터 내의 모든 엔드포인트를 가리키는 Identity
  4. world: 클러스터 외부의 모든 엔드포인트를 가리키는 Identity

이러한 예약 Identity를 사용한 정책 예시:

# reserved-identity-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "reserved-identity-policy"  # 정책 이름
  namespace: default  # 정책이 적용될 네임스페이스
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      app: web-server  # app=web-server 라벨을 가진 Pod에 적용
  ingress:  # 인바운드 트래픽 규칙
  - fromEntities:  # 특별 엔터티(Entity)로부터의 트래픽
    - "world"  # 인터넷(클러스터 외부)에서의 접근 허용
    toPorts:  # 허용할 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "80"  # HTTP 기본 포트
        protocol: TCP  # TCP 프로토콜만 허용
  - fromEntities:  # 다른 특별 엔터티로부터의 트래픽
    - "host"  # 호스트 네트워크에서의 접근 허용
    toPorts:  # 허용할 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "8080"  # 관리용 포트
        protocol: TCP  # TCP 프로토콜만 허용

이 정책은:

  • app: web-server 라벨을 가진 Pod에 적용됩니다.
  • 외부 세계(world Identity)에서의 HTTP 접근(80/TCP)을 허용합니다.
  • 호스트(host Identity)에서의 8080/TCP 접근을 허용합니다.

📌 실습: Identity 기반 정책 테스트

✅ 테스트 환경 설정

Identity 기반 정책을 테스트하기 위한 환경을 설정합니다:

# identity-test.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: identity-test  # 테스트용 네임스페이스 생성
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app  # 웹 애플리케이션 배포
  namespace: identity-test
spec:
  selector:
    matchLabels:
      app: web  # 셀렉터 라벨
      tier: frontend
  replicas: 2  # 2개의 복제본 생성
  template:
    metadata:
      labels:
        app: web  # Pod 라벨 (Identity 생성에 사용)
        tier: frontend  # 계층 정보
        version: v1  # 버전 정보
    spec:
      containers:
      - name: nginx
        image: nginx:1.19  # 웹 서버로 Nginx 사용
        ports:
        - containerPort: 80  # 웹 서버 포트
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-service  # API 서비스 배포
  namespace: identity-test
spec:
  selector:
    matchLabels:
      app: api
      tier: backend
  replicas: 2
  template:
    metadata:
      labels:
        app: api  # Pod 라벨 (다른 Identity 생성)
        tier: backend
        version: v1
    spec:
      containers:
      - name: httpd
        image: httpd:2.4  # 웹 서버로 Apache 사용
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-service  # 데이터베이스 서비스 배포
  namespace: identity-test
spec:
  selector:
    matchLabels:
      app: db
      tier: database
  replicas: 1
  template:
    metadata:
      labels:
        app: db  # Pod 라벨 (다른 Identity 생성)
        tier: database
        version: v1
    spec:
      containers:
      - name: postgres
        image: postgres:13  # 데이터베이스로 PostgreSQL 사용
        ports:
        - containerPort: 5432  # 데이터베이스 포트
        env:
        - name: POSTGRES_PASSWORD  # PostgreSQL 필수 환경 변수
          value: "password"  # 테스트용 비밀번호 (실무에서는 Secret 사용 권장)
---
apiVersion: v1
kind: Service
metadata:
  name: web-service  # 웹 서비스 생성
  namespace: identity-test
spec:
  selector:
    app: web  # app=web 라벨을 가진 Pod 선택
  ports:
  - port: 80  # 서비스 포트
    targetPort: 80  # Pod 포트
---
apiVersion: v1
kind: Service
metadata:
  name: api-service  # API 서비스 생성
  namespace: identity-test
spec:
  selector:
    app: api  # app=api 라벨을 가진 Pod 선택
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: db-service  # 데이터베이스 서비스 생성
  namespace: identity-test
spec:
  selector:
    app: db  # app=db 라벨을 가진 Pod 선택
  ports:
  - port: 5432  # PostgreSQL 포트
    targetPort: 5432
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-client  # 테스트용 클라이언트 배포
  namespace: identity-test
spec:
  selector:
    matchLabels:
      app: test-client
  replicas: 1
  template:
    metadata:
      labels:
        app: test-client  # 다른 Identity를 가진 테스트 클라이언트
    spec:
      containers:
      - name: curl
        image: curlimages/curl:7.80.0  # curl 도구가 설치된 이미지
        command: ["sleep", "3600"]  # 1시간 동안 실행 상태 유지

위 매니페스트를 적용합니다:

kubectl apply -f identity-test.yaml

✅ Identity 확인

테스트 환경에서 생성된 Pod들의 Identity를 확인합니다:

# Cilium 관리 Pod 찾기
CILIUM_POD=$(kubectl -n kube-system get pods -l k8s-app=cilium -o jsonpath='{.items[0].metadata.name}')

# Identity 목록 조회 (identity-test 네임스페이스에 해당하는 것만 필터링)
kubectl exec -n kube-system $CILIUM_POD -- cilium identity list | grep identity-test

# Endpoint 목록 조회 (더 자세한 정보를 JSON 형식으로 확인)
kubectl exec -n kube-system $CILIUM_POD -- cilium endpoint list -o json | jq '.[] | select(.status.identity != null) | {id: .id, labels: .status.labels, identity: .status.identity}'

조회 결과에서 각 Pod에 할당된 Identity 값과 라벨을 확인할 수 있습니다.

✅ 기본 연결 테스트

정책 적용 전에 모든 서비스 간의 연결을 테스트합니다:

# test-client Pod 이름 가져오기
TEST_POD=$(kubectl -n identity-test get pod -l app=test-client -o jsonpath='{.items[0].metadata.name}')

# 웹 서비스 연결 테스트
kubectl exec -n identity-test $TEST_POD -- curl -s web-service

# API 서비스 연결 테스트
kubectl exec -n identity-test $TEST_POD -- curl -s api-service

# DB 서비스 연결 테스트 (TCP 연결만 확인)
kubectl exec -n identity-test $TEST_POD -- nc -zv db-service 5432

✅ Identity 기반 정책 적용

이제 각 티어 간의 통신을 제한하는 Identity 기반 정책을 적용합니다:

# tier-identity-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "frontend-policy"  # 프론트엔드 정책 이름
  namespace: identity-test
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      tier: frontend  # tier=frontend 라벨을 가진 Pod에 적용
  egress:  # 아웃바운드 트래픽 규칙
  - toEndpoints:  # 목적지 Pod 선택
    - matchLabels:
        tier: backend  # tier=backend 라벨을 가진 Pod로만 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "80"  # HTTP 포트만 허용
        protocol: TCP  # TCP 프로토콜만 허용
---
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "backend-policy"  # 백엔드 정책 이름
  namespace: identity-test
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      tier: backend  # tier=backend 라벨을 가진 Pod에 적용
  ingress:  # 인바운드 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchLabels:
        tier: frontend  # tier=frontend 라벨을 가진 Pod에서만 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "80"  # HTTP 포트만 허용
        protocol: TCP  # TCP 프로토콜만 허용
  egress:  # 아웃바운드 트래픽 규칙
  - toEndpoints:  # 목적지 Pod 선택
    - matchLabels:
        tier: database  # tier=database 라벨을 가진 Pod로만 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "5432"  # PostgreSQL 포트만 허용
        protocol: TCP  # TCP 프로토콜만 허용
---
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "database-policy"  # 데이터베이스 정책 이름
  namespace: identity-test
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      tier: database  # tier=database 라벨을 가진 Pod에 적용
  ingress:  # 인바운드 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchLabels:
        tier: backend  # tier=backend 라벨을 가진 Pod에서만 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "5432"  # PostgreSQL 포트만 허용
        protocol: TCP  # TCP 프로토콜만 허용

정책을 적용합니다:

kubectl apply -f tier-identity-policy.yaml

✅ 정책 적용 후 테스트

정책 적용 후 연결을 다시 테스트합니다:

# 웹 서비스에서 API 서비스로의 연결 테스트 (허용되어야 함)
WEB_POD=$(kubectl -n identity-test get pod -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl exec -n identity-test $WEB_POD -- curl -s api-service

# API 서비스에서 DB 서비스로의 연결 테스트 (허용되어야 함)
API_POD=$(kubectl -n identity-test get pod -l app=api -o jsonpath='{.items[0].metadata.name}')
kubectl exec -n identity-test $API_POD -- nc -zv db-service 5432

# 웹 서비스에서 DB 서비스로의 직접 연결 테스트 (차단되어야 함)
kubectl exec -n identity-test $WEB_POD -- nc -zv db-service 5432

# 테스트 클라이언트에서 모든 서비스로의 연결 테스트 (모두 차단되어야 함)
kubectl exec -n identity-test $TEST_POD -- curl -s --connect-timeout 5 web-service
kubectl exec -n identity-test $TEST_POD -- curl -s --connect-timeout 5 api-service
kubectl exec -n identity-test $TEST_POD -- nc -zv -w 5 db-service 5432

정책이 올바르게 적용되었다면:

  • 웹 → API 연결은 허용됩니다.
  • API → DB 연결은 허용됩니다.
  • 웹 → DB 직접 연결은 차단됩니다.
  • 테스트 클라이언트에서의 모든 연결은 차단됩니다.

📌 Identity 변경 시나리오 테스트

✅ Pod 재생성 시 Identity 유지 테스트

Pod가 재생성되어도 동일한 라벨을 가지면 동일한 Identity가 유지되는지 확인합니다:

# 현재 API Pod의 Identity 확인
API_POD=$(kubectl -n identity-test get pod -l app=api -o jsonpath='{.items[0].metadata.name}')
kubectl -n kube-system exec $CILIUM_POD -- cilium endpoint list | grep $API_POD

# API Pod 삭제 (Deployment에 의해 자동 재생성됨)
kubectl -n identity-test delete pod $API_POD

# 잠시 대기
sleep 10

# 새로 생성된 API Pod 확인
NEW_API_POD=$(kubectl -n identity-test get pod -l app=api -o jsonpath='{.items[0].metadata.name}')

# 새 Pod의 Identity 확인
kubectl -n kube-system exec $CILIUM_POD -- cilium endpoint list | grep $NEW_API_POD

두 Pod의 Identity 값이 동일해야 합니다. 이는 Pod가 재생성되어도 라벨이 같으면 동일한 Identity가 유지됨을 보여줍니다.

✅ 라벨 변경 시 Identity 변경 테스트

Pod의 라벨을 변경하면 Identity도 변경되는지 확인합니다:

# modified-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: api-service
 namespace: identity-test
spec:
 selector:
   matchLabels:
     app: api
     tier: backend
 replicas: 2
 template:
   metadata:
     labels:
       app: api  # 기존 라벨 유지
       tier: backend  # 기존 라벨 유지
       version: v2  # v1에서 v2로 변경 (Identity 관련 라벨 변경)
   spec:
     containers:
     - name: httpd
       image: httpd:2.4
       ports:
       - containerPort: 80

 

변경된 배포를 적용합니다:

kubectl apply -f modified-deployment.yaml

 

새 Pod의 Identity를 확인합니다:

# 새 API Pod 확인
NEW_API_POD=$(kubectl -n identity-test get pod -l version=v2 -o jsonpath='{.items[0].metadata.name}')

# 새 Pod의 Identity 확인
kubectl -n kube-system exec $CILIUM_POD -- cilium endpoint list | grep $NEW_API_POD

 

version 라벨이 정책에 사용되지 않았기 때문에, Identity는 변경되지 않을 것입니다. 이는 보안 관련 라벨만 Identity 계산에 사용됨을 보여줍니다.

중요한 라벨을 변경하는 경우:

# changed-tier-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-service-test  # 새 배포 이름 (기존 배포와 구분)
  namespace: identity-test
spec:
  selector:
    matchLabels:
      app: api
      tier: middleware  # backend에서 middleware로 변경 (정책에 사용되는 중요 라벨)
  replicas: 1
  template:
    metadata:
      labels:
        app: api  # 기존 라벨 유지
        tier: middleware  # backend에서 middleware로 변경 (정책에 사용되는 중요 라벨)
        version: v1  # 기존 버전으로 복원
    spec:
      containers:
      - name: httpd
        image: httpd:2.4
        ports:
        - containerPort: 80

 

변경된 배포를 적용합니다:

kubectl apply -f changed-tier-deployment.yaml

 

새 Pod의 Identity를 확인하고 연결 테스트를 수행합니다:

# 새 API Pod 확인
MIDDLEWARE_POD=$(kubectl -n identity-test get pod -l tier=middleware -o jsonpath='{.items[0].metadata.name}')

# 새 Pod의 Identity 확인
kubectl -n kube-system exec $CILIUM_POD -- cilium endpoint list | grep $MIDDLEWARE_POD

# 웹 서비스에서 미들웨어 서비스로의 연결 테스트 (차단되어야 함)
kubectl exec -n identity-test $WEB_POD -- curl -s --connect-timeout 5 $MIDDLEWARE_POD

tier 라벨이 backend에서 middleware로 변경되었기 때문에, 새 Pod는 다른 Identity를 갖게 되고, 웹 서비스에서의 연결은 차단됩니다. 이는 정책에서 중요한 라벨이 변경되면 Identity도 변경되어 다른 보안 규칙이 적용됨을 보여줍니다.


📌 Identity 기반 정책의 고급 활용 사례

✅ 서비스 간 종속성 관리

마이크로서비스 아키텍처에서 서비스 간의 복잡한 종속성을 관리하는 정책:

# service-dependency-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "order-service-policy"  # 정책 이름
  namespace: microservices  # 적용될 네임스페이스
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      app: order-service  # 주문 서비스에 적용
  ingress:  # 인바운드 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchLabels:
        app: frontend-gateway  # 프론트엔드 게이트웨이에서의 접근 허용
    - matchLabels:
        app: user-service  # 사용자 서비스에서의 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "8080"  # API 포트
        protocol: TCP  # TCP 프로토콜만 허용
  egress:  # 아웃바운드 트래픽 규칙
  - toEndpoints:  # 목적지 Pod 선택
    - matchLabels:
        app: payment-service  # 결제 서비스 접근 허용
    - matchLabels:
        app: inventory-service  # 재고 서비스 접근 허용
    - matchLabels:
        app: notification-service  # 알림 서비스 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "8080"  # API 포트
        protocol: TCP  # TCP 프로토콜만 허용

이 정책은:

  • order-service는 frontend-gateway와 user-service에서만 요청을 받을 수 있습니다.
  • order-service는 payment-service, inventory-service, notification-service에만 요청을 보낼 수 있습니다.

이렇게 서비스 간 종속성을 명확히 정의하여 불필요한 통신을 차단하고 보안을 강화할 수 있습니다.

✅ 카나리 배포 지원

새 버전을 점진적으로 배포할 때 버전 기반 트래픽 제어:

# canary-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "canary-policy"  # 정책 이름 (카나리 배포용)
  namespace: production  # 적용될 네임스페이스
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      app: backend-service  # 백엔드 서비스 Pod 선택
      version: v2  # 새 버전 서비스에만 적용
  ingress:  # 인바운드 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchLabels:
        app: frontend-service  # 프론트엔드 서비스에서만 접근 허용
        version: v2  # 새 버전 프론트엔드에서만 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "8080"  # API 포트
        protocol: TCP  # TCP 프로토콜만 허용
---
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "stable-policy"  # 정책 이름 (안정 버전용)
  namespace: production  # 적용될 네임스페이스
spec:
  endpointSelector:  # 정책이 적용될 대상 Pod 선택
    matchLabels:
      app: backend-service  # 백엔드 서비스 Pod 선택
      version: v1  # 기존 버전 서비스에만 적용
  ingress:  # 인바운드 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchLabels:
        app: frontend-service  # 프론트엔드 서비스에서만 접근 허용
        version: v1  # 기존 버전 프론트엔드에서만 접근 허용
    toPorts:  # 목적지 포트 지정
    - ports:  # 허용할 포트 목록
      - port: "8080"  # API 포트
        protocol: TCP  # TCP 프로토콜만 허용

이 정책은:

  • v1 프론트엔드 → v1 백엔드
  • v2 프론트엔드 → v2 백엔드 로만 트래픽이 흐르도록 제한하여 버전 간 격리를 제공합니다.

이를 통해 새 버전을 안전하게 테스트하고 점진적으로 트래픽을 이동시킬 수 있습니다.

✅ 멀티 테넌트 환경 격리

여러 테넌트가 공유 클러스터를 사용할 때의 격리 정책:

# tenant-isolation-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "tenant-isolation"  # 정책 이름
  namespace: tenant-a  # tenant-a 네임스페이스에 적용
spec:
  endpointSelector:
    matchLabels: {}  # 네임스페이스 내 모든 Pod에 적용
  ingress:  # 인바운드 트래픽 규칙
  - fromEndpoints:  # 출발지 Pod 선택
    - matchLabels:
        "k8s:io.kubernetes.pod.namespace": tenant-a  # 같은 테넌트 네임스페이스 내에서만 통신 허용
  egress:  # 아웃바운드 트래픽 규칙
  - toEndpoints:  # 목적지 Pod 선택
    - matchLabels:
        "k8s:io.kubernetes.pod.namespace": tenant-a  # 같은 테넌트 네임스페이스 내에서만 통신 허용
  - toEndpoints:  # DNS 서버 접근 허용 (필수 서비스)
    - matchLabels:
        "k8s:io.kubernetes.pod.namespace": kube-system
        "k8s:k8s-app": kube-dns
    toPorts:  # DNS 포트 지정
    - ports:
      - port: "53"
        protocol: UDP
  - toEntities:  # 쿠버네티스 API 서버 접근 허용
    - kube-apiserver

이 정책은 각 테넌트 네임스페이스를 격리하여, 다른 테넌트와의 통신을 차단하면서도 필수 서비스에는 접근할 수 있도록 합니다.


📌 실무 보안 강화 팁

✅ 최소 권한 원칙 적용

네트워크 정책을 설계할 때 최소 권한 원칙을 적용하세요:

  1. 기본 거부 정책 시작: 모든 트래픽을 차단하는 기본 정책부터 시작하세요.
  2. 필요한 최소 통신만 허용: 애플리케이션 작동에 필요한 최소한의 트래픽만 명시적으로 허용하세요.
  3. 세분화된 권한: 광범위한 허용보다 구체적인 규칙을 선호하세요.

✅ 레이블 전략 수립

효과적인 Identity 기반 정책을 위한 레이블 전략:

  1. 일관된 레이블 체계: 클러스터 전체에 일관된 레이블 명명 규칙을 적용하세요.
  2. 의미 있는 레이블: 워크로드의 목적과 기능을 명확히 표현하는 레이블을 사용하세요.
  3. 보안 관련 레이블 분리: 보안 정책에 사용될 레이블을 명확히 식별하세요.
  4. 버전 레이블 활용: 애플리케이션 버전을 표시하는 레이블을 포함하세요.

✅ 정책 관리 모범 사례

대규모 클러스터에서 정책 관리를 위한 팁:

  1. GitOps 활용: 정책을 코드로 관리하고 Git 저장소에서 버전 관리하세요.
  2. 정책 템플릿: 공통 패턴에 대한 템플릿을 만들어 재사용하세요.
  3. 정책 테스트: 프로덕션 환경에 적용하기 전에 정책을 테스트하세요.
  4. 점진적 적용: 대규모 변경보다 작은 변경을 점진적으로 적용하세요.
  5. 모니터링 및 감사: Hubble을 사용하여 정책 효과를 모니터링하고 보안 이벤트를 기록하세요.

✅ 보안 감사 및 모니터링

Identity 기반 정책의 효과를 지속적으로 검증하세요:

  1. 트래픽 패턴 분석: Hubble을 사용하여 실제 트래픽 패턴을 분석하세요.
  2. 거부된 연결 모니터링: 차단된 연결을 모니터링하여 정책 위반 시도를 감지하세요.
  3. 정기적인 감사: 정책의 적절성을 정기적으로 검토하고 업데이트하세요.
  4. 보안 이벤트 알림: 비정상적인 트래픽 패턴에 대한 알림을 설정하세요.

📌 Summary

이번 글에서는 Cilium의 Identity 기반 정책과 보안 강화 방법에 대해 살펴보았습니다:

Cilium Identity의 핵심 개념:

  • Pod의 라벨을 기반으로 생성되는 고유 식별자
  • IP 주소가 아닌 워크로드의 특성과 역할에 기반한 정책
  • 동적 환경에서도 일관된 보안 정책 적용 가능

Identity 생성 및 관리 방식:

  • 보안 관련 라벨 필터링 및 해시 계산
  • eBPF 맵을 통한 효율적인 저장 및 조회
  • Endpoint와 Identity 간의 매핑 관리

Identity 기반 정책 구성:

  • 기본 라벨 매칭 정책
  • 복합 라벨 및 연산자를 활용한 고급 정책
  • 예약된 Identity(host, world 등) 활용

실무 활용 사례:

  • 서비스 간 종속성 관리
  • 카나리 배포 지원
  • 멀티 테넌트 환경 격리

보안 강화 팁:

  • 최소 권한 원칙 적용
  • 효과적인 레이블 전략 수립
  • 정책 관리 모범 사례
  • 지속적인 보안 감사 및 모니터링

Cilium의 Identity 기반 접근 제어는 기존 IP 기반 접근 방식의 한계를 극복하고, 클라우드 네이티브 환경에서 더욱 강력하고 유연한 보안을 제공합니다. 이를 효과적으로 활용하면 동적으로 변화하는 환경에서도 일관된 보안 정책을 유지할 수 있습니다.


 

728x90