Bird
Raised Fist0
Terraformcloud~5 mins

Dynamic blocks in ingress rules in Terraform - Commands & Configuration

Choose your learning style10 modes available
Introduction
When you want to create multiple similar ingress rules in a security group, writing each rule manually can be repetitive and error-prone. Dynamic blocks in Terraform let you generate these rules automatically from a list, making your configuration cleaner and easier to manage.
When you have many ingress rules with similar structure but different ports or CIDRs.
When you want to update or add ingress rules by just changing a list instead of editing multiple blocks.
When you want to avoid repeating the same code for each ingress rule in your security group.
When you want to keep your Terraform code DRY (Don't Repeat Yourself) and easy to read.
When you need to manage ingress rules dynamically based on variable input or environment.
Config File - main.tf
main.tf
provider "aws" {
  region = "us-east-1"
}

variable "ingress_rules" {
  type = list(object({
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))
  default = [
    {
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  ]
}

resource "aws_security_group" "example" {
  name        = "example-sg"
  description = "Security group with dynamic ingress rules"
  vpc_id      = "vpc-12345678"

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

This Terraform file creates an AWS security group with multiple ingress rules generated dynamically.

  • variable "ingress_rules" defines a list of ingress rule objects with ports, protocol, and CIDR blocks.
  • dynamic "ingress" block loops over each rule in the list and creates an ingress rule for it.
  • The content inside the dynamic block sets the properties for each ingress rule.
  • There is a default egress rule allowing all outbound traffic.
  • Replace vpc-12345678 with your actual VPC ID.
Commands
This command initializes the Terraform working directory. It downloads the AWS provider plugin and prepares Terraform to run.
Terminal
terraform init
Expected OutputExpected
Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/aws... - Installing hashicorp/aws v4.0.0... - Installed hashicorp/aws v4.0.0 (signed by HashiCorp) Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work.
This command shows what Terraform will do before applying changes. It previews the creation of the security group with dynamic ingress rules.
Terminal
terraform plan
Expected OutputExpected
An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_security_group.example will be created + resource "aws_security_group" "example" { + description = "Security group with dynamic ingress rules" + id = (known after apply) + name = "example-sg" + vpc_id = "vpc-12345678" + ingress { + cidr_blocks = ["0.0.0.0/0"] + from_port = 80 + protocol = "tcp" + to_port = 80 } + ingress { + cidr_blocks = ["0.0.0.0/0"] + from_port = 443 + protocol = "tcp" + to_port = 443 } + egress { + cidr_blocks = ["0.0.0.0/0"] + from_port = 0 + protocol = "-1" + to_port = 0 } } Plan: 1 to add, 0 to change, 0 to destroy.
This command applies the planned changes and creates the security group with the dynamic ingress rules automatically without asking for confirmation.
Terminal
terraform apply -auto-approve
Expected OutputExpected
aws_security_group.example: Creating... aws_security_group.example: Creation complete after 3s [id=sg-0a1b2c3d4e5f6g7h8] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
→
-auto-approve - Skips interactive approval prompt to apply changes immediately
This command displays the current state of the created resources, showing the security group and its dynamically created ingress rules.
Terminal
terraform show
Expected OutputExpected
aws_security_group.example: id = sg-0a1b2c3d4e5f6g7h8 name = example-sg description = Security group with dynamic ingress rules vpc_id = vpc-12345678 ingress { from_port = 80 to_port = 80 protocol = tcp cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 443 to_port = 443 protocol = tcp cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = -1 cidr_blocks = ["0.0.0.0/0"] }
Key Concept

If you remember nothing else from this pattern, remember: dynamic blocks let you create multiple similar resource blocks from a list, keeping your Terraform code clean and easy to update.

Common Mistakes
Writing multiple ingress blocks manually instead of using a dynamic block.
This causes repetitive code that is hard to maintain and update.
Use a dynamic block with a list variable to generate ingress rules automatically.
Forgetting to use ingress.value inside the dynamic block content.
Terraform will not know which values to use for each ingress rule, causing errors.
Always reference the current item with ingress.value inside the dynamic block.
Not defining the variable type correctly for the list of ingress rules.
Terraform will fail to validate the input and may produce confusing errors.
Define the variable as a list of objects with the correct attributes and types.
Summary
Define a variable list with ingress rule details like ports, protocol, and CIDR blocks.
Use a dynamic block in the security group resource to loop over the list and create ingress rules.
Run terraform init, plan, and apply to create the security group with all rules automatically.

Practice

(1/5)
1. What is the main purpose of using dynamic blocks in Terraform ingress rules?
easy
A. To define a single static ingress rule
B. To encrypt ingress rule data
C. To delete existing ingress rules automatically
D. To create multiple similar ingress rules without repeating code

Solution

  1. Step 1: Understand what dynamic blocks do

    Dynamic blocks allow repeating a block multiple times based on a list or map, avoiding code repetition.
  2. Step 2: Apply this to ingress rules

    Ingress rules often need multiple similar blocks; dynamic blocks generate these efficiently.
  3. Final Answer:

    To create multiple similar ingress rules without repeating code -> Option D
  4. Quick Check:

    Dynamic blocks = multiple similar blocks [OK]
Hint: Dynamic blocks repeat blocks from lists or maps [OK]
Common Mistakes:
  • Thinking dynamic blocks delete rules
  • Confusing dynamic with static blocks
  • Assuming dynamic blocks encrypt data
2. Which of the following is the correct syntax to start a dynamic block named ingress in Terraform?
easy
A. dynamic "ingress" { for_each = var.rules { content { ... } } }
B. dynamic ingress { for_each = var.rules { content { ... } } }
C. dynamic "ingress" { for_each = var.rules content { ... } }
D. dynamic ingress { for_each = var.rules content { ... } }

Solution

  1. Step 1: Recall dynamic block syntax

    Dynamic blocks require the block type as a quoted string, e.g., dynamic "ingress".
  2. Step 2: Check for correct placement of for_each and content

    for_each is assigned outside braces, and content block is inside the dynamic block.
  3. Final Answer:

    dynamic "ingress" { for_each = var.rules content { ... } } -> Option C
  4. Quick Check:

    Dynamic block syntax uses quotes and for_each outside braces [OK]
Hint: Use quotes around block type and place for_each before content [OK]
Common Mistakes:
  • Omitting quotes around block type
  • Placing for_each inside braces incorrectly
  • Using braces incorrectly around for_each
3. Given the Terraform snippet:
variable "rules" {
  default = [
    { from_port = 80, to_port = 80, protocol = "tcp" },
    { from_port = 443, to_port = 443, protocol = "tcp" }
  ]
}

resource "aws_security_group" "example" {
  name = "example"

  dynamic "ingress" {
    for_each = var.rules
    content {
      from_port   = each.value.from_port
      to_port     = each.value.to_port
      protocol    = each.value.protocol
      cidr_blocks = ["0.0.0.0/0"]
    }
  }
}

How many ingress rules will be created?
medium
A. 2
B. 0
C. 1
D. 3

Solution

  1. Step 1: Count elements in var.rules

    var.rules contains 2 map elements, each with from_port, to_port, protocol.
  2. Step 2: Understand dynamic block behavior

    Dynamic block creates one ingress block per element in var.rules, so 2 ingress blocks.
  3. Final Answer:

    2 -> Option A
  4. Quick Check:

    List length = 2 ingress rules created [OK]
Hint: Count list items in for_each to find block count [OK]
Common Mistakes:
  • Counting only one rule
  • Assuming dynamic block creates zero rules
  • Miscounting list elements
4. Identify the error in this Terraform dynamic block snippet for ingress rules:
dynamic "ingress" {
  for_each = var.rules
  content = {
    from_port   = each.value.from_port
    to_port     = each.value.to_port
    protocol    = each.value.protocol
    cidr_blocks = ["0.0.0.0/0"]
  }
}
medium
A. Incorrect use of '=' after content instead of block
B. Missing quotes around "ingress"
C. for_each should be inside content block
D. cidr_blocks must be a string, not a list

Solution

  1. Step 1: Check dynamic block syntax for content

    The content block should be a block, not assigned with '='. Using '=' causes syntax error.
  2. Step 2: Verify other parts

    Quotes around "ingress" are present; for_each is correctly outside content; cidr_blocks accepts list.
  3. Final Answer:

    Incorrect use of '=' after content instead of block -> Option A
  4. Quick Check:

    content is a block, not an assignment [OK]
Hint: Use block syntax for content, not '=' assignment [OK]
Common Mistakes:
  • Using '=' after content instead of block braces
  • Placing for_each inside content
  • Omitting quotes around block type
5. You want to create ingress rules dynamically but only for rules where from_port is greater than 1000. Which Terraform expression correctly filters var.rules for use in a dynamic block's for_each?
hard
A. for_each = [for r in var.rules : r if r.from_port > 1000]
B. for_each = { for idx, r in var.rules : idx => r if r.from_port > 1000 }
C. for_each = filter(var.rules, r => r.from_port > 1000)
D. for_each = { for r in var.rules : r.from_port => r if r.from_port > 1000 }

Solution

  1. Step 1: Understand for_each type requirements

    for_each expects a map or set of strings; using a map with keys is preferred for dynamic blocks.
  2. Step 2: Analyze each option

    A returns a list, which is invalid for for_each in dynamic blocks. B uses r.from_port as key, which may duplicate keys. C uses filter function which is invalid syntax in Terraform. D creates a map with index keys filtered by condition, valid and safe.
  3. Final Answer:

    for_each = { for idx, r in var.rules : idx => r if r.from_port > 1000 } -> Option B
  4. Quick Check:

    for_each needs map with unique keys filtered by condition [OK]
Hint: Use map comprehension with index keys and condition [OK]
Common Mistakes:
  • Using list instead of map for for_each
  • Using non-unique keys causing errors
  • Trying unsupported filter() function
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard