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_actionblocks for theaws_lb_listenerresource. - How to make an optional
default_actionblock. - How to write an if-statement for
default_actionusing 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_eachargument 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_oidcvariable is defined as an object, making it easy to pass structured data for the OIDC configuration.
Best Practices for 2025
- Use Optional Attributes: Leverage
optionalattributes in variable definitions to simplify input handling. - Validate Inputs: Use
validationblocks 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!