Skip to content

How to forward traffic from ALB (Load balancer controller managed) to nginx controller in EKS?

0

I have an EKS cluster where I have installed the AWS Load Balancer Controller and ExternalDNS Controller.

I have created:

A Deployment for a Spring Boot application

A Service of type NodePort

An Ingress resource to create an ALB with routing rules

In this setup, the ALB is created successfully and routes traffic directly to the backend service. This works correctly.

However, I am facing an issue with CORS when my frontend application sends requests to the backend. Since ALB does not handle CORS, I decided to introduce NGINX Ingress Controller.

I installed the NGINX Ingress Controller as a NodePort service (not as a LoadBalancer, because the ALB already exists).

Now, I want to forward traffic from the ALB → NGINX service → backend service, so that NGINX can handle CORS before forwarding the request.

The problem is that the NGINX service is not getting registered in the ALB target group. In the ALB target group, it shows “Service not found”.

How to forward traffic to ngx ingress controller service? What am i doing wronf here

Nginx ingress controller install - Nodeport

# ------------------------------------------------------
# NGINX Ingress Controller (Internal – behind ALB)
# ------------------------------------------------------
resource "helm_release" "nginx_ingress" {
  name             = "nginx-ingress"
  repository       = "https://kubernetes.github.io/ingress-nginx"
  chart            = "ingress-nginx"
  namespace        = "ingress-nginx"
  create_namespace = true

  # --------------------------------------------------
  # Controller settings
  # --------------------------------------------------
  set {
    name  = "controller.replicaCount"
    value = "2"
  }

  # IMPORTANT:
  # Do NOT expose nginx via LoadBalancer
  # ALB will forward traffic to this service
  set {
  name  = "controller.service.type"
  value = "NodePort"
}

  # --------------------------------------------------
  # IngressClass configuration
  # --------------------------------------------------
  set {
    name  = "controller.ingressClass"
    value = "nginx"
  }

  set {
    name  = "controller.ingressClassResource.name"
    value = "nginx"
  }

  set {
    name  = "controller.ingressClassResource.enabled"
    value = "true"
  }

  set {
    name  = "controller.ingressClassResource.default"
    value = "false"
  }

  # --------------------------------------------------
  # Allow nginx annotations (required for CORS/snippets)
  # --------------------------------------------------
  set {
    name  = "controller.allowSnippetAnnotations"
    value = "true"
  }

  # --------------------------------------------------
  # Global CORS configuration (can override per ingress)
  # --------------------------------------------------
  set {
    name  = "controller.config.enable-cors"
    value = "true"
  }

  set {
    name  = "controller.config.cors-allow-origin"
    value = "*"
  }

  set_list {
    name  = "controller.config.cors-allow-methods"
    value = ["GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS"]
  }

  set_list {
    name  = "controller.config.cors-allow-headers"
    value = ["Authorization", "Content-Type", "Accept"]
  }

  set {
    name  = "controller.config.cors-allow-credentials"
    value = "true"
  }

  # --------------------------------------------------
  # Recommended production settings
  # --------------------------------------------------
  set {
    name  = "controller.config.use-forwarded-headers"
    value = "true"
  }

  set {
    name  = "controller.config.compute-full-forwarded-for"
    value = "true"
  }

  set {
    name  = "controller.config.proxy-body-size"
    value = "50m"
  }

  set {
    name  = "controller.config.proxy-read-timeout"
    value = "120"
  }

  set {
    name  = "controller.config.proxy-send-timeout"
    value = "120"
  }
}

Backend app service

# Kubernetes Service Manifest (Type: Node Port Service)
resource "kubernetes_service_v1" "construction_be_app_service" {
  metadata {
    name = "construction-be-app-service"
    namespace = "default"
    annotations = {
      "alb.ingress.kubernetes.io/healthcheck-path" = "/construction-expenses-manager/health"
    }
  }
  spec {
    selector = {
      app = kubernetes_deployment_v1.construction_be_app_deployment.spec.0.selector.0.match_labels.app
    }
    port {
      name        = "http"
      port        = 80
      target_port = 8080
    }
    type = "NodePort"
  }
}

Backend app ingress for alb

resource "time_sleep" "wait_60_seconds" {
  depends_on = [module.acm]
  create_duration = "120s"
}

# Kubernetes Service Manifest (Type: Load Balancer)
resource "kubernetes_ingress_v1" "ingress_app1" {
  metadata {
    name = "app1-ingress"
    annotations = {

      #"alb.ingress.kubernetes.io/target-type" = "ip"
      # Load Balancer Name
      "alb.ingress.kubernetes.io/load-balancer-name" = "ingress-groups-construction"
      # Ingress Core Settings
      "alb.ingress.kubernetes.io/scheme" = "internet-facing"
      # Health Check Settings
      "alb.ingress.kubernetes.io/healthcheck-protocol" =  "HTTP"
      "alb.ingress.kubernetes.io/healthcheck-port" = "traffic-port"
      #Important Note:  Need to add health check path annotations in service level if we are planning to use multiple targets in a load balancer    
      "alb.ingress.kubernetes.io/healthcheck-interval-seconds" = 15
      "alb.ingress.kubernetes.io/healthcheck-timeout-seconds" = 5
      "alb.ingress.kubernetes.io/success-codes" = 200
      "alb.ingress.kubernetes.io/healthy-threshold-count" = 2
      "alb.ingress.kubernetes.io/unhealthy-threshold-count" = 2
      ## SSL Settings
      # Option-1: Using Terraform jsonencode Function
      "alb.ingress.kubernetes.io/listen-ports" = jsonencode([{"HTTPS" = 443}, {"HTTP" = 80}]) 
      # SSL Redirect Setting
      "alb.ingress.kubernetes.io/ssl-redirect" = 443
      # External DNS - For creating a Record Set in Route53
      "external-dns.alpha.kubernetes.io/hostname" = "construction.foo-app.com"
      # Ingress Groups
      "alb.ingress.kubernetes.io/group.name" = "foo-app.web"
      "alb.ingress.kubernetes.io/group.order" = 10
    }    
  }

  spec {
    ingress_class_name = "my-aws-ingress-class" # Ingress Class 

    # SSL Certificate Discovery using TLS
    tls {
      hosts = [ "*.foo-app.com" ]
    }   

       # Rule-1: Route requests to App1 if the DNS is "construction.foo-app.com"
    rule {
      host = "construction.foo-app.com"      
      http {
        path {
          backend {
            service {
              name = "nginx-ingress-ingress-nginx-controller"
              port {
                number = 80
              }
            }
          }
          path = "/"
          path_type = "Prefix"
        }
      }        
    }

  }
}

Backend app ingress nginx

resource "kubernetes_ingress_v1" "nginx_app_ingress" {
  metadata {
    name      = "construction-nginx-ingress"
    namespace = "default"

    annotations = {
      # ❌ NO rewrite-target

      # CORS
      "nginx.ingress.kubernetes.io/enable-cors" = "true"
      "nginx.ingress.kubernetes.io/cors-allow-origin" = "https://construction.foo-app.com"
      "nginx.ingress.kubernetes.io/cors-allow-methods" = "GET, POST, PUT, DELETE, OPTIONS"
      "nginx.ingress.kubernetes.io/cors-allow-headers" = "Authorization, Content-Type"
      "nginx.ingress.kubernetes.io/cors-allow-credentials" = "true"

      # Important when backend is behind proxy
      "nginx.ingress.kubernetes.io/use-forwarded-headers" = "true"
    }
  }

  spec {
    ingress_class_name = "nginx"

    rule {
      host = "construction.foo-app.com"
      http {
        path {
          # 🔴 Backend REQUIRES full context path
          path      = "/construction-expenses-manager"
          path_type = "Prefix"

          backend {
            service {
              name = kubernetes_service_v1.construction_be_app_service.metadata[0].name
              port {
                number = 80
              }
            }
          }
        }
      }
    }
  }
}

here is service created by nginx controller

kubectl get svc -n ingress-nginx
nginx-ingress-ingress-nginx-controller              NodePort
nginx-ingress-ingress-nginx-controller-admission    ClusterIP

Note - Unlock AWS load balancer controller, i have not created any IAM role for it. I didn't think it was necessary

1 Answer
1

The issue you're experiencing is that you're trying to route traffic from your ALB directly to the NGINX Ingress Controller service, but the target registration is failing. Here's what's happening and how to fix it:

The Problem:

When you configure your ALB Ingress to point to the NGINX service (nginx-ingress-ingress-nginx-controller), the AWS Load Balancer Controller needs to register targets in the ALB's target group. However, you need to ensure the service is properly configured for the target type you're using.

The Solution:

You need to specify the target type in your ALB Ingress annotations. Based on your configuration, you should add the alb.ingress.kubernetes.io/target-type annotation. You have two options:

Option 1: Instance Mode (Recommended for NodePort)

Since your NGINX service is configured as NodePort, use Instance mode:

  1. Add this annotation to your kubernetes_ingress_v1.ingress_app1:
"alb.ingress.kubernetes.io/target-type" = "instance"
  1. Ensure your NGINX service remains as NodePort (which you already have configured correctly).

Option 2: IP Mode

If you prefer IP mode:

  1. Change the annotation to:
"alb.ingress.kubernetes.io/target-type" = "ip"
  1. Change your NGINX service type from NodePort to ClusterIP in your Helm release:
set {
name  = "controller.service.type"
value = "ClusterIP"
}

Additional Considerations:

  • Make sure your worker nodes have the proper subnet tags for the ALB to discover them (for Instance mode)
  • Verify that security groups allow traffic between the ALB and your worker nodes
  • The NGINX service name in your ALB Ingress backend should match exactly: nginx-ingress-ingress-nginx-controller
  • Ensure the port number (80) matches the port exposed by the NGINX service

The key issue is that without specifying the target-type annotation, the AWS Load Balancer Controller cannot properly register the NGINX service as targets in the ALB's target group, which is why you're seeing "Service not found" in the target group.
Sources
Troubleshoot AWS Load Balancer Controller errors in Amazon EKS | AWS re:Post

answered 5 days ago
EXPERT
reviewed 2 days ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.