<p>I found a solution - not sure it's the best but it seems to work well enough for my case.</p>
<p>The solution is in three parts: first I added a variable to provide the default that works for most of my cases:</p>
<pre><code>variable &quot;default_lb_action&quot; {
  default = {
      &quot;production&quot;: {&quot;type&quot;: &quot;forward&quot;}
      &quot;staging&quot;: {&quot;type&quot;: &quot;forward&quot;}
  }
}
</code></pre>
<p>Then I added a new <code>local</code> like this:</p>
<pre><code> locals { 
   lb_default_action = {
      type = var.default_lb_action[local.environment].type
      target_group_arn = var.default_lb_action[local.environment].type == &quot;forward&quot; ? lookup(var.default_lb_action[local.environment], &quot;target_group_arn&quot;, aws_alb_target_group.group.arn) : null
      redirect = try(var.default_lb_action[local.environment].redirect, [])
    }
  }
</code></pre>
<p>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.</p>
<p>The last step is the load balancer listener definition itself, which now looks like this:</p>
<pre><code>resource &quot;aws_alb_listener&quot; &quot;listener_https&quot; {
  load_balancer_arn = aws_alb.alb.arn
  port = &quot;443&quot;
  protocol = &quot;HTTPS&quot;
  ssl_policy = &quot;ELBSecurityPolicy-FS-1-2-Res-2019-08&quot;
  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 &quot;redirect&quot; {
          for_each = local.lb_default_action.redirect
          iterator = redir
          content {
            host = redir.value[&quot;host&quot;]
            path = redir.value[&quot;path&quot;]
            port = redir.value[&quot;port&quot;]
            protocol = redir.value[&quot;protocol&quot;]
            query = redir.value[&quot;query&quot;]
            status_code = redir.value[&quot;status_code&quot;]
          }
      }
  }
}
</code></pre>
<p>The important bits here are that the <code>target_group_arn</code> can be null (if the <code>type</code> is not <code>&quot;forward&quot;</code>) and that the <code>redirect</code> block may be empty as well.</p>
<p>With the above, I can set a var like this and get the result I needed:</p>
<pre><code>default_lb_action = {
  production = {
    type = &quot;redirect&quot;
    redirect = [
      {
        host = &quot;www.example.com&quot;
        path = &quot;/#{path}&quot;
        port = &quot;#{port}&quot;
        protocol = &quot;HTTPS&quot;
        query = &quot;#{query}&quot;
        status_code = &quot;HTTP_301&quot;
      }]
  }
  staging = {&quot;type&quot;: &quot;forward&quot;}
}
</code></pre>
<p>Hope this helps somebody else!</p>

CC BY-SA 4.0
2021-08-16T15:40:08.400Z
2021-08-16T15:40:08.400Z
pgcd
<p>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.</p>
<p>To be more specific, this is what the common setup looks like</p>
<pre><code>  resource &quot;aws_alb_listener&quot; &quot;listener_https&quot; {
     load_balancer_arn = aws_alb.alb.arn
     port = &quot;443&quot;
     protocol = &quot;HTTPS&quot;
     ssl_policy = &quot;ELBSecurityPolicy-FS-1-2-Res-2019-08&quot;
     certificate_arn = data.aws_acm_certificate.main.arn
     default_action {
        target_group_arn = aws_alb_target_group.group.arn
        type = &quot;forward&quot;
     }
 }
</code></pre>
<p>but in a couple of cases I need the default action to be a redirect, rather than a forward.</p>
<p>I thought using a <code>dynamic &quot;default_action&quot;</code> 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).</p>
<p>I guess my question could also be generalized to &quot;(how) can I define all the values of a given resource as a single value and then apply them&quot; (equivalent to what I'd do in python by preparing a dict with the values I need and then creating the object with <code>**dict</code>)</p>

<terraform>
Making aws_lb_listener default_action dynamic
pgcd
# Making aws_lb_listener default_action dynamic

(Asked by: username_0 on 2021-08-16)

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)

**Tags:** terraform


---

## 1 answers

### Answer by username_0 on 2021-08-16. Score: 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!


---

