I’m trying to add multiple rules to a cloudposse security group. Here is the relevant code:
module "subnets" {
source = "cloudposse/dynamic-subnets/aws"
version = "0.39.8"
vpc_id = module.vpc.vpc_id
igw_id = module.vpc.igw_id
cidr_block = module.vpc.vpc_cidr_block
availability_zones = local.az_names
# nat_gateway_enabled = true
context = module.this.context
}
module "sg" {
source = "cloudposse/security-group/aws"
version = "0.4.3"
attributes = ["primary"]
rules = [
{
key = "HTTP"
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = module.subnets.public_subnet_cidrs
self = null
description = "Allow HTTP from IPs in our public subnets (which includes the ALB)"
},
{
key = "SSH"
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
self = null
description = "Allow SSH from all IPs"
}
]
vpc_id = module.vpc.vpc_id
context = module.this.context
}
This is failing with:
Error: Invalid value for module argument The given value is not suitable for child module variable “rules” defined at .terraform/modules/project_module.sg/variables.tf:60,1-17: element types must all match for conversion to list.
And the problem is the cidr_blocks
. If I replace the first one with ["0.0.0.0/0"]
it works. I see that the output from the aws-dynamic-subnets
module is aws_subnet.public.*.cidr_block
. The current value of the cidr_blocks
variable in the resource is ["172.16.96.0/19", "172.16.128.0/19"]
, which sure looks like a list of strings to me. When I open terraform console
and ask for the type of public_subnet_cidrs
, I just get dynamic
. I’ve tried wrapping the output in tolist()
and adding an empty string to the cidr_blocks array (to create lists of the same length) in the second ingress rule, but neither changes the error.
I have successfully worked around this issue by using a rule_matrix
for the HTTP rule and then also defining rules
with a single rule dictionary for the SSH rule, but this feels rather hacky.
What am I doing wrong?
You can use rule_maps
, instead of rules
:
module "sg" {
source = "cloudposse/security-group/aws"
version = "0.4.3"
attributes = ["primary"]
rules_map = {
"HTTP" = [{
key = "HTTP"
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = module.subnets.public_subnet_cidrs
self = null
description = "Allow HTTP from IPs in our public subnets (which includes the ALB)"
}],
"SSH" = [{
key = "SSH"
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
self = null
description = "Allow SSH from all IPs"
}
]
}
vpc_id = module.vpc.vpc_id
context = module.this.context
}
This is a little bit cleaner then using both rules
and rule_matrix
. Also I'm not sure why just using rules
does not work. I guess it does some inner processing of cidr_blocks
, and expects them to be exactly same type (list with 3 non-empty string elements).