1

I use Terraform a mostly uniform group of servers - EC2, S3 etc. This works reasonably well, except we need to have rather different actions for the load balancers depending on the specific group, and I can't figure out how to do it.

To be more specific, this is what the common setup looks like

  resource "aws_alb_listener" "listener_https" {
     load_balancer_arn = aws_alb.alb.arn
     port = "443"
     protocol = "HTTPS"
     ssl_policy = "ELBSecurityPolicy-FS-1-2-Res-2019-08"
     certificate_arn = data.aws_acm_certificate.main.arn
     default_action {
        target_group_arn = aws_alb_target_group.group.arn
        type = "forward"
     }
 }

but in a couple of cases I need the default action to be a redirect, rather than a forward.

I thought using a dynamic "default_action" block could help, but I can't seem to find a way to set both the name of the fields and the value (which could mean it's not the correct approach, in which case I'd love to know what the correct one is).

I guess my question could also be generalized to "(how) can I define all the values of a given resource as a single value and then apply them" (equivalent to what I'd do in python by preparing a dict with the values I need and then creating the object with **dict)

0

I found a solution - not sure it's the best but it seems to work well enough for my case.

The solution is in three parts: first I added a variable to provide the default that works for most of my cases:

variable "default_lb_action" {
  default = {
      "production": {"type": "forward"}
      "staging": {"type": "forward"}
  }
}

Then I added a new local like this:

 locals { 
   lb_default_action = {
      type = var.default_lb_action[local.environment].type
      target_group_arn = var.default_lb_action[local.environment].type == "forward" ? lookup(var.default_lb_action[local.environment], "target_group_arn", aws_alb_target_group.group.arn) : null
      redirect = try(var.default_lb_action[local.environment].redirect, [])
    }
  }

Please note that I've left the option to explicitly declare a target_group_arn, which may or may not be a requirement, and that redirect defaults to an empty list.

The last step is the load balancer listener definition itself, which now looks like this:

resource "aws_alb_listener" "listener_https" {
  load_balancer_arn = aws_alb.alb.arn
  port = "443"
  protocol = "HTTPS"
  ssl_policy = "ELBSecurityPolicy-FS-1-2-Res-2019-08"
  certificate_arn = data.aws_acm_certificate.main.arn
  default_action {
      type = local.lb_default_action.type
      target_group_arn = local.lb_default_action.target_group_arn
      dynamic "redirect" {
          for_each = local.lb_default_action.redirect
          iterator = redir
          content {
            host = redir.value["host"]
            path = redir.value["path"]
            port = redir.value["port"]
            protocol = redir.value["protocol"]
            query = redir.value["query"]
            status_code = redir.value["status_code"]
          }
      }
  }
}

The important bits here are that the target_group_arn can be null (if the type is not "forward") and that the redirect block may be empty as well.

With the above, I can set a var like this and get the result I needed:

default_lb_action = {
  production = {
    type = "redirect"
    redirect = [
      {
        host = "www.example.com"
        path = "/#{path}"
        port = "#{port}"
        protocol = "HTTPS"
        query = "#{query}"
        status_code = "HTTP_301"
      }]
  }
  staging = {"type": "forward"}
}

Hope this helps somebody else!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.