If Statements Inside Terraform Dynamic Blocks

Posted by Miguel Lopez on Tue 24 January 2023 in terraform

Technical Stack: AWS, Terraform 1.6.0+

Read: 5 minutes

Introduction

Dynamic blocks in Terraform allow you to conditionally generate nested blocks within resources. This feature is particularly useful when you need to create optional configurations based on input variables.

In this guide, we'll explore how to use dynamic blocks to implement conditional logic for the default_action block in the aws_lb_listener resource. By the end, you'll understand:

  • How to include multiple default_action blocks for the aws_lb_listener resource.
  • How to make an optional default_action block.
  • How to write an if-statement for default_action using a dynamic block.

If Statements Inside Dynamic Blocks

Dynamic blocks use the for_each argument to iterate over a collection. By combining for_each with a conditional expression, you can create if-statements to control whether a block is generated.

Basic Setup

// filepath: resources.tf
dynamic "default_action" {
  for_each = var.default_action_type == "authenticate-oidc" ? [1] : []
  content {
    # ...block content...
  }
}

In this example: - The for_each argument evaluates a conditional expression. - If the condition is true, the block is created with the specified content. - If the condition is false, the block is skipped.


Using If Statements for aws_lb_listener

Let's apply this concept to the aws_lb_listener resource. We'll create two optional default_action blocks: one for forward actions and another for authenticate-oidc actions.

Example Configuration

// filepath: resources.tf
resource "aws_lb_listener" "listener" {
  load_balancer_arn = aws_lb.application.arn

  port     = var.port
  protocol = var.protocol

  # Forward Action
  dynamic "default_action" {
    for_each = var.default_action_type == "forward" ? [1] : []
    content {
      type = "forward"
      forward {
        target_group_arn = var.target_group_arn
      }
    }
  }

  # Authenticate-OIDC Action
  dynamic "default_action" {
    for_each = var.default_action_type == "authenticate-oidc" ? [1] : []
    content {
      type = "authenticate-oidc"
      authenticate_oidc {
        authorization_endpoint              = lookup(var.authenticate_oidc, "authorization_endpoint")
        client_id                           = lookup(var.authenticate_oidc, "client_id")
        client_secret                       = lookup(var.authenticate_oidc, "client_secret")
        issuer                              = lookup(var.authenticate_oidc, "issuer")
        token_endpoint                      = lookup(var.authenticate_oidc, "token_endpoint")
        user_info_endpoint                  = lookup(var.authenticate_oidc, "user_info_endpoint")
        scope                               = lookup(var.authenticate_oidc, "scope", null)
        session_timeout                     = lookup(var.authenticate_oidc, "session_timeout", 2628000)
        authentication_request_extra_params = lookup(var.authenticate_oidc, "authentication_request_extra_params", null)
    }
  }
}

Input Variables

// filepath: variables.tf
variable "port" {
  default = 80
  type    = number
}

variable "protocol" {
  default = "HTTP"
  type    = string
}

variable "default_action_type" {
  description = "Type of Default Action"
  type        = string
}

variable "authenticate_oidc" {
  description = "OIDC configuration for authentication"
  type        = object({
    authorization_endpoint              = string
    client_id                           = string
    client_secret                       = string
    issuer                              = string
    token_endpoint                      = string
    user_info_endpoint                  = string
    scope                               = optional(string, null)
    session_timeout                     = optional(number, 2628000)
    authentication_request_extra_params = optional(map(string), null)
  })
}

variable "target_group_arn" {
  description = "ARN of the target group for forward action"
  type        = string
}

Explanation

  1. Dynamic Blocks: Each dynamic "default_action" block is conditionally created based on the value of var.default_action_type.
  2. Conditional Logic: The for_each argument evaluates whether the block should be created:
  3. If var.default_action_type == "forward", the forward block is created.
  4. If var.default_action_type == "authenticate-oidc", the authenticate-oidc block is created.
  5. Input Variables: The authenticate_oidc variable is defined as an object, making it easy to pass structured data for the OIDC configuration.

Best Practices for 2025

  1. Use Optional Attributes: Leverage optional attributes in variable definitions to simplify input handling.
  2. Validate Inputs: Use validation blocks in variables to ensure input values meet expected criteria.
  3. Modularize Configurations: Encapsulate dynamic blocks in reusable modules for better maintainability.

Conclusion

Dynamic blocks in Terraform provide a powerful way to implement conditional logic within resources. By combining for_each with conditional expressions, you can create flexible and reusable configurations.

This approach is particularly useful for creating optional blocks, such as the default_action blocks in the aws_lb_listener resource. Start using these patterns in your Terraform projects to simplify complex configurations and improve maintainability!