Layer 3 정책

Layer 3 정책 (Layer 3 Policies)

어떤 엔드포인트가 서로 통신할 수 있는지에 대한 기본 연결 규칙을 수립하는 Layer 3 정책을 설명하는 문서예요. Endpoints, Services, Entities, Node, IP/CIDR, DNS 기반 방법을 모두 다뤄요.

출처: Layer 3 Policies

본문

Layer 3 정책은 어떤 엔드포인트가 서로 통신할 수 있는지에 대한 기본 연결 규칙을 수립해요. Layer 3 정책은 다음 방법으로 지정할 수 있어요.

  • Endpoints 기반: 두 엔드포인트가 모두 Cilium이 관리하고 라벨이 할당된 경우의 관계를 설명하는 데 사용돼요. 이 방법의 장점은 IP 주소가 정책에 인코딩되지 않아 정책이 주소 지정과 완전히 분리된다는 거예요.
  • Services 기반: Labels와 CIDR 사이의 중간 형태이며 오케스트레이션 시스템의 서비스 개념을 활용해요. 좋은 예로, 서비스의 모든 백엔드 IP 주소를 자동으로 유지하는 Kubernetes의 Service endpoints 개념이 있어요. 이를 통해 목적지 엔드포인트가 Cilium에 의해 제어되지 않아도 IP 주소를 정책에 하드코딩하는 것을 피할 수 있어요.
  • Entities 기반: Entities는 IP 주소를 알 필요 없이 분류할 수 있는 원격 피어를 설명하는 데 사용돼요. 여기에는 엔드포인트를 제공하는 로컬 호스트로의 연결 또는 클러스터 외부로의 모든 연결이 포함돼요.
  • Node 기반: remote-node entity의 확장이에요. 선택적으로 노드는 특정 노드만 접근을 허용/차단하는 데 사용할 수 있는 고유한 신원을 가질 수 있어요.
  • IP/CIDR 기반: 원격 피어가 엔드포인트가 아닌 경우 외부 서비스로/로부터의 관계를 설명하는 데 사용돼요. 이는 IP 주소나 서브넷을 정책에 하드코딩해야 해요. 이 구조는 안정적인 IP 또는 서브넷 할당을 요구하므로 최후의 수단으로 사용해야 해요.
  • DNS 기반: DNS 조회를 통해 IP로 변환된 DNS 이름을 사용해 원격의 비클러스터 피어를 선택해요. 위 IP/CIDR 기반 규칙의 모든 제한을 공유해요. DNS 정보는 별도의 정책 규칙으로 DNS 트래픽을 DNS Proxy를 통해 라우팅해 획득해요. DNS TTL이 존중돼요.

Endpoints 기반 (Endpoints based)

Endpoints 기반 L3 정책은 Cilium이 관리하는 클러스터 안의 엔드포인트 사이의 규칙을 수립하는 데 사용돼요. Endpoints 기반 L3 정책은 규칙 안에서 Endpoint Selector를 사용해 어떤 트래픽을 받을 수 있는지(ingress), 혹은 보낼 수 있는지(egress)를 선택해 정의돼요. 빈 Endpoint Selector는 모든 트래픽을 허용해요. 아래 예제가 더 자세히 보여줘요.

참고: Kubernetes: Kubernetes 환경에서 Endpoint Selector가 네임스페이스와 관련해 어떻게 적용되는지에 대한 자세한 내용은 Namespaces 섹션을 참고하세요.

Ingress

endpointSelector 필드의 Endpoint Selector로 목적지 엔드포인트를 선택하는 ingress 규칙이 하나 이상 존재하면, 엔드포인트는 다른 엔드포인트로부터 트래픽을 받을 수 있어요. 선택된 엔드포인트의 ingress에서 트래픽을 제한하려면, 규칙이 fromEndpoints 필드의 Endpoint Selector로 출처 엔드포인트를 선택해요.

간단한 Ingress Allow (Simple Ingress Allow)

다음 예제는 role=frontend 라벨의 엔드포인트에서 role=backend 라벨의 엔드포인트로의 통신을 허용하는 간단한 ingress 규칙을 사용하는 방법을 보여줘요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l3-rule"
spec:
  endpointSelector:
    matchLabels:
      role: backend
  ingress:
  - fromEndpoints:
    - matchLabels:
        role: frontend

모든 엔드포인트 Ingress Allow (Ingress Allow All Endpoints)

빈 Endpoint Selector는 모든 엔드포인트를 선택해요. 따라서 엔드포인트에 모든 ingress 트래픽을 허용하는 규칙은 다음과 같이 작성할 수 있어요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "allow-all-to-victim"
spec:
  endpointSelector:
    matchLabels:
      role: victim
  ingress:
  - fromEndpoints:
    - {}

위 예제가 엔드포인트에 모든 ingress 트래픽을 허용한다고 해서, 모든 엔드포인트가 자신의 정책에 따라 이 엔드포인트에 트래픽을 보낼 수 있다는 뜻은 아니라는 점에 주의하세요. 즉, 정책은 양쪽(송신자와 수신자) 모두에 구성되어야 해요.

Egress

endpointSelector 필드의 Endpoint Selector로 목적지 엔드포인트를 선택하는 egress 규칙이 하나 이상 존재하면, 엔드포인트는 다른 엔드포인트에 트래픽을 보낼 수 있어요. 선택된 엔드포인트의 egress에서 트래픽을 제한하려면, 규칙이 toEndpoints 필드의 Endpoint Selector로 목적지 엔드포인트를 선택해요.

간단한 Egress Allow (Simple Egress Allow)

다음 예제는 role=frontend 라벨의 엔드포인트에서 role=backend 라벨의 엔드포인트로의 통신을 허용하는 간단한 egress 규칙을 사용하는 방법을 보여줘요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l3-egress-rule"
spec:
  endpointSelector:
    matchLabels:
      role: frontend
  egress:
  - toEndpoints:
    - matchLabels:
        role: backend

모든 엔드포인트 Egress Allow (Egress Allow All Endpoints)

빈 Endpoint Selector는 CiliumNetworkPolicy 네임스페이스(기본 default)에 기반해 엔드포인트로부터의 모든 egress 엔드포인트를 선택해요. 다음 규칙은 role=frontend 라벨의 엔드포인트에서 같은 네임스페이스의 다른 모든 엔드포인트로의 모든 egress 트래픽을 허용해요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "allow-all-from-frontend"
spec:
  endpointSelector:
    matchLabels:
      role: frontend
  egress:
  - toEndpoints:
    - {}

위 예제가 엔드포인트로부터의 모든 egress 트래픽을 허용한다고 해서, egress 트래픽의 수신자가 그 트래픽을 거부하는 ingress 규칙을 가질 수 없다는 뜻은 아니에요. 즉, 정책은 양쪽(송신자와 수신자) 모두에 구성되어야 해요.

간단한 Egress Deny (Simple Egress Deny)

다음 예제는 role=frontend 라벨의 엔드포인트에서 role=backend 라벨의 엔드포인트로의 통신을 거부하는 방법을 보여줘요. egressDeny 규칙이 일치하면, 정책이 그 외에는 허용하는 egress 규칙을 포함하더라도 egress 트래픽은 거부돼요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "deny-egress-example"
spec:
  endpointSelector:
    matchLabels:
      role: frontend
  egress:
  - toEntities:
    - all
  egressDeny:
  - toEndpoints:
    - matchLabels:
        role: backend

Ingress/Egress 기본 Deny (Ingress/Egress Default Deny)

규칙이 엔드포인트를 선택하고 해당 ingress 또는 egress 규칙 섹션을 포함하면, 엔드포인트는 ingress 또는 egress에서 기본 deny 모드로 들어갈 수 있어요.

참고: 엔드포인트를 선택하는 어떤 규칙도 이 효과를 가져요. 이 예제는 다른 피어를 동시에 화이트리스트하지 않고 엔드포인트를 기본 deny 모드로 만드는 방법을 보여줘요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "deny-all-egress"
spec:
  endpointSelector:
    matchLabels:
      role: restricted
  egress:
  - {}

추가 라벨 요구사항 (Additional Label Requirements)

경고: fromRequires와 toRequires 필드는 Cilium 1.17.x부터 폐기됐어요. Cilium 1.19부터 제거됐어요.

정책을 정의할 때 관심사 분리(separation of concern) 원칙을 적용해야 하는 경우가 자주 있어요. 이를 위해 어떤 연결이든 발생하기 위한 기본 요구사항을 수립하는 추가 구조가 존재해요.

이를 위해 fromRequires 필드를 사용해 어떤 fromEndpoints 관계의 기초가 되는 라벨 요구사항을 수립할 수 있어요. fromRequires는 선택된 엔드포인트가 도달 가능하려면 충족되어야 하는 추가 제약의 목록이에요. 이러한 추가 제약은 그 자체로 접근 권한을 부여하지 않으므로, 트래픽을 허용하려면 fromEndpoints와 일치하는 규칙도 있어야 해요. egress 정책에도 toRequires와 toEndpoints로 동일하게 적용돼요.

이 규칙의 목적은 env=prod의 어떤 엔드포인트든 출처 엔드포인트도 env=prod 라벨을 가질 때만 접근할 수 있다는 것 같은 기본 요구사항을 수립하도록 하는 거예요.

경고: toRequires와 fromRequires는 같은 엔드포인트 선택자를 공유하는 모든 규칙에 적용되며 다른 egress·ingress 규칙으로 제한되지 않아요. 결과적으로 toRequires와 fromRequires는 자신의 엔드포인트 선택자에 적용되는 모든 ingress·egress 트래픽을 제한해요. toRequires와 fromRequires가 엔드포인트 선택자에 적용되는 모든 ingress·egress 트래픽을 제한한다는 사실의 중요한 의미는, 다른 egress·ingress 규칙(fromEndpoints, fromPorts, toEntities, toServices 등)이 toRequires나 fromRequires 필드의 범위를 제한하지 않는다는 거예요. 다른 ingress·egress 규칙을 toRequires나 fromRequires와 짝지으면 유효한 정책이 되지만, toRequires와 fromRequires에 설정된 요구사항은 다른 규칙이 달리 허용하는 것과 무관하게 계속 적용돼요.

이 예제는 env=prod 라벨의 모든 엔드포인트가 출처 엔드포인트도 env=prod 라벨을 가질 때만 접근할 수 있도록 요구하는 방법을 보여줘요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "requires-rule"
specs:
  - description: "For endpoints with env=prod, only allow if source also has label env=prod"
    endpointSelector:
      matchLabels:
        env: prod
    ingress:
    - fromRequires:
      - matchLabels:
          env: prod

이 fromRequires 규칙은 그 자체로는 아무것도 허용하지 않으며, 트래픽을 허용하려면 다른 규칙과 결합해야 해요. 예를 들어 아래 예제 정책과 결합하면 env=prod 라벨의 엔드포인트는 env=prod와 role=frontend 라벨을 모두 가진 엔드포인트에서 접근할 수 있게 돼요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l3-rule"
specs:
  - description: "For endpoints with env=prod, allow if source also has label role=frontend"
    endpointSelector:
      matchLabels:
        env: prod
    ingress:
    - fromEndpoints:
      - matchLabels:
          role: frontend

Services 기반 (Services based)

Egress 규칙의 toServices 문을 통해 엔드포인트에서 클러스터에서 실행 중인 서비스로의 트래픽을 허용할 수 있어요. 정책은 이름이나 라벨 선택자로 Kubernetes Services를 참조할 수 있어요. 이 기능은 발견된 서비스의 라벨 선택자를 정책 안의 엔드포인트 선택자로 사용해요.

참고: 선택자가 없는 Services는 다르게 처리돼요. 서비스의 EndpointSlices에 있는 IP가 CIDR 선택자로 변환돼요. CIDR 선택자는 파드를 선택할 수 없으며, 그 제한이 여기에도 적용돼요. 특별한 Kubernetes Service인 default/kubernetes는 라벨 선택자를 사용하지 않아요. toServices 기반 정책으로 Kubernetes API 서버에 접근 권한을 부여하는 것은 권장되지 않아요. 대신 kube-apiserver entity를 사용하세요.

이 예제는 id=app2 라벨의 모든 엔드포인트가 default Kubernetes 네임스페이스의 Kubernetes Service myservice의 모든 엔드포인트, 그리고 another-namespace 네임스페이스에서 env=staging 라벨을 가진 모든 서비스와 통신하도록 허용하는 방법을 보여줘요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "service-rule"
spec:
  endpointSelector:
    matchLabels:
      id: app2
  egress:
  - toServices:
    # Services may be referenced by namespace + name
    - k8sService:
        serviceName: myservice
        namespace: default
    # Services may be referenced by namespace + label selector
    - k8sServiceSelector:
        selector:
          matchLabels:
            env: staging
        namespace: another-namespace

Entities 기반 (Entities based)

fromEntities는 선택된 엔드포인트에 접근할 수 있는 entity를 설명하는 데 사용돼요. toEntities는 선택된 엔드포인트가 접근할 수 있는 entity를 설명하는 데 사용돼요.

다음 entity가 정의돼 있어요.

  • host: host entity는 로컬 호스트를 포함해요. 로컬 호스트에서 호스트 네트워킹 모드로 실행되는 모든 컨테이너도 포함돼요.
  • remote-node: 연결된 클러스터 중 로컬 호스트가 아닌 어떤 노드든 포함해요. 원격 노드에서 호스트 네트워킹 모드로 실행되는 모든 컨테이너도 포함돼요.
  • kube-apiserver: kube-apiserver entity는 Kubernetes 클러스터의 kube-apiserver를 나타내요. 이 entity는 클러스터 안과 밖의 kube-apiserver 두 배포 형태를 모두 나타내요.
  • ingress: ingress entity는 ingress L7 트래픽을 처리하는 Cilium Envoy 인스턴스를 나타내요. ingress 엔드포인트를 사용할 때 같은 클러스터 안의 파드 간 트래픽(헤어피닝이라고도 함)에도 적용된다는 점에 유의하세요.
  • cluster: cluster는 로컬 클러스터 안의 모든 네트워크 엔드포인트의 논리적 그룹이에요. 여기에는 로컬 클러스터의 모든 Cilium 관리 엔드포인트, 로컬 클러스터의 비관리 엔드포인트, 그리고 host, remote-node, init, ingress, health, kube-apiserver entity가 포함돼요. 또한 clustermesh 시나리오의 모든 원격 노드도 포함돼요.
  • cluster-mesh: cluster-mesh entity는 메시 클러스터의 모든 엔드포인트와 cluster entity가 선택하는 모든 것을 선택해요.
  • init: init entity는 보안 신원이 아직 해결되지 않은 부트스트랩 단계의 모든 엔드포인트를 포함해요. 이는 보통 비Kubernetes 환경에서만 관찰돼요. 자세한 내용은 Endpoint Lifecycle 섹션을 참고하세요.
  • health: health entity는 클러스터 연결 상태를 확인하는 데 사용되는 health 엔드포인트를 나타내요. Cilium이 관리하는 각 노드는 health 엔드포인트를 호스팅해요. health check에 대한 자세한 내용은 Checking cluster connectivity health를 참고하세요.
  • unmanaged: unmanaged entity는 Cilium이 관리하지 않는 엔드포인트를 나타내요. 비관리 엔드포인트는 클러스터의 일부로 간주되며 cluster entity에 포함돼요.
  • world: world entity는 클러스터 외부의 모든 엔드포인트에 해당해요. world로 허용하는 것은 CIDR 0.0.0.0/0으로 허용하는 것과 동일해요. world로/에서 허용하는 것의 대안은 세밀한 DNS 또는 CIDR 기반 정책을 정의하는 거예요.
  • all: all entity는 모든 알려진 클러스터와 world의 결합을 나타내며 모든 통신을 화이트리스트해요.

참고: kube-apiserver entity는 Azure AKS, GCP GKE 같은 일부 Kubernetes 배포판에서 ingress 트래픽에 동작하지 않을 수 있어요. 이는 ingress 컨트롤 플레인 트래픽이 워커 노드를 통해 터널링되며 원래 출처 IP를 보존하지 않기 때문이에요. 대신 더 넓은 fromEntities: cluster 규칙을 사용할 수 있을 거예요. 하지만 toEntities: kube-apiserver로 egress 트래픽을 제한하는 것은 이 Kubernetes 배포판에서 동작할 것으로 예상돼요.

kube-apiserver로/로부터 접근 (Access to/from kube-apiserver)

env=dev 라벨의 모든 엔드포인트가 kube-apiserver에 접근하도록 허용해요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "dev-to-kube-apiserver"
spec:
  endpointSelector:
    matchLabels:
      env: dev
  egress:
    - toEntities:
      - kube-apiserver

로컬 호스트로/로부터 접근 (Access to/from local host)

env=dev 라벨의 모든 엔드포인트가 해당 엔드포인트를 제공하는 호스트에 접근하도록 허용해요.

참고: Kubernetes는 모든 로컬 엔드포인트의 로컬 호스트로부터의 모든 통신을 자동으로 허용해요. --allow-localhost=policy 옵션으로 에이전트를 실행하면 이 동작을 비활성화해 정책으로 제어할 수 있어요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "dev-to-host"
spec:
  endpointSelector:
    matchLabels:
      env: dev
  egress:
    - toEntities:
      - host

클러스터(또는 clustermesh)의 모든 노드로/로부터 접근 (Access to/from all nodes in the cluster (or clustermesh))

env=dev 라벨의 모든 엔드포인트가 Cilium이 실행되는 클러스터의 어떤 호스트로부터든 트래픽을 받도록 허용해요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "to-dev-from-nodes-in-cluster"
spec:
  endpointSelector:
    matchLabels:
      env: dev
  ingress:
    - fromEntities:
      - host
      - remote-node

클러스터 외부로/로부터 접근 (Access to/from outside cluster)

이 예제는 클러스터 외부에서 role=public 라벨의 모든 엔드포인트로의 접근을 활성화하는 방법을 보여줘요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "from-world-to-role-public"
spec:
  endpointSelector:
    matchLabels:
      role: public
  ingress:
    - fromEntities:
      - world

Node 기반 (Node based)

참고: 아래의 fromNodes/toNodes 필드 예제는 enable-node-selector-labels 플래그가 true로 설정될 때만(또는 그에 해당하는 Helm 값 nodeSelectorLabels: true) 적용돼요.

--enable-node-selector-labels=true를 지정하면 각 cilium-agent가 다른 모든 노드에 대해 서로 다른 로컬 보안 신원을 할당해요. 하지만 로컬 범위 신원 대신 remote-node 범위 신원 범위를 사용해요. 기본적으로 Node 객체가 가진 모든 라벨이 고려되며, 이로 인해 각 remote-node에 대해 고유한 신원이 할당될 수 있어요. 이러한 경우 --node-labels 플래그로 보안 관련 라벨만 필터링할 수도 있어요.

이 예제는 env=prod 라벨의 모든 엔드포인트가 클러스터(또는 clustermesh)의 컨트롤 플레인(node-role.kubernetes.io/control-plane="" 라벨) 노드로부터만 트래픽을 받도록 허용하는 방법을 보여줘요. 기본적으로 정책은 명시적으로 지정하지 않으면 Cluster Mesh 환경의 모든 클러스터의 노드를 자동으로 선택한다는 점에 유의하세요. 노드 선택을 기본적으로 로컬 클러스터로 제한하려면 ConfigMap 옵션 policy-default-local-cluster 또는 Helm 값 clustermesh.policyDefaultLocalCluster로 --policy-default-local-cluster 옵션을 활성화할 수 있어요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "to-prod-from-control-plane-nodes"
spec:
  endpointSelector:
    matchLabels:
      env: prod
  ingress:
    - fromNodes:
        - matchLabels:
            node-role.kubernetes.io/control-plane: ""

IP/CIDR 기반 (IP/CIDR based)

CIDR 정책은 Cilium이 관리하지 않아 라벨이 없는 엔드포인트로/로부터의 정책을 정의하는 데 사용돼요. 이들은 보통 특정 서브넷에서 실행되는 외부 서비스, VM 또는 금속(metal) 머신이에요. CIDR 정책은 외부 서비스에 대한 접근을 제한하는 데도 사용할 수 있어요. 예를 들어 특정 IP 범위로의 외부 접근을 제한할 때요. CIDR 정책은 ingress나 egress에 적용할 수 있어요.

CIDR 규칙은 Cilium이 출처나 목적지를 엔드포인트 라벨에서 파생된 신원(즉 Special Identities)으로 매핑할 수 없을 때 적용돼요. 예를 들어 CIDR 규칙은 연결의 한쪽이 다음인 트래픽에 적용돼요.

  • 클러스터 외부의 네트워크 엔드포인트
  • 파드가 실행되는 호스트 네트워크 네임스페이스
  • 클러스터 프리픽스 안에 있지만 IP 네트워킹이 Cilium에서 제공되지 않는 경우
  • (선택) 클러스터 안의 노드 IP

반대로 CIDR 규칙은 연결의 양쪽이 모두 Cilium이 관리하거나 클러스터의 노드에 속한 IP(호스트 네트워킹 파드 포함)를 사용하는 트래픽에는 적용되지 않아요. 이 트래픽은 위에서 설명한 것처럼 labels, services 또는 entities 기반 정책으로 허용될 수 있어요.

Ingress

  • fromCIDR: endpointSelector가 선택한 모든 엔드포인트에 통신할 수 있는 출처 프리픽스/CIDR 목록이에요.
  • fromCIDRSet: endpointSelector가 선택한 모든 엔드포인트에 통신할 수 있는 출처 프리픽스/CIDR 목록과, 각 출처 프리픽스/CIDR의 서브넷으로서 통신이 허용되지 않는 선택적 프리픽스/CIDR 목록이에요. fromCIDRSet은 CiliumCIDRGroup을 통해 프리픽스/CIDR을 간접적으로 참조할 수도 있어요.

Egress

  • toCIDR: endpointSelector가 선택한 엔드포인트가 통신할 수 있는 목적지 프리픽스/CIDR 목록이에요. fromEndpoints가 선택한 엔드포인트는 각 목적지 엔드포인트에 자동으로 응답할 수 있다는 점을 유의하세요.
  • toCIDRSet: endpointSelector가 선택한 엔드포인트가 통신할 수 있는 목적지 프리픽스/CIDR 목록과, 각 출처 프리픽스/CIDR의 서브넷으로서 통신이 허용되지 않는 선택적 프리픽스/CIDR 목록이에요. toCIDRSet은 CiliumCIDRGroup을 통해 프리픽스/CIDR을 간접적으로 참조할 수도 있어요.

외부 CIDR 블록으로 허용 (Allow to external CIDR block)

이 예제는 app=myService 라벨의 모든 엔드포인트가 외부 IP 20.1.1.1과 CIDR 프리픽스 10.0.0.0/8에 통신하도록 허용하지만, CIDR 프리픽스 10.96.0.0/12는 허용하지 않는 방법을 보여줘요.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "cidr-rule"
spec:
  endpointSelector:
    matchLabels:
      app: myService
  egress:
  - toCIDR:
    - 20.1.1.1/32
  - toCIDRSet:
    - cidr: 10.0.0.0/8
      except:
      - 10.96.0.0/12

확장성 (Scalability)

많은 수의 서로 다른 CIDR을 선택하는 정책은 에이전트가 많은 수의 보안 신원을 할당하게 할 수 있어요. 이 시나리오에서는 CiliumCIDRGroup을 사용해 신원 사용을 줄이세요.

CIDR / ipBlock으로 파드나 노드 선택 (Selecting pods or nodes with CIDR / ipBlock)

참고: 이것은 베타 기능이에요. 문제가 발생하면 피드백을 주고 GitHub issue를 제출해 주세요.

기본적으로 CIDR 기반 선택자는 클러스터 내 엔터티(파드나 노드)와 일치하지 않아요. 선택적으로 CIDR/ipBlock으로 파드나 노드를 선택하도록 정책 엔진에 지시할 수 있어요. 이를 위해 --policy-cidr-match-mode=pods 또는 --policy-cidr-match-mode=nodes(또는 그에 해당하는 Helm 값 policyCIDRMatchMode: pods 또는 policyCIDRMatchMode: nodes)로 Cilium을 구성해야 해요.

주의: 대부분의 배포에서는 --policy-cidr-match-mode를 비활성화(기본값)한 채 두는 것이 권장돼요. --policy-cidr-match-mode=pods를 활성화하면 CIDR 선택자와 일치하는 모든 파드에 대해 추가 보안 신원을 할당해요. 파드 수가 많거나 파드 변동이 크거나 CIDR 규칙 집합이 광범위한 환경에서는 신원 소비가 크게 늘어나 Cilium 보안 신원이 고갈될 위험이 있어요. CIDR 규칙이 클러스터 내 파드 IP와 일치해야 하는 경우에만 이 설정을 활성화·수정하고, 클러스터의 보안 신원 할당 한도를 이해하며, 신원 사용을 모니터링하고 필요하면 되돌릴 준비를 하세요.

--policy-cidr-match-mode=nodes를 지정하면 모든 에이전트가 다른 모든 노드에 대해 별개의 로컬 보안 신원을 할당해요. 이는 메모리 사용을 약간 늘리는데, 클러스터의 노드 1000개마다 약 1MB 정도예요. 이는 특히 셀프 호스팅 클러스터, 즉 apiserver가 클러스터 내 노드에 호스팅되는 클러스터와 관련돼요. CIDR 기반 선택자는 기본적으로 노드를 무시하므로, 일반적으로 CiliumNetworkPolicy의 일부로 kube-apiserver entity를 사용해야 해요. --policy-cidr-match-mode=nodes를 설정하면 KubernetesNetworkPolicy에서 ipBlock 피어로 apiserver를 선택할 수 있게 돼요.

DNS 기반 (DNS based)

DNS 정책은 Cilium이 관리하지 않지만 DNS로 조회 가능한 도메인 이름을 가진 엔드포인트에 대한 Layer 3 정책을 정의하는 데 사용돼요. DNS 응답에 제공된 IP 주소는 CIDR 기반 정책의 IP와 유사한 방식으로 Cilium이 허용해요. 이는 원격 IP가 변경되거나 사전에 알 수 없거나 DNS가 더 편리한 경우의 대안이에요. DNS 요청 자체에 정책을 시행하려면 Layer 7 Policies를 참고하세요.

참고: 도메인 이름을 IP 주소와 연결하기 위해 Cilium은 DNS Proxy를 사용해 엔드포인트별로 DNS 응답을 가로채요. 이를 위해서는 Cilium이 --enable-l7-proxy=true로 구성되고 DNS 요청을 허용하는 L7 정책(rules.dns YAML 블록)이 있어야 해요. 자세한 내용은 Obtaining DNS Data for use by toFQDNs을 참고하세요.

모든 toFQDNs 규칙에 대해 L3 CIDR 기반 규칙이 생성되며 같은 엔드포인트에 적용돼요. IP 정보는 matchName 또는 matchPattern 규칙에 의해 삽입되도록 선택되며, 해당 노드에서 Cilium이 본 모든 DNS 응답에서 수집돼요. 단일 egress 규칙에 여러 선택자를 포함할 수 있어요.

참고: DNS Proxy는 각 Cilium 에이전트에 제공돼요. 결과적으로 정책이 대상으로 하는 DNS 요청은 Cilium 에이전트 파드의 가용성에 의존해요. 여기에는 DNS 정책(Layer 7 Protocol Visibility)이 포함돼요.

toFQDNs egress 규칙은 toEndpoints(Endpoints Based 아래)와 toCIDRs(CIDR Based 아래) 같은 다른 L3 규칙을 포함할 수 없어요. toPorts(Layer 4 Policies 참고) 같은 L4/L7 규칙을 포함할 수 있으며, 선택적으로 HTTP 섹션(Layer 7 Policies 참고)을 포함할 수 있어요.

참고: DNS 기반 규칙은 외부 연결을 위한 것이며 CIDR 기반 규칙과 유사하게 동작해요. 클러스터 내부 트래픽은 Services based 및 Endpoints based를 참고하세요.

허용할 IP는 다음으로 선택돼요.

  • toFQDNs.matchName: matchName과 정확히 일치하는 도메인의 IP를 삽입해요. 여러 개의 서로 다른 이름을 별도의 matchName 항목에 포함할 수 있으며, 어떤 matchName과 일치하는 도메인의 IP가 삽입돼요.
  • toFQDNs.matchPattern: matchPattern의 패턴과 일치하는 도메인의 IP를 삽입해요(와일드카드 고려). 패턴은 도메인 이름에 허용되는 리터럴 문자(a-z, 0-9, ., -)로 구성돼요. *는 여러 편의 동작이 있는 와일드카드로 허용돼요.
    • 도메인 안의 *는 . 구분자를 제외하고 0개 이상의 유효한 DNS 문자를 허용해요. *.cilium.io는 sub.cilium.io와는 일치하지만 cilium.io나 sub.sub.cilium.io와는 일치하지 않아요. part*ial.com은 partial.com과 part-extra-ial.com과 일치해요.
    • *만 단독으로는 모든 이름과 일치하고, 모든 캐시된 DNS IP를 이 규칙에 삽입해요.
    • **.는 프리픽스의 모든 연속 하위 도메인을 와일드카드화하는 DNS 매치 패턴에서 지원되는 특수 프리픽스예요. 예를 들어 **.cilium.io 패턴은 app.cilium.io와 test.app.cilium.io와 모두 일치하지만 cilium.io와는 일치하지 않아요.

아래 예제는 DNS 서비스로의 53 포트 모든 DNS 트래픽을 허용하고 DNS Proxy를 통해 가로챈답니다. Kubernetes Service 뒤의 DNS 애플리케이션에 비표준 DNS 포트를 사용한다면, 포트가 백엔드 포트와 일치해야 해요. 애플리케이션이 my-remote-service.com에 요청하면, Cilium은 IP 주소를 배우고 toFQDNs.matchName 규칙 아래의 이름 일치로 인해 트래픽을 허용해요.

예제 (Example)

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "to-fqdn"
spec:
  endpointSelector:
    matchLabels:
      app: test-app
  egress:
    - toEndpoints:
      - matchLabels:
          "k8s:io.kubernetes.pod.namespace": kube-system
          "k8s:k8s-app": kube-dns
      toPorts:
        - ports:
           - port: "53"
             protocol: ANY
          rules:
            dns:
              - matchPattern: "*"
    - toFQDNs:
        - matchName: "my-remote-service.com"

단기 연결 및 FQDN/엔드포인트당 최대 IP 관리 (Managing Short-Lived Connections & Maximum IPs per FQDN/endpoint)

많은 단기 연결은 FQDN에 매핑되는 IP 수를 빠르게 늘릴 수 있어요. 특정 FQDN에 매핑되는 IP 주소 수를 제한하기 위해, 각 FQDN에는 유지될 IP의 엔드포인트당 최대 용량이 있어요(기본값: 50). 이 한도를 초과하면 가장 오래된 IP 항목이 캐시에서 자동으로 만료돼요. 이 용량은 --tofqdns-endpoint-max-ip-per-hostname 옵션으로 변경할 수 있어요.

위의 장기 연결과 마찬가지로, 활성 연결은 종료될 때까지 만료되지 않아요. 같은 파드에서 장기·단기 연결을 혼합하는 것은 안전해요. 위에서 설명한 한도를 초과하는 IP는 연결이 사용하지 않는 경우에만 제거돼요.

더 알아보기 (Learn more)