'AWS - x-real-ip is ip of nginx-ingress-controller

I currently have the following problem. I have a backend that is behind an nginx-ingress controller used as load balancer in aws. Usually i should get the users real ip by either the header x-forwarded-for or x-real-ip. However this ip always points to the ip of the ingress controller in my case. I use terraform to setup my architecture.

This is my current configuration

resource "helm_release" "ingress_nginx" {
  name             = "ingress-nginx"
  namespace        = "ingress"
  create_namespace = true
  chart            = "ingress-nginx"
  version          = "4.0.13"
  repository       = "https://kubernetes.github.io/ingress-nginx"

  values = [
    <<-EOF
    controller:
      service:
        annotations:
          service.beta.kubernetes.io/aws-load-balancer-type: nlb
      admissionWebhooks:
        enabled: false
    EOF
  ]
}

data "kubernetes_service" "ingress_nginx" {
  metadata {
    name      = "ingress-nginx-controller"
    namespace = helm_release.ingress_nginx.metadata[0].namespace
  }
}

data "aws_lb" "ingress_nginx" {
  name = regex(
    "(^[^-]+)",
    data.kubernetes_service.ingress_nginx.status[0].load_balancer[0].ingress[0].hostname
  )[0]
}

output "lb" {
  value = data.aws_lb.ingress_nginx.name
}`

Does anybody know how to fix the header in this config?



Solution 1:[1]

To get the real IP address in the header both the ingress controller and the NLB (Network Load Balancer) need to use Proxy Protocol. To do this, in terraform you need to configure the ingress controller with the proxy-protocol option:

resource "helm_release" "ingress_nginx" {
  name             = "ingress-nginx"
  namespace        = "ingress"
  create_namespace = true
  chart            = "ingress-nginx"
  version          = "4.0.13"
  repository       = "https://kubernetes.github.io/ingress-nginx"

  values = [
    <<-EOF
    controller:
      service:
        annotations:
          service.beta.kubernetes.io/aws-load-balancer-type: nlb
      config:
        use-forwarded-headers: true
        use-proxy-protocol: true
        enable-real-ip: true
      admissionWebhooks:
        enabled: false
    EOF
  ]
}

data "kubernetes_service" "ingress_nginx" {
  metadata {
    name      = "ingress-nginx-controller"
    namespace = helm_release.ingress_nginx.metadata[0].namespace
  }
}

data "aws_lb" "ingress_nginx" {
  name = regex(
    "(^[^-]+)",
    data.kubernetes_service.ingress_nginx.status[0].load_balancer[0].ingress[0].hostname
  )[0]
}

output "lb" {
  value = data.aws_lb.ingress_nginx.name
}

Now, it seems that currently there is no way to get the NLB to use proxy protocol by annotating the service.

There are some issues in github mentioning that the following annotations would solve it:

*service.beta.kubernetes.io/aws-load-balancer-type: "nlb-ip"*

and

*service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"*

However, these have not worked for me. So, I have enabled proxy protocol manually though the AWS Console by doing the following:

AWS console --> EC2 --> Target groups under load balancing --> Select Target groups associated with your NLB --> Attributes --> Enable proxy protocol 2

I guess that in terraform the optimal solution would be to explicitly create a Network Load Balancer with the correct target group and associate it with the ingress controller service.

Doing this, now I get the correct IP addresses of the clients connecting to the ingress controller.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 emilianofs