쿠버네티스 일반/Network

AWS NLB EKS 환경에서 사용자 IP 파드로 전달

Jerry_이정훈 2022. 9. 30. 05:40
728x90

사용자의 IP를 파드까지 정상적으로 전달하도록 작업한 내역을 공유한다.

 

TL;DR

  • AWS NLB는 L4 기반이라 L7 Application LB의 x-forwarded-for 설정없이 client-ip 전달이 가능
  • 하지만 쿠버네티스의 Proxy 구조 상 외부 LB에서 받은 트래픽이 전체 클러스터의 노드를 거쳐서 파드로 전달되기 때문에 파드에는 client ip가 아닌 노드 IP가 기록됨
  • externalTrafficPolicy을 Local로 변경하면 노드 IP가 아닌 client ip 전달 가능. 하지만 설정을 변경하면 전체 클러스터의 노드가 아닌 ingress controller가 설치된 노드에서만 트래픽을 전달하여 ingress controller가 설치된 노드(통상 이중화를 위한 2개의 노드)만 트래픽이 몰리고 2개의 노드만 처리하므로 안정성에 문제가 발생할 수 있음
  • externalTrafficPolicy을 cluster로 유지하고 NLB 설정에서 Proxy protocol을 활성화해서 client IP 전달 가능

아래 내가 쓴 글보다는 이 블로그를 참조하는게 훨씬 낫다. 다만 나는 nginx ingress-controller 헬름 차트를 사용하여 해당 부분을 공유한다.

 

blog.barogo.io

 

사용자 IP를 그대로 전달하는 것은 자주하는 설정인데(x-forwarded-for 헤더 추가) 쿠버네티스는 kube proxy 구조라 기본 옵션에서는 사용자 IP가 아닌 노드의 IP가 전달된다.

from: https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies

물론 위 그림과 같이 externalTrafficPolicy: Local 옵션을 지정하면 사용자의 IP가 그대로 전달된다. 하지만 이경우 ingress-controller가 설치된 노드에 트래픽이 몰리고 해당 노드에 문제가 발생하면 전체 ingress 서비스에 문제가 발생하므로 기본 설정인 externalTrafficPolicy: Cluster 옵션을 유지하는게 낫다. (물론 on-premise 환경처럼 노드의 갯수가 작아 ingress-controller를 전체 노드에 daemonset으로 설치하면 된다. 실제 이렇게 이전 회사에서는 운영하기도 하였고. 하지만 클라우드 환경은 노드의 수량이 많아 조금 맞지 않는다.)

 

externalTrafficPolicy: Cluster 옵션을 유지하고 사용자 IP를 전달하려면 상단의 LoadBalancer에서 proxy protocol을 활성화해야 한다. 우리 환경은 AWS NLB를 사용하는데 해당 옵션은 NLB가 바라보는 타켓 그룹에서 설정한다.

 

AWS Console의
- EC2 - Load Balancing - Target Groups - 해당 타켓 그룹
- Attributes : ‘Proxy protocol v2’ 옵션 선택

위의 타켓 그룹은 쿠버네티스의 로드밸런서가 사용하는 타켓 그룹에서 작업한다. 

 

위 설정은 GUI 작업이라 IaC 코드화가 되지 않았다. AWS Load Balancer Controller를 사용하면 될수도 있을 것 같은데 테스트 해 보지는 않았다.

 

참조.

https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/guide/service/annotations/#target-group-attributes 

 

Annotations - AWS Load Balancer Controller

Annotations Service annotations Annotation keys and values can only be strings. All other types below must be string-encoded, for example: boolean: "true" integer: "42" stringList: "s1,s2,s3" stringMap: "k1=v1,k2=v2" json: "{ \"key\": \"value\" }" Annotati

kubernetes-sigs.github.io

service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: proxy_protocol_v2.enabled=true

다음은 nginx ingress controller의 서비스와 ConfigMap도 추가 작업을 해야한다. nginx ingress controller를 사용하는데 필자는 헬름 차트를 이용하여 설치하였다. 헬름 차트의 변수 파일에서 아래 부분을 수정한다.

 

먼저 쿠버네티스 서비스의 annotations을 추가한다. 

controller:
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*'

다음으로 ConfigMap 부분을 추가한다.

controller:
# -- Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
  config:
    use-proxy-protocol: "true"

이제 설정이 완료되어 수정된 헬름 차트로 배포한다.

$ (⎈ |kr-stage:switchws) helm upgrade ingress-nginx -f my-values.yaml .

설정이 완료되어 파드에서 확인하면 노드의 IP가 아닌 사용자의 진짜 IP를 확인할 수 있다.

반응형