참조

참조 (Reference)

Cilium Ingress의 동작 방식에 대한 참조 문서예요. 다른 Ingress 컨트롤러와의 차이, CiliumNetworkPolicy와의 관계, 소스 IP 가시성, TLS 패스스루에 대해 설명해요.

출처: Reference

본문

Cilium Ingress와 Gateway API가 다른 Ingress 컨트롤러와 다른 점 (How Cilium Ingress and Gateway API differ from other Ingress controllers)

Cilium의 Ingress 및 Gateway API 지원과 다른 Ingress 컨트롤러 사이의 가장 큰 차이점 중 하나는 구현이 CNI와 얼마나 밀접하게 연결돼 있는지예요. Cilium에서는 Ingress와 Gateway API가 네트워킹 스택의 일부이므로, 다른 Ingress나 Gateway API 컨트롤러와는 다르게 동작해요 (심지어 Cilium 클러스터에서 실행되는 다른 Ingress/Gateway API 컨트롤러라도요).

다른 Ingress/Gateway API 컨트롤러는 일반적으로 클러스터에 Deployment나 DaemonSet으로 설치되고, Loadbalancer Service 등으로 노출돼요 (물론 Cilium이 이를 활성화할 수도 있어요).

Cilium의 Ingress 및 Gateway API 구성은 Loadbalancer나 NodePort 서비스로 노출되거나, 선택적으로 호스트 네트워크에서도 노출될 수 있어요. 하지만 이 모든 경우에 트래픽이 Service의 포트에 도착하면 eBPF 코드가 트래픽을 가로채서 (TPROXY 커널 기능을 사용해) Envoy로 투명하게 전달해요.

이것은 클라이언트 IP 가시성 같은 것에 영향을 주는데, 이는 Cilium의 Ingress/Gateway API 지원에서 다른 Ingress 컨트롤러와 다르게 동작해요.

또한 Cilium의 Network Policy 엔진이 Ingress로 향하는 트래픽과 Ingress에서 나오는 트래픽에 CiliumNetworkPolicy를 적용할 수 있게 해줘요.

Cilium의 ingress 구성과 CiliumNetworkPolicy (Cilium's ingress config and CiliumNetworkPolicy)

Cilium을 통해 백엔드 서비스로 향하는 Ingress 및 Gateway API 트래픽은 노드별 Envoy 프록시를 통과해요.

노드별 Envoy 프록시에는 eBPF 정책 엔진과 상호작용하고 트래픽에 대한 정책 조회를 수행할 수 있는 특수 코드가 있어요. 이를 통해 Envoy는 Ingress(및 Gateway API) 트래픽과 GAMMA나 L7 Traffic Management를 통한 동서(east-west) 트래픽 모두에 대해 Network Policy enforcement point가 될 수 있어요.

하지만 ingress 구성에는 추가 단계가 하나 더 있어요. Ingress나 Gateway API를 위해 Envoy에 도착한 트래픽은 Cilium의 Policy 엔진에서 특별한 ingress 아이덴티티로 지정돼요.

클러스터 외부에서 온 트래픽은 (클러스터에 IP CIDR 정책이 없다면) 보통 world 아이덴티티로 지정돼요. 즉 Cilium Ingress에는 실제로 두 개의 논리적 Policy enforcement point가 있다는 뜻이에요 — 트래픽이 ingress 아이덴티티에 도착하기 전과, 노드별 Envoy를 빠져나가려는 그 이후예요.

즉, 클러스터에 Network Policy를 적용할 때는 두 단계 모두 허용되는지, 그리고 world에서 ingress로, ingress에서 클러스터 안의 아이덴티티(위 이미지의 productpage 아이덴티티 등)로 트래픽이 허용되는지 확인하는 게 중요해요.

Ingress에 대한 자세한 내용은 Ingress and Network Policy Example을 참고해주세요. 단, 같은 원칙이 Gateway API에도 적용돼요.

소스 IP 가시성 (Source IP Visibility)

참고

기본적으로 Cilium ingress 구성(Ingress와 Gateway API 모두)의 소스 IP 가시성은 대부분의 설치에서 그냥 동작해야 해요. 요구사항과 관련 설정에 대한 자세한 내용은 이 섹션을 읽어주세요.

백엔드가 실제 요청이 어떤 IP 주소에서 왔는지 추론할 수 있는 것은 대부분의 애플리케이션에서 중요해요.

기본적으로 Cilium의 Envoy 인스턴스는 일반적인 규칙을 사용해 인입 HTTP 연결의 보이는 소스 주소를 X-Forwarded-For 헤더에 추가하도록 구성돼 있어요. 즉 기본적으로 Cilium은 신뢰된 홉(hop) 수를 0으로 설정해서, Envoy가 X-Forwarded-For 목록 안의 값이 아니라 연결이 열린 주소를 사용하도록 해요. 이 개수를 늘리면 Envoy가 목록의 오른쪽에서부터 세어 n 번째 값을 사용하게 돼요.

Envoy는 또한 X-Forwarded-For를 기반으로 결정된 신뢰된 클라이언트 주소가 무엇이든 X-Envoy-External-Address 헤더로 설정해요.

기본적으로 Cilium은 Ingress를 포함한 Layer 7 기능에 대한 정책을 적용할 때 연결 클라이언트의 소스 IP를 사용해요. 트래픽의 소스가 X-Forwarded-For 헤더를 주입하는 것을 신뢰한다면(예: 클라우드 로드 밸런서 사용 시), values 파일의 gatewayAPI 또는 ingressController 섹션에서 useRemoteAddress를 false로 설정해 Envoy가 X-Forwarded-For 헤더에 인코딩된 클라이언트 IP에서 온 트래픽으로 취급하도록 강제할 수 있어요.

자세한 내용은 Envoy X-Forwarded-For headers 문서를 참고해주세요.

참고

Cilium ingress(Ingress든 Gateway API든)를 사용하는 백엔드는 X-Forwarded-For와 X-Envoy-External-Address 헤더만 보면 돼요 (많은 HTTP 라이브러리가 이를 투명하게 처리해요).

Loadbalancer 또는 NodePort Service의 externalTrafficPolicy

Cilium의 ingress 지원(Ingress와 Gateway API 모두)은 종종 Loadbalancer나 NodePort Service를 사용해 Envoy DaemonSet을 노출해요.

이런 경우 Service 객체에는 클라이언트 IP 가시성과 특히 관련된 필드인 externalTrafficPolicy 필드가 있어요.

관련 설정 두 가지가 있어요:

  • Local: 노드는 소스 IP를 마스커레이드하지 않고 로컬 노드에서 실행 중인 파드로만 트래픽을 라우팅해요. 그렇기 때문에 kube-proxy를 사용하는 클러스터에서는 이것이 소스 IP 가시성을 보장하는 유일한 방법이에요. externalTrafficPolicy: local의 계약의 일부에는 노드가 포트를 연다는 것(externalTrafficPolicy: Local이 설정되면 Kubernetes가 자동으로 설정하는 healthCheckNodePort)도 있으며, 로컬 파드가 실행 중인 노드에서는 http://<nodeIP>:<healthCheckNodePort>/healthz 요청이 200을 반환하고, 그렇지 않은 노드에서는 200이 아닌 값을 반환해요. Cilium은 일반 Loadbalancer Service에 대해 이를 구현하지만, Cilium ingress 구성(Ingress와 Gateway API 모두)에서는 조금 다르게 동작해요.
  • Cluster: 노드는 클러스터 전체의 모든 엔드포인트로 균등하게 라우팅해요. 여기에는 몇 가지 다른 효과가 있어요. 첫째, 업스트림 로드 밸런서는 아무 노드로나 트래픽을 보내도 백엔드 파드에 도달할 것으로 기대하며, 노드는 소스 IP를 마스커레이드할 수도 있어요. 즉 많은 경우 externalTrafficPolicy: Cluster는 백엔드 파드가 소스 IP를 보지 못할 수 있다는 뜻이에요.

Cilium의 경우, Envoy를 노출하는 Service로 향하는 모든 ingress 트래픽은 항상 로컬 노드로 가고, 항상 Linux Kernel TPROXY 함수(백엔드로 패킷을 투명하게 전달)를 사용해 Envoy로 전달돼요.

즉 Cilium ingress 구성(Ingress와 Gateway API 모두)의 경우, 두 externalTrafficPolicy 경우 모두에서 조금 다르게 동작해요.

참고

두 externalTrafficPolicy 경우 모두에서 트래픽은 클러스터의 아무 노드에나 도착해서, 소스 IP를 그대로 유지한 채 Envoy로 전달돼요.

또한 Cilium의 Envoy를 노출하는 모든 Service에 대해, Cilium은 externalTrafficPolicy: Local이 설정되면 클러스터의 모든 노드가 healthCheckNodePort 검사를 통과하도록 보장해서, 외부 로드 밸런서가 올바르게 전달하게 해요.

하지만 Cilium의 ingress 구성(Ingress와 Gateway API 모두)의 경우, 백엔드 파드에 소스 IP를 보이게 유지하기 위해 externalTrafficPolicy: Local을 구성하는 것은 필요하지 않아요 (X-Forwarded-For와 X-Envoy-External-Address 필드 덕분이에요).

TLS 패스스루와 소스 IP 가시성 (TLS Passthrough and source IP visibility)

Ingress와 Gateway API 모두 TLS 패스스루 구성을 지원해요 (Ingress는 어노테이션, Gateway API는 TLSRoute 리소스). 이 구성은 여러 TLS 패스스루 백엔드가 로드 밸런서에서 동일한 TLS 포트를 공유할 수 있게 해주며, Envoy가 TLS 핸드셰이크의 Server Name Indicator(SNI) 필드를 검사해서 그 값을 사용해 TLS 스트림을 백엔드로 전달해요.

하지만 Envoy가 TLS 스트림의 TCP 프록시를 수행하므로, 이것은 소스 IP 가시성에 문제가 돼요.

어떤 일이 벌어지냐면, TLS 트래픽이 Envoy에 도착해서 TCP 스트림을 종료하고, Envoy가 client hello를 검사해 SNI를 찾은 다음 전달할 백엔드를 선택하고, 새 TCP 스트림을 시작해 다운스트림(외부) 패킷 안의 TLS 트래픽을 업스트림(백엔드)으로 전달해요.

이것은 새 TCP 스트림이므로, 백엔드 입장에서는 소스 IP가 Envoy예요 (Cilium 구성에 따라 보통 Node IP예요).

참고

TLS 패스스루를 수행할 때 백엔드는 전달된 TLS 스트림의 소스로 Cilium Envoy의 IP 주소를 보게 돼요.

더 알아보기 (Learn more)