Terraform Conditions
Loading...
Conditions
Conditions in Terraform allow you to control the creation of resources based on the evaluation of an expression. This can be useful when you need to create resources conditionally based on the state of other resources or variables.
The syntax of a conditional expression is as follows:
1condition ? true_val : false_valExplanation:
condition: The expression that is evaluated to determine the result.true_val: The value returned if the condition is true.false_val: The value returned if the condition is false.
The syntax of a conditional multiple nested expressions is as follows:
1condition1 ? condition2 ? true_val2 : false_val2 : false_val1Explanation:
condition1: The first expression that is evaluated to determine the result.condition2: The second expression that is evaluated if the first condition is true.true_val2: The value returned if the second condition is true.false_val2: The value returned if the second condition is false.false_val1: The value returned if the first condition is false.
Best Practices
Use Conditions Sparingly
Conditions can make your code harder to read and maintain. Use them sparingly and only when necessary. If you find yourself using conditions frequently, consider refactoring your code to make it more readable.
Use Variables
Use variables to store the condition values. This makes it easier to change the condition values without modifying the code.
The following example shows how to use variables to store the condition values:
1variable "instance_enable" {2 type = bool3 description = "(Required) Whether to create an instance. Set to false to prevent the instance from being created."4 default = false5}6
7resource "aws_instance" "example" {8 count = var.instance_enable ? 1 : 09 # ...10}Explanation:
instance_enable: A variable that stores the condition value.aws_instance.example: The resource that is created conditionally based on the value of theinstance_enablevariable.
Use Local Values
If you find yourself using conditions frequently in your code, consider using local values to simplify the code. Local values allow you to define a value that is calculated based on other values in your code.
The following example shows how to use local values to simplify the code:
1variable "subnet_cidr_block" {2 type = string3 description = "(Optional) The IPv4 CIDR block for the subnet."4 default = ""5}6
7locals {8 subnet_cidr_block = var.subnet_cidr_block != "" ? var.subnet_cidr_block : null9}10
11resource "aws_subnet" "example" {12 vpc_id = "vpc-12345678"13 cidr_block = local.subnet_cidr_block14 # ...15}Explanation:
subnet_cidr_block: A variable that stores the CIDR block for the subnet.subnet_cidr_block: A local value that calculates the value of the CIDR block based on the value of thesubnet_cidr_blockvariable.aws_subnet.example: The resource that is created conditionally based on the value of thesubnet_cidr_blocklocal value.
Use Conditions in Dynamic Block
You can use conditions in dynamic blocks to create resources conditionally. This can be useful when you need to create multiple resources based on the evaluation of an expression.
The following example shows how to use conditions in dynamic blocks:
1variable "security_group_ingress" {2 type = list(object({3 from_port = number4 to_port = number5 protocol = string6 cidr_blocks = optional(list(string))7 ipv6_cidr_blocks = optional(list(string))8 security_groups = optional(list(string))9 prefix_list_ids = optional(list(string))10 description = optional(string)11 self = optional(bool)12 }))13 description = <<EOF14 (Optional, VPC only) Configuration block for egress rules. Can be specified multiple times for each egress rule. Each egress block supports fields documented below. This argument is processed in attribute-as-blocks mode. This argument is processed in attribute-as-blocks mode.15
16 The following arguments are required:17
18 from_port - (Required) Start port (or ICMP type number if protocol is icmp or icmpv6).19 to_port - (Required) End range port (or ICMP code if protocol is icmp).20 protocol - (Required) Protocol. If you select a protocol of -1 (semantically equivalent to all, which is not a valid value here), you must specify a from_port and to_port equal to 0. The supported values are defined in the IpProtocol argument on the IpPermission API reference. This argument is normalized to a lowercase value to match the AWS API requirement when using with Terraform 0.12.x and above, please make sure that the value of the protocol is specified as lowercase when using with older version of Terraform to avoid an issue during upgrade.21 cidr_blocks - (Optional) List of CIDR blocks.22 description - (Optional) Description of this ingress rule.23 ipv6_cidr_blocks - (Optional) List of IPv6 CIDR blocks.24 prefix_list_ids - (Optional) List of Prefix List IDs.25 security_groups - (Optional) List of security groups. A group name can be used relative to the default VPC. Otherwise, group ID.26 self - (Optional) Whether the security group itself will be added as a source to this ingress rule.27 EOF28 default = [{29 cidr_blocks = [""]30 from_port = 031 to_port = 032 protocol = "-1"33 }]34}35variable "security_group_egress" {36 type = list(object({37 from_port = number38 to_port = number39 protocol = string40 cidr_blocks = optional(list(string))41 ipv6_cidr_blocks = optional(list(string))42 security_groups = optional(list(string))43 prefix_list_ids = optional(list(string))44 description = optional(string)45 self = optional(bool)46 }))47 description = <<EOF48 (Optional) Configuration block for ingress rules. Can be specified multiple times for each ingress rule. Each ingress block supports fields documented below. This argument is processed in attribute-as-blocks mode. This argument is processed in attribute-as-blocks mode.49
50 The following arguments are required:51
52 from_port - (Required) Start port (or ICMP type number if protocol is icmp)53 to_port - (Required) End range port (or ICMP code if protocol is icmp).54 protocol - (Required) Protocol. If you select a protocol of -1 (semantically equivalent to all, which is not a valid value here), you must specify a from_port and to_port equal to 0. The supported values are defined in the IpProtocol argument in the IpPermission API reference. This argument is normalized to a lowercase value to match the AWS API requirement when using Terraform 0.12.x and above. Please make sure that the value of the protocol is specified as lowercase when used with older version of Terraform to avoid issues during upgrade.55 cidr_blocks - (Optional) List of CIDR blocks.56 description - (Optional) Description of this egress rule.57 ipv6_cidr_blocks - (Optional) List of IPv6 CIDR blocks.58 prefix_list_ids - (Optional) List of Prefix List IDs.59 security_groups - (Optional) List of security groups. A group name can be used relative to the default VPC. Otherwise, group ID.60 self - (Optional) Whether the security group itself will be added as a source to this egress rule.61 EOF62 default = null63}Explanation:
security_group_ingress: A variable that stores the configuration block for ingress rules.security_group_egress: A variable that stores the configuration block for egress rules.
1resource "aws_security_group" "this" {2 count = var.security_group_enable ? 1 : 03
4 ...5
6 dynamic "ingress" {7 iterator = ingress8 for_each = can(length(var.security_group_ingress)) ? var.security_group_ingress : []9
10 content {11 cidr_blocks = lookup(ingress.value, "cidr_blocks", null)12 ipv6_cidr_blocks = lookup(ingress.value, "ipv6_cidr_blocks", null)13 prefix_list_ids = lookup(ingress.value, "prefix_list_ids", null)14 security_groups = lookup(ingress.value, "security_groups", null)15 description = lookup(ingress.value, "description", null)16 from_port = lookup(ingress.value, "from_port", null)17 to_port = lookup(ingress.value, "to_port", null)18 protocol = lookup(ingress.value, "protocol", null)19 self = lookup(ingress.value, "self", null)20 }21 }22
23 dynamic "egress" {24 iterator = egress25 for_each = can(length(var.security_group_egress)) ? var.security_group_egress : []26
27 content {28 cidr_blocks = lookup(egress.value, "cidr_blocks", null)29 ipv6_cidr_blocks = lookup(egress.value, "ipv6_cidr_blocks", null)30 prefix_list_ids = lookup(egress.value, "prefix_list_ids", null)31 security_groups = lookup(egress.value, "security_groups", null)32 description = lookup(egress.value, "description", null)33 from_port = lookup(egress.value, "from_port", null)34 to_port = lookup(egress.value, "to_port", null)35 protocol = lookup(egress.value, "protocol", null)36 self = lookup(egress.value, "self", null)37 }38 }39
40 ...41}Explanation:
aws_security_group.this: The resource that is created conditionally based on the value of thesecurity_group_enablevariable.dynamic "ingress": A dynamic block that creates ingress rules conditionally based on the value of thesecurity_group_ingressvariable.dynamic "egress": A dynamic block that creates egress rules conditionally based on the value of thesecurity_group_egressvariable.can()function: A function that checks if the length of the list is greater than zero.length()function: A function that returns the length of the list.lookup()function: A function that retrieves the value of the specified key from the map. If the key does not exist, it returns the default value.