Search code examples
terraformterraform-provider-aws

Terraform: pass a list of security groups


I try to pass a list of security groups to create ec2 instance.

variables.tf

variable "parameters" {
  type = map(any)
}
terraform.tfvars.json
{
  "parameters": {
    "ami": "ami1234",
    "vpc_security_group_ids": "sg-1234,sg-wxyz"
  }
}

Note, teffaform does not allow to use list for security groups as it requires all element type of map be the same. So I have to use comma-separated string.

resource "aws_instance" "worker" {
  ...
  vpc_security_group_ids = ["${split(",",var.parameters.vpc_security_group_ids)}"]
}

I copy some online code to split the string, but terraform complains that the variable is only known after apply.


Solution

  • As I think you've already understood, the any in map(any) represents asking Terraform to automatically infer the element type of the map, and so Terraform will study the given value and automatically choose a single concrete type to replace any. In the case of your example here, the result would be map(string) because all of the values in your map are strings.

    However, the example you've described here appears to me to more suited to be an object type rather than a map. Maps are intended for arbitrary key/value pairs where all of the elements represent the same kind of thing and can therefore be of the same type. Object types are for describing a single thing that has multiple different properties of different types.

    Therefore I would suggest rewriting your type constraint to properly describe the data structure you're expecting, which seems to be the following based on context:

    variable "parameters" {
      type = object({
        ami                    = string
        vpc_security_group_ids = set(string)
      })
    }
    

    set(string) matches the provider's type constraint for vpc_security_group_ids in aws_instance, since security groups don't have any meaningful ordering when associated with an EC2 instance and so it wouldn't make sense to use a list.

    With this data type in place then you should be able to just assign the variable values directly, because they will already be of the expected types:

    resource "aws_instance" "worker" {
      ami                    = var.parameters.ami
      vpc_security_group_ids = var.parameters.vpc_security_group_ids
    }