amazon-web-servicesterraformtls1.2nlb

Terraform AWS NLB TLS Passthrough


Using terraform I'm provisioning infra in AWS for my K3S cluster. I have provisioned an NLB with two listeners on port 80 and 443, with appropriate self-signed certs. This works. I can access HTTP services in my cluster via the nlb.

resource "tls_private_key" "agents" {
  algorithm = "RSA"
}

resource "tls_self_signed_cert" "agents" {
  key_algorithm         = "RSA"
  private_key_pem       = tls_private_key.agents.private_key_pem
  validity_period_hours = 24

  subject {
    common_name  = "my hostname"
    organization = "My org"
  }

  allowed_uses = [
    "key_encipherment",
    "digital_signature",
    "server_auth"
  ]
}

resource "aws_acm_certificate" "agents" {
  private_key      = tls_private_key.agents.private_key_pem
  certificate_body = tls_self_signed_cert.agents.cert_pem
}


resource "aws_lb" "agents" {
  name               = "basic-load-balancer"
  load_balancer_type = "network"

  subnet_mapping {
    subnet_id     = aws_subnet.agents.id
    allocation_id = aws_eip.agents.id
  }
}

resource "aws_lb_listener" "agents_80" {
  load_balancer_arn = aws_lb.agents.arn
  protocol = "TCP"
  port     = 80

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.agents_80.arn
  }
}

resource "aws_lb_listener" "agents_443" {
  load_balancer_arn = aws_lb.agents.arn
  protocol = "TLS"
  port     = 443
  certificate_arn = aws_acm_certificate.agents.arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.agents_443.arn
  }
}

resource "aws_lb_target_group" "agents_80" {
  port     = 30000
  protocol = "TCP"
  vpc_id   = var.vpc.id

  depends_on = [
    aws_lb.agents
  ]
}
resource "aws_lb_target_group" "agents_443" {
  port     = 30001
  protocol = "TCP"
  vpc_id   = var.vpc.id

  depends_on = [
    aws_lb.agents
  ]
}

resource "aws_autoscaling_attachment" "agents_80" {
  autoscaling_group_name = aws_autoscaling_group.agents.name
  alb_target_group_arn   = aws_lb_target_group.agents_80.arn
}

resource "aws_autoscaling_attachment" "agents_443" {
  autoscaling_group_name = aws_autoscaling_group.agents.name
  alb_target_group_arn   = aws_lb_target_group.agents_443.arn
}

That's a cutdown version of my code.

I have configured my ingress controller to listen for HTTP and HTTPS on NodePorts 30000 and 30001 respectively. This works too.

The thing that doesn't work is that the NLB is terminating TLS, but I need it to passthrough. I'm doing this so that I can access Kubernetes Dashboard (among other apps), but the dashboard requires https to sign-in, something I can't provide if tls is terminated at the nlb.

I need help configuring the nlb for passthrough. I have searched and searched and can't find any examples. If anyone knows how to configure this it would be good to get some tf code, or even just an idea of the appropriate way of achieving it in AWS so that I can implement it myself in tf.


Solution

  • Do you need TLS passthrough, or just TLS communication between the NLB and the server? Or do you just need to configure your server to be aware that the initial connection was TLS?

    For TLS passthrough you would install an SSL certificate on the server, and delete the certificate from the load balancer. You would change the protocol of the port 443 listener on the load balancer from "TLS" to "TCP". This is not a very typical setup on AWS, and you can't use the free AWS ACM SSL certificates in this configuration, you would have to use something like Let's Encrypt on the server.

    For TLS communication between the NLB and the server, you would install a certificate on the server, a self-signed cert is fine for this, and then just change the target group settings on the load balancer to point to the secure ports on the server.

    If you just want to make the server aware that the initial connection protocol was TLS, you would configure the server to use the x-forwarded-proto header passed by the load balancer to determine if the connection is secure.