Search code examples
kubernetesnginxterraformkubernetes-ingressnginx-ingress

Terraform Kubernetes NGINX Ingress - Host rules not returning 504 (Gateway Timeout)


I am trying to specify different hosts (subdomains) to different Kubernetes Services within my Kubernetes NGINX Ingress. For reference I am using Azure AKS.

I have the following ingress declared in Terraform.

resource "helm_release" "nginx_ingress" {
  name             = "nginx-ingress"
  repository       = "https://kubernetes.github.io/ingress-nginx"
  chart            = "ingress-nginx"
  namespace        = "ingress-nginx"
  create_namespace = true
  set {
    name  = "controller.service.type"
    value = "LoadBalancer"
  }
}

resource "kubernetes_ingress_v1" "nginx_ingress" {
  metadata {
    name = "nginx-ingress"
  }

  spec {
    ingress_class_name = "nginx"

    rule {
      host = "front-end.mydomain.com" # disable to access both hosts
      http {
        path {
          path      = "/"
          path_type = "Prefix"
          backend {
            service {
              name = kubernetes_service_v1.front_end.metadata[0].name
              port {
                number = 80
              }
            }
          }
        }
      }
    }

    rule {
      host = "docs.mydomain.com"
      http {
        path {
          path      = "/"
          path_type = "Prefix"
          backend {
            service {
              name = kubernetes_service_v1.front_end.metadata[0].name
              port {
                number = 80
              }
            }
          }
        }
      }
    }
  }
}

This is what happens with different configurations.

If I have one host set, both sites are accessible over HTTP on their domains.

If I have no hosts set, no sites are accessible over HTTP on their domains.

If I have both hosts set, no sites are accessible over HTTP on their domains.

I do not currently understand why this is occurring. I have confirmed the DNS A records point towards the correct IP address of the load balancer/ingress for each subdomain.

Edit: Fixed missing curly brace


Solution

  • After significant tinkering, I have resolved the issue.

    The solution was to set the below on the NGINX ingress controller declared using the helm release provider.

    # Required for SSL/TLS self-check to succeed (cert-manager)
    set {
      name  = "controller.service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path"
      value = "/healthz"
    }
    
    # Required for host path routing to succeed
    set {
      name  = "controller.service.externalTrafficPolicy"
      value = "Local"
    }
    

    Updated complete example below.

    resource "helm_release" "nginx_ingress" {
      name             = "nginx-ingress"
      repository       = "https://kubernetes.github.io/ingress-nginx"
      chart            = "ingress-nginx"
      namespace        = "ingress-nginx"
      create_namespace = true
      set {
        name  = "controller.service.type"
        value = "LoadBalancer"
      }
      set {
        name  = "controller.service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path"
        value = "/healthz"
      }
      set {
        name  = "controller.service.externalTrafficPolicy"
        value = "Local"
      }
    }
    
    resource "kubernetes_ingress_v1" "nginx_ingress" {
      metadata {
        name = "nginx-ingress"
      }
    
      spec {
        ingress_class_name = "nginx"
    
        rule {
          host = "front-end.mydomain.com"
          http {
            path {
              path      = "/"
              path_type = "Prefix"
              backend {
                service {
                  name = kubernetes_service_v1.front_end.metadata[0].name
                  port {
                    number = 80
                  }
                }
              }
            }
          }
        }
    
        rule {
          host = "docs.mydomain.com"
          http {
            path {
              path      = "/"
              path_type = "Prefix"
              backend {
                service {
                  name = kubernetes_service_v1.front_end.metadata[0].name
                  port {
                    number = 80
                  }
                }
              }
            }
          }
        }
    
        tls {
          hosts = [
            "front-end.mydomain.com",
            "docs.mydomain.com"
          ]
          secret_name = "letsencrypt-tls"
        }
      }
    }