게이트웨이 네트워크 토폴로지 구성

게이트웨이 네트워크 토폴로지 구성 (Configuring Gateway Network Topology)

클라이언트 IP 주소와 인증서 정보 같은 외부 클라이언트 속성을 목적지 워크로드로 전달하기 위한 네트워크 토폴로지를 구성하는 방법을 배워요. X-Forwarded-For, X-Forwarded-Client-Cert 헤더와 PROXY 프로토콜을 다뤄요.

출처: Istio 문서

본문

Istio는 쿠버네티스 Gateway API를 지원하며 향후 트래픽 관리의 기본 API로 만들려고 해요. 다음 지침은 트래픽 관리를 구성할 때 Gateway API 또는 Istio 구성 API 중 하나를 선택해 사용할 수 있게 해줘요. 선호에 따라 Gateway API 또는 Istio APIs 탭 아래의 지침을 따르세요.

대부분의 쿠버네티스 클러스터에는 Gateway API CRD가 기본으로 설치되지 않으므로 Gateway API를 사용하기 전에 설치되어 있는지 확인하세요.

$ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.0/experimental-install.yaml

외부 클라이언트 속성(IP 주소, 인증서 정보)을 목적지 워크로드로 전달하기

많은 애플리케이션은 제대로 동작하기 위해 원래 요청의 클라이언트 IP 주소와 인증서 정보를 알아야 해요. 주목할 만한 경우로는 클라이언트 IP가 채워져야 하는 로깅·감사 도구와, 규칙 집합을 올바르게 적용하기 위해 이 정보가 필요한 Web Application Firewall(WAF) 같은 보안 도구가 있어요. 서비스에 클라이언트 속성을 제공하는 능력은 오랫동안 리버스 프록시의 주요 기능이었어요. 이러한 클라이언트 속성을 목적지 워크로드로 전달하기 위해 프록시는 X-Forwarded-For(XFF)와 X-Forwarded-Client-Cert(XFCC) 헤더를 사용해요.

오늘날의 네트워크는 성격이 매우 다양하지만, 네트워크 토폴로지가 어떻든 이러한 속성에 대한 지원은 요구사항이에요. 네트워크가 클라우드 기반 Load Balancer, 온프레미스 Load Balancer, 인터넷에 직접 노출된 게이트웨이, 많은 중간 프록시를 제공하는 게이트웨이, 그리고 명시되지 않은 다른 배포 토폴로지를 사용하든, 이 정보는 보존되어 전달되어야 해요.

Istio가 ingress gateway를 제공하지만, 위에서 언급한 다양한 아키텍처를 고려하면 클라이언트 속성을 목적지 워크로드로 올바르게 전달하는 것을 지원하는 합리적인 기본값을 제공할 수 없어요. Istio 멀티클러스터 배포 모델이 더 보편화됨에 따라 이는 더욱 중요해져요.

X-Forwarded-For에 대한 자세한 내용은 IETF의 RFC를 참고하세요.

네트워크 토폴로지 구성

XFF와 XFCC 헤더의 구성은 모든 게이트웨이 워크로드에 대해 MeshConfig로 전역 설정하거나, 파드 어노테이션으로 게이트웨이별로 설정할 수 있어요. 예를 들어 IstioOperator 커스텀 리소스를 사용해 설치 또는 업그레이드 시 전역으로 구성하려면:

spec:
  meshConfig:
    defaultConfig:
      gatewayTopology:
        numTrustedProxies: <VALUE>
        forwardClientCertDetails: <ENUM_VALUE>

Istio ingress gateway의 Pod spec에 proxy.istio.io/config 어노테이션을 추가해 두 설정을 모두 구성할 수도 있어요.

...
  metadata:
    annotations:
      "proxy.istio.io/config": '{"gatewayTopology" : { "numTrustedProxies": <VALUE>, "forwardClientCertDetails": <ENUM_VALUE> } }'

X-Forwarded-For 헤더 구성

애플리케이션은 X-Forwarded-For 헤더 같은 요청의 클라이언트 속성을 전달하기 위해 리버스 프록시에 의존해요. 하지만 Istio가 배포될 수 있는 네트워크 토폴로지가 다양하기 때문에, 클라이언트 주소를 올바르게 추출할 수 있도록 Istio 게이트웨이 프록시 앞에 배포된 신뢰할 수 있는 프록시의 수로 numTrustedProxies를 설정해야 해요. 이는 ingress gateway가 X-Envoy-External-Address 헤더에 채우는 값을 제어하며, 업스트림 서비스가 이 값을 사용해 클라이언트의 원래 IP 주소에 안정적으로 접근할 수 있어요.

예를 들어 Istio 게이트웨이 앞에 클라우드 기반 Load Balancer와 리버스 프록시가 있다면 numTrustedProxies를 2로 설정하세요.

httpbin으로 X-Forwarded-For 기능 사용 예제
  1. 다음 명령을 실행해 numTrustedProxies를 2로 설정한 topology.yaml 파일을 만들고 Istio를 설치하세요.
$ cat <<EOF > topology.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  meshConfig:
    defaultConfig:
      gatewayTopology:
        numTrustedProxies: 2
EOF
$ istioctl install -f topology.yaml

이전에 Istio ingress gateway를 설치했다면 1단계 후에 모든 ingress gateway 파드를 재시작하세요.

  1. httpbin 네임스페이스를 만드세요.
$ kubectl create namespace httpbin
namespace/httpbin created
  1. sidecar 주입을 위해 istio-injection 라벨을 enabled로 설정하세요.
$ kubectl label --overwrite namespace httpbin istio-injection=enabled
namespace/httpbin labeled
  1. httpbin 네임스페이스에 httpbin을 배포하세요.
$ kubectl apply -n httpbin -f @samples/httpbin/httpbin.yaml@
  1. httpbin과 연관된 게이트웨이를 배포하세요.
$ kubectl apply -n httpbin -f @samples/httpbin/httpbin-gateway.yaml@
$ kubectl apply -n httpbin -f @samples/httpbin/gateway-api/httpbin-gateway.yaml@
$ kubectl wait --for=condition=programmed gtw -n httpbin httpbin-gateway
  1. Istio ingress gateway의 IP 주소를 기반으로 로컬 GATEWAY_URL 환경 변수를 설정하세요.
$ export GATEWAY_URL=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export GATEWAY_URL=$(kubectl get gateways.gateway.networking.k8s.io httpbin-gateway -n httpbin -ojsonpath='{.status.addresses[0].value}')
  1. 다음 curl 명령을 실행해 X-Forwarded-For 헤더에 프록시 주소가 있는 요청을 시뮬레이션하세요.
$ curl -s -H 'X-Forwarded-For: 56.5.6.7, 72.9.5.6, 98.1.2.3' "$GATEWAY_URL/get?show_env=true" | jq '.headers["X-Forwarded-For"][0]'
  "56.5.6.7, 72.9.5.6, 98.1.2.3,10.244.0.1"

위 출력은 httpbin 워크로드가 받은 요청 헤더를 보여줘요. Istio 게이트웨이가 이 요청을 받았을 때, curl 명령의 X-Forwarded-For 헤더에서 두 번째 마지막(numTrustedProxies: 2) 주소로 X-Envoy-External-Address 헤더를 설정했어요. 또한 게이트웨이는 httpbin 워크로드로 전달하기 전에 X-Forwarded-For 헤더에 자신의 IP를 추가해요.

X-Forwarded-Client-Cert 헤더 구성

XFCC에 관한 Envoy의 문서에서:

XFCC 헤더가 처리되는 방식을 구성하려면 IstioOperator에서 forwardClientCertDetails를 설정하세요.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  meshConfig:
    defaultConfig:
      gatewayTopology:
        forwardClientCertDetails: <ENUM_VALUE>

여기서 ENUM_VALUE는 다음 유형 중 하나일 수 있어요.

ENUM_VALUE
UNDEFINED Field is not set.
SANITIZE Do not send the XFCC header to the next hop.
FORWARD_ONLY When the client connection is mTLS (Mutual TLS), forward the XFCC header in the request.
APPEND_FORWARD When the client connection is mTLS, append the client certificate information to the request's XFCC header and forward it.
SANITIZE_SET When the client connection is mTLS, reset the XFCC header with the client certificate information and send it to the next hop. This is the default value for a gateway.
ALWAYS_FORWARD_ONLY Always forward the XFCC header in the request, regardless of whether the client connection is mTLS.

이 기능을 사용하는 예제는 Envoy 문서를 참고하세요.

PROXY 프로토콜

PROXY 프로토콜은 HTTP 및 X-Forwarded-For, X-Envoy-External-Address 헤더 같은 L7 프로토콜에 의존하지 않고 TCP 프록시 간에 클라이언트 속성을 교환하고 보존할 수 있게 해줘요. 이는 외부 TCP 로드 밸런서가 Istio 게이트웨이를 통해 TCP 트래픽을 백엔드 TCP 서비스로 프록시하면서도 소스 IP 같은 클라이언트 속성을 업스트림 TCP 서비스 엔드포인트에 노출해야 하는 시나리오를 위한 것이에요. PROXY 프로토콜은 EnvoyFilter를 통해 활성화할 수 있어요.

PROXY 프로토콜은 Envoy의 TCP 트래픽 전달에서만 지원돼요. 자세한 내용과 중요한 성능 주의사항은 Envoy 문서를 참고하세요.

PROXY 프로토콜은 L7 트래픽이나 L7 로드 밸런서 뒤에 있는 Istio 게이트웨이에는 사용하면 안 돼요.

외부 TCP 로드 밸런서가 TCP 트래픽을 전달하고 PROXY 프로토콜을 사용하도록 구성되어 있다면, Istio Gateway TCP 리스너도 PROXY 프로토콜을 수용하도록 구성해야 해요. 게이트웨이의 모든 TCP 리스너에서 PROXY 프로토콜을 활성화하려면 IstioOperator에서 proxyProtocol을 설정하세요. 예를 들어:

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  meshConfig:
    defaultConfig:
      gatewayTopology:
        proxyProtocol: {}

또는 다음 파드 어노테이션으로 게이트웨이를 배포하세요.

metadata:
  annotations:
    "proxy.istio.io/config": '{"gatewayTopology" : { "proxyProtocol": {} }}'

클라이언트 IP는 게이트웨이가 PROXY 프로토콜에서 검색해 X-Forwarded-For와 X-Envoy-External-Address 헤더에 설정(또는 추가)돼요. PROXY 프로토콜은 X-Forwarded-For 및 X-Envoy-External-Address 같은 L7 헤더와 상호 배타적이라는 점을 기억하세요. gatewayTopology 구성과 함께 PROXY 프로토콜을 사용하면 신뢰할 수 있는 클라이언트 주소를 결정할 때 numTrustedProxies와 수신된 X-Forwarded-For 헤더가 우선하며, PROXY 프로토콜 클라이언트 정보는 무시돼요.

위 예제는 게이트웨이가 들어오는 PROXY 프로토콜 TCP 트래픽을 수용하도록만 구성한다는 점을 기억하세요. Envoy 자체가 PROXY 프로토콜로 업스트림 서비스와 통신하도록 구성하는 예제는 Envoy 문서를 참고하세요.

더 알아보기 (Learn more)