🐶
Terraform

Terraform Conditional Attributes: A Complete Guide

By Filip on 10/07/2024

Learn how to use conditional attributes in Terraform to create dynamic and flexible infrastructure deployments based on specific conditions and variables.

Terraform Conditional Attributes: A Complete Guide

Table of Contents

Introduction

Terraform offers powerful ways to manage your infrastructure, but it doesn't allow you to directly use conditions to control if an attribute exists or not within a resource block. However, you can still implement conditional logic effectively using alternative Terraform features. Let's explore four common methods and important factors to consider.

Step-by-Step Guide

Terraform doesn't directly support conditional attributes within resource blocks. You can't have an attribute appear or disappear based on a variable's value directly. However, you can achieve conditional logic using other Terraform constructs:

1. Conditional Expressions:

  • Use the ternary operator (condition ? true_val : false_val) to dynamically set an attribute's value.
    resource "example_resource" "example" {
      attribute = var.condition ? "value_if_true" : "value_if_false"
    }

2. Dynamic Blocks:

  • For blocks within resources (like lifecycle_rule in aws_s3_bucket), use dynamic blocks with a for_each loop.
    resource "aws_s3_bucket" "example" {
      # ...
    
      dynamic "lifecycle_rule" {
        for_each = var.enable_lifecycle_rules ? [1] : []
        content {
          # ... lifecycle rule configuration
        }
      }
    }
    • If var.enable_lifecycle_rules is true, the lifecycle_rule block is created; otherwise, it's omitted.

3. Conditional Objects and for_each:

  • Define a local variable as a map, conditionally populating it based on your criteria.
    locals {
      eventbridge_rules = {
        rule_one = {
          name              = "rule_one"
          schedule_expression = "cron(12 30 * * ? *)"
        }
        rule_two = {
          name = "rule_two"
          # No schedule_expression here
        }
        rule_three = {
          name              = "rule_three"
          schedule_expression = var.enable_rule_three ? "cron(0 * * * ? *)" : null
        }
      }
    }
    
    resource "aws_cloudwatch_event_rule" "schedule" {
      for_each = local.eventbridge_rules
      name              = each.value.name
      schedule_expression = each.value.schedule_expression
    }
    • The schedule_expression for rule_three is set based on var.enable_rule_three.

4. Conditional Modules:

  • Use the count or for_each meta-arguments to conditionally include entire modules.
    module "optional_module" {
      source = "./module-path"
      # ... module inputs
      count = var.enable_module ? 1 : 0
    }

Important Considerations:

  • Planning and State: Terraform's planning phase is affected by these techniques. Changes in conditions can lead to resource recreation.
  • Null Values: Be mindful of attributes that don't accept null. Use empty strings or other appropriate defaults.
  • Readability: Choose the approach that maintains the clarity and readability of your Terraform code.

Code Example

This code provides examples of using conditional logic in Terraform to manage resources dynamically. It demonstrates using conditional expressions for simple decisions, dynamic blocks for optional resource attributes, conditional objects and for_each for iterating over varying data structures, and conditional modules for including or excluding entire infrastructure components based on conditions. These techniques offer flexibility in defining infrastructure that adapts to different environments or requirements.

This code demonstrates the techniques described in the article for implementing conditional logic in Terraform.

1. Conditional Expressions:

variable "create_database" {
  type = bool
  default = false
}

resource "aws_rds_instance" "example" {
  # ... other RDS instance configurations

  # Conditionally create the database
  db_name = var.create_database ? "my_database" : null
}

2. Dynamic Blocks:

variable "enable_logging" {
  type = bool
  default = false
}

resource "aws_s3_bucket" "example" {
  # ... other S3 bucket configurations

  dynamic "logging" {
    for_each = var.enable_logging ? [1] : []
    content {
      target_bucket = aws_s3_bucket.log_bucket.id
      target_prefix = "logfiles/"
    }
  }
}

3. Conditional Objects and for_each:

variable "enable_rule_two" {
  type = bool
  default = false
}

locals {
  iam_roles = {
    role_one = {
      name = "role_one"
      policy_arns = ["arn:aws:iam::aws:policy/AmazonS3FullAccess"]
    }
    role_two = {
      name = "role_two"
      policy_arns = var.enable_rule_two ? ["arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"] : []
    }
  }
}

resource "aws_iam_role" "example" {
  for_each = local.iam_roles
  name = each.value.name
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "example" {
  for_each = { for role in local.iam_roles : role.name => role }
  role       = aws_iam_role.example[each.key].name
  policy_arn = each.value.policy_arns[0]
}

4. Conditional Modules:

variable "create_vpc" {
  type = bool
  default = false
}

module "vpc" {
  source = "./modules/vpc"
  # ... module inputs
  count = var.create_vpc ? 1 : 0
}

These examples illustrate how to conditionally manage resources and configurations in Terraform using various techniques. Remember to choose the approach that best suits your specific needs and maintains the readability of your code.

Additional Notes

  • Understanding the Limitations: While these methods provide workarounds, remember that Terraform fundamentally evaluates resource presence during the planning stage. This means changes in conditions can lead to resource replacement, not just attribute modification.
  • Prioritizing Readability: As your infrastructure codebase grows, maintaining clarity is crucial. Choose the conditional logic approach that best balances conciseness with understandability for future maintainers (including yourself!).
  • Testing is Key: Due to the potential for resource recreation, thoroughly test your Terraform code with different variable combinations to ensure your infrastructure behaves as expected in various scenarios.
  • Exploring Alternatives: For highly complex conditional scenarios, consider if your use case might be better served by tools designed for orchestration and dynamic provisioning, potentially in conjunction with Terraform.
  • Terraform Version Awareness: Always consult the documentation for the specific Terraform version you're using, as features and syntax can evolve over time.

By understanding these nuances and carefully applying the techniques described, you can effectively manage conditional logic within your Terraform projects and build flexible, adaptable infrastructure.

Summary

Terraform doesn't allow attributes to appear conditionally within resource blocks. However, you can achieve conditional logic using these methods:

| Technique | Description

Conclusion

While Terraform doesn't directly support conditional attributes within resource blocks, you can achieve conditional logic effectively using techniques like conditional expressions, dynamic blocks, conditional objects with for_each, and conditional modules. Each approach offers a unique way to manage resources and configurations dynamically based on variables or conditions. When implementing these workarounds, it's crucial to consider their impact on Terraform's planning phase and potential resource recreation. Always prioritize the readability of your code and thoroughly test your configurations to ensure your infrastructure behaves as expected in different scenarios. By understanding these nuances and choosing the appropriate method for your use case, you can leverage Terraform's flexibility to build robust and adaptable infrastructure.

References

  • How to set a Resource attribute conditionally? : r/Terraform How to set a Resource attribute conditionally? : r/Terraform | Posted by u/phillycheeze - 3 votes and 2 comments
  • Variable Attribute Key Conditional - Terraform - HashiCorp Discuss Variable Attribute Key Conditional - Terraform - HashiCorp Discuss | Is there a way of making a variable attribute key conditional? For example, when declaring several EventBridge scheduled rules can the schedule_expression have a default value if not declared: local.tfvars eventbridge = { rule_one = { name = "rule_one" schedule_expression = "cron(12 30 * * ? *)" } rule_two = { name = "rule_two" } rule_three = { name = "rule_three" } } main.tf resource "aws_cloudwatch_event_rule" "schedule" { for_each = local.eventbridge name = each.value["name"] schedule_e...
  • Conditional block with required attribute, if declared : r/Terraform Conditional block with required attribute, if declared : r/Terraform | Posted by u/Athlon77 - 3 votes and 4 comments
  • Creating a Conditional Object - Terraform - HashiCorp Discuss Creating a Conditional Object - Terraform - HashiCorp Discuss | I have a module defined for an EKS cluster using the AWS EKS module, and I am trying to conditionally create a gpu-specific managed node group depending on the cluster. I have no idea if this is even feasible, I know conditionals within Terraform are classically limiting and frustrating. Here is what I have so far (invalid), but it gets the point across for what I’m trying to do which is conditionally create the gpu managed node group. module "eks" { source = "terraform-aws-modules/eks/aws"...
  • Conditional Expressions - Configuration Language | Terraform ... Conditional Expressions - Configuration Language | Terraform ... | The two result values may be of any type, but they must both be of the same type so that Terraform can determine what type the whole conditional expression will ...
  • Terrarform cdk condition based on attributes - CDK for Terraform ... Terrarform cdk condition based on attributes - CDK for Terraform ... | Hello , I am attempting to assign a value to the ‘userData’ attribute while incorporating conditions that determine the specific value to be assigned. I aim to express these conditions in the same line as the assignment statement: userData: conditional(Op.neq(platform,“windows”),linuxScripts,windowsScripts ) , these are my vars : const windowsScripts= fs.readFileSync(‘…/scripts/user-data.ps1’,‘utf-8’) ; const linuxScripts=fs.readFileSync(‘…/scripts/user-data.sh’,‘utf-8’) ; and i got “T...
  • How to Use Terraform Conditional Expressions How to Use Terraform Conditional Expressions | What is a Terraform conditional? See how to use these operators to create resources, deploy modules, and other usage examples.
  • Ability to Conditionally Mark Schema Attributes Sensitive · Issue ... Ability to Conditionally Mark Schema Attributes Sensitive · Issue ... | Please Note: This issue is being submitted in the absence of an existing one I could find and meant more for gathering other use cases and/or showing an explicit decision on the subject. Especially...
  • Creating Nested Conditional Dynamic Terraform Blocks ... Creating Nested Conditional Dynamic Terraform Blocks ... | While working on an assignment to update the AWS Cognito User Pool for the team that I’ve built using Terraform, I faced a problem where the software development team is working on revising c…

Were You Able to Follow the Instructions?

😍Love it!
😊Yes
😐Meh-gical
😞No
🤮Clickbait