1

In Terraform, how can access the values from the variable below?

variable "egress_rules" {
  type = list(object({
    from_port = number
    to_port = number
    protocol = string
    cidr_blocks = list(string)
  }))
  default = [
    {
      from_port = 0
      to_port = 0
      protocol = "-1"
      cidr_blocks = ["0.0.0.0/0"]
    }
  ]
}

I tried:

resource "aws_security_group_rule" "egress" {
  security_group_id = aws_security_group.new.id
  type = "ingress"
  for_each = var.egress_rules
    from_port   = each.value.from_port
    to_port     = each.value.to_port
    protocol    = each.value.protocol
    cidr_blocks = each.value.cidr_blocks
}

But got this error:

Error: Invalid for_each argument

What is the correct way to reference this variable?

2
  • 2
    For for_each uses ingress_rules, but your variable is egress_rules? Commented Jan 9, 2021 at 0:54
  • My bad @Marcin I copied the wrong example Commented Jan 9, 2021 at 5:22

3 Answers 3

3

for_each will not work with a list of maps. You have to convert it to a map. This is commonly done through a for expression:

resource "aws_security_group_rule" "egress" {
  security_group_id = aws_security_group.new.id
  type = "ingress"
  for_each = { for idx, rule in var.egress_rules: idx => rule }
    from_port   = each.value.from_port
    to_port     = each.value.to_port
    protocol    = each.value.protocol
    cidr_blocks = each.value.cidr_blocks
}
Sign up to request clarification or add additional context in comments.

Comments

0

Adding to above answer from @Marcin

If you want to use single object instead of list then you can directly access without for_each

Instead of declaring it as list of objects; use single object as shown below

variable "egress_rules" {
  type = object({
    from_port = number
    to_port = number
    protocol = string
    cidr_blocks = list(string)
  })
  default = ({
      from_port = 0
      to_port = 0
      protocol = "-1"
      cidr_blocks = ["0.0.0.0/0"]
    }}
}

Then access in your resource like

resource "aws_security_group_rule" "egress" {
  security_group_id = aws_security_group.new.id
  from_port   = var.egress_rules.from_port
  to_port     = var.egress_rules.from_port
  protocol    = var.egress_rules.protocol
  cidr_blocks = var.egress_rules.cidr_blocks
}

Comments

-1

to set multiple properties of a resource you could use a map of objects like this:

variable "egress_rules" {
  type = map(object({
    from_port = number
    to_port = number
    protocol = string
    cidr_blocks = list(string)
  }))
}

Your variable definition would be:

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

The updated resource definition would be:

resource "aws_security_group_rule" "egress" {
  security_group_id = aws_security_group.new.id
  type = "egress"
  for_each = var.egress_rules
    from_port   = each.value["from_port"]
    to_port     = each.value["to_port"]
    protocol    = each.valuep["protocol"]
    cidr_blocks = each.value["cidr_blocks"]
}

2 Comments

Your example of egress_rules does not match its type. Also what is ingress_rules if you define egress_rules? Also there is a spelling mistake in valuep?
This default value is not compatible with the variable's type constraint: map of object required.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.