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 theaws_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
- Dynamic Blocks: Each
dynamic "default_action"
block is conditionally created based on the value ofvar.default_action_type
. - Conditional Logic: The
for_each
argument evaluates whether the block should be created: - If
var.default_action_type == "forward"
, the forward block is created. - If
var.default_action_type == "authenticate-oidc"
, the authenticate-oidc block is created. - 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
- Use Optional Attributes: Leverage
optional
attributes in variable definitions to simplify input handling. - Validate Inputs: Use
validation
blocks in variables to ensure input values meet expected criteria. - 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!