앰비언트와 쿠버네티스 NetworkPolicy

앰비언트와 쿠버네티스 NetworkPolicy (Ambient and Kubernetes NetworkPolicy)

쿠버네티스 NetworkPolicy를 사용하면 layer 4 트래픽이 파드에 도달하는 방식을 제어할 수 있어요.

출처: Istio 문서

본문

NetworkPolicy는 일반적으로 클러스터에 설치된 CNI가 적용해요. Istio는 CNI가 아니며, NetworkPolicy를 적용하거나 관리하지 않고, 모든 경우에 그것을 존중해요. 앰비언트는 쿠버네티스 NetworkPolicy 적용을 우회하지 않으며 앞으로도 우회하지 않을 거예요.

이의 한 가지 함의는 Istio 트래픽을 차단하거나 Istio 기능을 방해하는 쿠버네티스 NetworkPolicy를 만들 수 있다는 것이에요. 그래서 NetworkPolicy와 앰비언트를 함께 사용할 때는 몇 가지 명심할 것이 있어요.

앰비언트 트래픽 오버레이와 쿠버네티스 NetworkPolicy (Ambient traffic overlay and Kubernetes NetworkPolicy)

앱비언트 메시에 애플리케이션을 추가하면, 앰비언트의 보안 L4 오버레이는 포트 15008에 걸쳐 파드 사이의 트래픽을 터널링해요. 보안 처리된 트래픽이 목적지 포트 15008로 대상 파드에 들어가면, 트래픽은 원래 목적지 포트로 다시 프록시돼요.

하지만 NetworkPolicy는 파드 밖의 호스트에서 적용돼요. 즉, 예를 들어 443을 제외한 모든 포트에서 앰비언트 파드로의 인바운드 트래픽을 거부하는 기존 NetworkPolicy가 있다면, 그 NetworkPolicy에 포트 15008에 대한 예외를 추가해야 해요. 트래픽을 받는 사이드카 워크로드도 앰비언트 워크로드가 그것과 통신할 수 있도록 포트 15008에서 인바운드 트래픽을 허용해야 해요.

예를 들어 다음 NetworkPolicy는 my-app으로의 포트 15008 HBONE 인바운드 트래픽을 차단할 거예요:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-app-allow-ingress-web
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: my-app
  ingress:
  - ports:
    - port: 8080
      protocol: TCP

그리고 my-app이 메시에 추가된다면 다음과 같이 변경해야 해요:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-app-allow-ingress-web
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: my-app
  ingress:
  - ports:
    - port: 8080
      protocol: TCP
    - port: 15008
      protocol: TCP

앰비언트, 헬스 프로브, 쿠버네티스 NetworkPolicy (Ambient, health probes, and Kubernetes NetworkPolicy)

쿠버네티스 헬스 체크 프로브는 문제를 일으키고 쿠버네티스 트래픽 정책 전반에 특별한 사례를 만들어요. 그것들은 클러스터의 다른 파드가 아니라 노드에서 프로세스로 실행되는 kubelet에서 시작돼요. 평문이고 보안되지 않아요. kubelet이나 쿠버네티스 노드는 일반적으로 자체 암호화 신원이 없으므로 접근 제어가 불가능해요. 헬스 프로브 포트에서 모든 트래픽을 통과시키는 것만으로는 충분하지 않아요. 악성 트래픽이 kubelet만큼 쉽게 그 포트를 사용할 수 있기 때문이에요. 게다가 많은 앱이 헬스 프로브와 정당한 애플리케이션 트래픽에 같은 포트를 사용하므로, 단순한 포트 기반 허용은 수용할 수 없어요.

다양한 CNI 구현은 서로 다른 방식으로 이 문제를 풀며, kubelet 헬스 프로브를 정상적인 정책 적용에서 조용히 제외해서 문제를 우회하거나, 그것들을 위한 정책 예외를 구성하려고 해요.

Istio 앱비언트에서 이 문제는 iptables 규칙과 소스 네트워크 주소 변환(SNAT)의 조합을 사용해, 로컬 노드에서 비롯되었음이 증명되는 패킷만 고정된 link-local IP로 다시 쓰고, 그것들이 보안되지 않은 헬스 프로브 트래픽으로서 Istio 정책 적용에 의해 명시적으로 무시될 수 있도록 함으로써 해결돼요. link-local IP가 기본값으로 선택된 이유는 일반적으로 인그레스-이그레스 제어에서 무시되고, IETF 표준에 따라 로컬 서브네트워크 밖으로는 라우팅될 수 없기 때문이에요.

이 동작은 파드를 앱비언트 메시에 추가할 때 투명하게 활성화되며, 기본적으로 앱비언트는 link-local 주소 169.254.7.127(IPv4)와 fd16:9254:7127:1337:ffff:ffff:ffff:ffff(IPv6)를 사용해 kubelet 헬스 프로브 패킷을 식별하고 올바르게 허용해요.

참고: 워크로드, 네임스페이스, 클러스터가 쿠버네티스 NetworkPolicy를 적용한다면, 앰비언트 모드가 사용하는 IPv4와 IPv6 주소를 모두 허용해야 해요. CNI에 따라 이 주소들을 가진 패킷이 차단될 수 있고, 그러면 애플리케이션 파드가 앱비언트 메시에 합류할 때 헬스 프로브가 실패할 거예요.

예를 들어, 네임스페이스에 다음 NetworkPolicy를 적용하면 my-app 파드로의 모든 트래픽(Istio든 아니든)을 차단하며, kubelet 헬스 프로브도 포함해 차단해요. CNI에 따라 kubelet 프로브와 link-local 주소가 이 정책에 무시되거나 차단될 수 있어요:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-ingress
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: my-app
  policyTypes:
  - Ingress

파드가 앱비언트 메시에 등록되면, 헬스 프로브 패킷에 SNAT를 통해 link-local 주소가 할당되기 시작하고, 이는 CNI의 NetworkPolicy 구현에 의해 헬스 프로브가 차단되기 시작할 수 있음을 의미해요. 앱비언트 헬스 프로브가 NetworkPolicy를 우회하도록 허용하려면, 호스트 노드에서 파드로의 트래픽을 명시적으로 허용하세요. 앱비언트가 이 트래픽에 사용하는 link-local 주소를 허용 목록에 추가해:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-ingress-allow-kubelet-healthprobes
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: my-app
  ingress:
    - from:
      - ipBlock:
          cidr: 169.254.7.127/32

참고: 듀얼 스택 클러스터나 IPv6 전용 클러스터를 사용한다면, IPv4 항목에 더해 IPv6 ipBlock(fd16:9254:7127:1337:ffff:ffff:ffff:ffff/128)으로 NetworkPolicy를 업데이트하거나 IPv4 항목 대신 사용하세요.

더 알아보기 (Learn more)