Istio와의 통합

Istio와의 통합 (Integration with Istio)

이 페이지는 Cilium이 활성화된 Kubernetes 클러스터에서 Istio를 사용하는 시작 방법을 알려드려요. Cilium 구성, Istio 구성, 그리고 데모 애플리케이션의 세 가지 공통 측면을 다뤄요.

출처: Integration with Istio

본문

이 페이지는 Cilium이 활성화된 Kubernetes 클러스터에서 Istio를 사용하는 시작 방법을 알려드려요. 이 문서는 Cilium과 Istio 통합의 다음 공통 측면을 다뤄요:

  • Cilium 구성
  • Istio 구성
  • 데모 애플리케이션

참고

Cilium을 Istio와 함께 두 가지 방법으로 실행할 수 있어요:

  • kube-proxy가 있는 경우 (권장):
    • kubeProxyReplacement: false(기본값)로 설정해요.
    • Cilium은 kube-proxy를 완전히 교체하지 않으며, kube-proxy가 ClusterIP 라우팅을 계속 처리해요.
    • 특히 사이드카 또는 ambient 모드에서 최소한의 중단으로 Istio를 사용하는 데 권장되는 설정이에요.
  • kube-proxy가 제거된 경우 (완전 교체):
    • kubeProxyReplacement: true, socketLB.hostNamespaceOnly: true, cni.exclusive: false로 설정해요.
    • 이 설정은 Cilium의 소켓 기반 로드 밸런싱이 Istio의 프록시와 간섭하지 않도록 방지해요.
    • 이 모드에서는 kube-proxy를 제거할 수 있지만, 호환성을 보장하려면 이 구성이 필요해요.

요약하면, kubeProxyReplacement: false(기본값, 대부분의 Istio 설치에서 권장)로 설정하면 Cilium과 kube-proxy와 함께 Istio를 실행할 수 있어요. 또는 kubeProxyReplacement: true로 설정해 kube-proxy 없이 실행할 수도 있지만, Istio와의 충돌을 피하려면 Cilium을 신중하게 구성해야 해요.

Cilium 구성 (Cilium Configuration)

Cilium 구성의 주요 목표는 Istio의 사이드카 프록시(사이드카 모드)나 노드 프록시(ambient 모드)로 리다이렉트된 트래픽이 중단되지 않도록 보장하는 거예요. Cilium의 kubeProxyReplacement 기능( Kubernetes Without kube-proxy 문서 참고)을 활성화하면 중단이 발생할 수 있는데, 이 기능은 Pod 내부에 소켓 기반 로드 밸런싱을 활성화하기 때문이에요.

Cilium이 Istio와 간섭하지 않도록 하려면 Cilium ConfigMap의 bpf-lb-sock-hostns-only 매개변수를 true로 설정하는 것이 중요해요. 이는 socketLB.hostNamespaceOnly Helm 값을 true로 설정하는 --set 플래그로 달성할 수 있어요. 결과는 다음 명령으로 확인할 수 있어요:

$ kubectl get configmaps -n kube-system cilium-config -oyaml | grep bpf-lb-sock-hostns
bpf-lb-sock-hostns-only: "true"

Istio는 CNI 플러그인을 사용해 사이드카와 ambient 모드 모두의 기능을 구현해요. Cilium이 노드의 다른 CNI 플러그인과 간섭하지 않도록 Cilium ConfigMap의 cni-exclusive 매개변수를 false로 설정하는 것이 중요해요. 이는 cni.exclusive Helm 값을 false로 설정하는 --set 플래그로 달성할 수 있어요. 결과는 다음 명령으로 확인할 수 있어요:

$ kubectl get configmaps -n kube-system cilium-config -oyaml | grep cni-exclusive
cni-exclusive: "false"

Istio 구성 (Istio configuration)

Cilium과 Istio를 함께 배포할 때는 다음을 유의하세요:

  • Cilium 또는 Istio L7 HTTP 정책 제어 중 하나를 사용할 수 있지만, 분할 뇌(split-brain) 문제를 피하기 위해 Cilium과 Istio L7 HTTP 정책 제어를 동시에 사용하는 것은 권장하지 않아요.
    • Cilium L7 HTTP 정책 제어(예: Layer 7 Policies)를 Istio(사이드카 또는 ambient 모드)와 함께 사용하려면 다음을 해야 해요:
      • 사이드카: Cilium L7 정책으로 관리하려는 워크로드에 대해 Istio의 PeerAuthentication 아래에 mtls.mode=DISABLE을 구성해 Istio mTLS를 비활성화해요.
      • Ambient: Cilium L7 정책으로 관리하려는 워크로드를 Istio ambient에서 제거하려면 네임스페이스에서 istio.io/dataplane-mode 레이블을 제거하거나, Cilium L7로 관리하려는 파드에 ambient.istio.io/redirection: disabled를 어노테이션해요.
    • 그렇지 않으면 Istio가 관리하는 워크로드 사이의 트래픽이 Istio에 의해 mTLS로 암호화되어, L7 정책 적용 목적으로 Cilium이 접근할 수 없게 돼요.
    • Istio L7 HTTP 정책 제어를 사용한다면 정책은 Istio에서 관리되며 워크로드 사이의 mTLS 비활성화는 필요하지 않아요.
  • Istio L7 HTTP 정책 제어와 함께 ambient 모드에서 Istio mTLS를 사용한다면, ambient 워크로드 사이의 트래픽은 Istio가 포트 15008로 파드 안팎으로 암호화하고 터널링해요. 이 시나리오에서 Cilium NetworkPolicy는 Istio가 관리하는 파드에 들어오고 나가는 암호화되고 터널링된 L4 트래픽에는 여전히 적용돼요. 하지만 Cilium은 그 터널링되고 암호화된 L4 트래픽의 실제 소스와 목적지, 또는 어떤 L7 정보도 볼 수 없어요. 즉 Istio가 관리하고 mTLS로 보호된 워크로드 사이의 트래픽에 대한 정책은 Istio가 L4 이상에서 강제해야 해요. Istio가 관리하지 않는 워크로드에서 Istio가 관리하는 워크로드로 들어오는 트래픽은 터널링되거나 암호화되지 않으므로, Cilium이 강제하는 Kubernetes NetworkPolicy의 적용을 계속 완전히 받게 돼요.
  • 자동 사이드카 주입과 함께 사이드카 모드에서 Istio를 사용하면서 Cilium 오버레이 모드(VXLAN 또는 GENEVE)를 함께 사용하는 경우, istiod 파드는 API 서버가 도달할 수 있도록 hostNetwork: true로 실행되어야 해요.

데모 애플리케이션 (Cilium으로 Istio ambient 모드 사용하기)

이 가이드는 Istio L7 HTTP 정책 제어 대신 Cilium L7 HTTP 정책 제어를 사용할 때, Istio ambient mTLS 모드와 Cilium 네트워크 정책 사이의 상호작용을 보여드려요. Istio 구성 섹션에서 설명한 주의사항도 포함돼요.

사전 요구사항 (Prerequisites)

  • Istio가 로컬 Kubernetes 클러스터에 이미 설치되어 있어요.
  • Cilium이 socketLB.hostNamespaceOnly와 cni.exclusive=false Helm 값으로 이미 설치되어 있어요.
  • Istio의 istioctl이 로컬 호스트에 설치되어 있어요.

세 개의 서로 다른 네임스페이스에 웹 서버와 클라이언트 애플리케이션 집합을 배포하는 것부터 시작해볼게요:

kubectl create ns red
kubectl label namespace red istio.io/dataplane-mode=ambient
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/httpbin.yaml)
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/netshoot.yaml)
kubectl create ns blue
kubectl label namespace blue istio.io/dataplane-mode=ambient
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/httpbin.yaml)
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/netshoot.yaml)
kubectl create ns green
kubectl -n green apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/netshoot.yaml

기본적으로 Istio는 PERMISSIVE 모드로 동작해서, Istio-ambient가 관리하는 파드와 관리하지 않는 파드 모두 서로 간에 보안되지 않은 트래픽을 주고받을 수 있게 해요. 앞선 예제에서 배포한 클라이언트와 서버 애플리케이션 사이의 연결성을 다음 명령으로 테스트할 수 있어요:

kubectl exec -n red deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'red' to server 'red': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'red': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'green' to server 'red': %{http_code}\n"
kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'blue': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'green' to server 'blue': %{http_code}\n"

모든 명령이 성공적으로 완료되어야 해요:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 200

네임스페이스 사이의 통신을 제한하기 위해 Cilium이 강제하는 L4 NetworkPolicy를 적용할 수 있어요. 다음 명령은 blue 네임스페이스의 통신을 blue와 red 네임스페이스에만 있는 클라이언트로 제한하는 L4 네트워크 정책을 적용해요.

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/l4-policy.yaml

예상 결과를 확인하기 위해 동일한 연결성 검사를 다시 실행해볼게요:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 000
command terminated with exit code 28

그런 다음 같은 네트워크 정책을 강화해서 추가 HTTP 기반 검사를 수행할 수 있어요. 다음 명령은 /ip URL 경로와의 통신만 허용하는 Cilium L7 네트워크 정책을 적용해요:

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/l7-policy.yaml

이 시점에서 Cilium 프록시(HTTP)가 Istio의 mTLS 기반 HTTPS 연결과 간섭하므로 blue 네임스페이스와의 모든 통신이 끊겨요:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 000
command terminated with exit code 28
client 'blue' to server 'blue': 000
command terminated with exit code 28
client 'green' to server 'blue': 000
command terminated with exit code 28

문제를 해결하고 Cilium이 L7 정책을 관리하게 하려면, Cilium이 L7 정책을 관리하길 원하는 워크로드나 네임스페이스를 Istio ambient 메시에서 제거해야 해요:

kubectl label namespace red istio.io/dataplane-mode-
kubectl label namespace blue istio.io/dataplane-mode-

연결성 검사를 다시 실행해서 blue 네임스페이스와의 통신이 복원됐는지 확인할 수 있어요. /deny 같은 다른 URL 경로에 접근해서 Cilium이 L7 네트워크 정책을 강제하는지 확인할 수 있어요:

$ kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/deny -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
client 'red' to server 'blue': 403

데모 애플리케이션 (Istio 사이드카 모드)

이 가이드는 Istio L7 HTTP 정책 제어 대신 Cilium L7 HTTP 정책 제어를 사용할 때, Istio의 사이드카 기반 mTLS 모드와 Cilium 네트워크 정책 사이의 상호작용을 보여드려요. Istio 구성 섹션에서 설명한 mTLS 비활성화에 관한 주의사항도 포함돼요.

사전 요구사항 (Prerequisites)

  • Istio가 로컬 Kubernetes 클러스터에 이미 설치되어 있어요.
  • Cilium이 socketLB.hostNamespaceOnly와 cni.exclusive=false Helm 값으로 이미 설치되어 있어요.
  • Istio의 istioctl이 로컬 호스트에 설치되어 있어요.

세 개의 서로 다른 네임스페이스에 웹 서버와 클라이언트 애플리케이션 집합을 배포하는 것부터 시작해볼게요:

kubectl create ns red
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/httpbin.yaml | istioctl kube-inject -f -)
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/netshoot.yaml | istioctl kube-inject -f -)
kubectl create ns blue
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/httpbin.yaml | istioctl kube-inject -f -)
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/netshoot.yaml | istioctl kube-inject -f -)
kubectl create ns green
kubectl -n green apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/netshoot.yaml

기본적으로 Istio는 PERMISSIVE 모드로 동작해서, Istio가 관리하는 파드와 사이드카가 없는 파드 모두 서로 간에 트래픽을 주고받을 수 있게 해요. 앞선 예제에서 배포한 클라이언트와 서버 애플리케이션 사이의 연결성을 다음 명령으로 테스트할 수 있어요:

kubectl exec -n red deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'red' to server 'red': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'red': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'green' to server 'red': %{http_code}\n"
kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'blue': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'green' to server 'blue': %{http_code}\n"

모든 명령이 성공적으로 완료되어야 해요:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 200

네임스페이스 사이의 통신을 제한하기 위해 네트워크 정책을 적용할 수 있어요. 다음 명령은 blue 네임스페이스의 통신을 blue와 red 네임스페이스에만 있는 클라이언트로 제한하는 Cilium이 관리하는 L4 네트워크 정책을 적용해요.

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/l4-policy.yaml

예상 결과를 확인하기 위해 동일한 연결성 검사를 다시 실행해볼게요:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 000
command terminated with exit code 28

그런 다음 L4 네트워크 정책을 강화해서 추가 Cilium 관리 HTTP 기반 검사를 수행할 수 있어요. 다음 명령은 /ip URL 경로와의 통신만 허용하는 Cilium L7 네트워크 정책을 적용해요:

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/l7-policy.yaml

이 시점에서 Cilium 프록시(HTTP)가 Istio의 mTLS 기반 HTTPS 연결과 간섭하므로 blue 네임스페이스와의 모든 통신이 끊겨요:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 503
client 'blue' to server 'blue': 503
client 'green' to server 'blue': 000
command terminated with exit code 28

문제를 해결하고 Cilium이 L7 정책을 관리하게 하려면 새 정책을 구성해 Istio의 mTLS 인증을 비활성화해야 해요:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
spec:
  mtls:
    mode: DISABLE

이 정책은 HTTP 기반 네트워크 정책을 구현하는 것과 동일한 네임스페이스에 적용해야 해요:

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes-istio/authn.yaml

연결성 검사를 다시 실행해서 blue 네임스페이스와의 통신이 복원됐는지 확인할 수 있어요. /deny 같은 다른 URL 경로에 접근해서 Cilium이 L7 네트워크 정책을 강제하는지 확인할 수 있어요:

$ kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/deny -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
client 'red' to server 'blue': 403

더 알아보기 (Learn more)