I tried to create an AWS security group with multiple inbound rules, Normally we need to multiple ingresses in the sg for multiple inbound rules. Instead of creating multiple ingress rules separately, I tried to create a list of ingress and so that I can easily reuse the module for different applications.
PFB,
module/sg/sg.tf >>
resource "aws_security_group" "ec2_security_groups" {
name = var.name_security_groups
vpc_id = var.vpc_id
}
module/sg/rules.tf >>
resource "aws_security_group_rule" "ingress_rules" {
count = lenght(var.ingress_rules)
type = "ingress"
from_port = var.ingress_rules[count.index][0]
to_port = var.ingress_rules[count.index][1]
protocol = var.ingress_rules[count.index][2]
cidr_blocks = var.ingress_rules[count.index][3]
description = var.ingress_rules[count.index][4]
security_group_id = aws_security_group.ec2_security_groups.id
}
module/sg/variable.tf >>
variable "vpc_id" {
}
variable "name_security_groups" {
}
variable "ingress_rules" {
type = list(string)
}
In the application folder,
application/dev/sg.tf >>
module "sg_test" {
source = "../modules/sg"
vpc_id = "vpc-xxxxxxxxx"
name_security_groups = "sg_test"
ingress_rules = var.sg_ingress_rules
}
application/dev/variable.tf >>
variable "sg_ingress_rules" {
type = list(string)
default = {
[22, 22, "tcp", "1.2.3.4/32", "test"]
[23, 23, "tcp", "1.2.3.4/32", "test"]
}
}
Error:
Error: Missing attribute value
on test-sgs.tf line 21, in variable "sg_ingress_rules":
20:
21:
22:
Expected an attribute value, introduced by an equals sign ("=").
Please help to correct this or if there is any other method please suggest.
Regards,
Thanks#apparentlymart, who helped to solve this in Terraform discussion
The Security rule:-
resource "aws_security_group_rule" "ingress_rules" {
count = length(var.ingress_rules)
type = "ingress"
from_port = var.ingress_rules[count.index].from_port
to_port = var.ingress_rules[count.index].to_port
protocol = var.ingress_rules[count.index].protocol
cidr_blocks = [var.ingress_rules[count.index].cidr_block]
description = var.ingress_rules[count.index].description
security_group_id = aws_security_group.ec2_security_groups.id
}
And the variable:
variable "sg_ingress_rules" {
type = list(object({
from_port = number
to_port = number
protocol = string
cidr_block = string
description = string
}))
default = [
{
from_port = 22
to_port = 22
protocol = "tcp"
cidr_block = "1.2.3.4/32"
description = "test"
},
{
from_port = 23
to_port = 23
protocol = "tcp"
cidr_block = "1.2.3.4/32"
description = "test"
},
]
}
We can do this in a simple way:-
locals {
ports_in = [
443,
80
]
ports_out = [
0
]
}
resource "aws_security_group" "internet_facing_alb" {
name = "internetfacing-loadbalancer-sg"
description = "Security group attached to internet facing loadbalancer"
vpc_id = var.vpc_id
dynamic "ingress" {
for_each = toset(local.ports_in)
content {
description = "Web Traffic from internet"
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
dynamic "egress" {
for_each = toset(local.ports_out)
content {
description = "Web Traffic to internet"
from_port = egress.value
to_port = egress.value
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
tags = {
Name = "internetfacing-loadbalancer-sg"
}
}
If you want this to work literally with indexed fields, make it a list(list(string)) and change the default oyter syntax from braces (used for maps) to brackets (used for lists):
variable "sg_ingress_rules" {
type = list(list(string))
default = [
[22, 22, "tcp", "1.2.3.4/32", "test"]
[23, 23, "tcp", "1.2.3.4/32", "test"]
]
}
That is a confusing data structure and will be difficult to work with, so I recommend this instead:
variable "sg_ingress_rules" {
type = map(map(any))
default = {
thing1 = {from=22, to=22, proto="tcp", cidr="1.2.3.4/32", desc=test"]
thing2 = {from=23, to=23, proto="tcp", cidr="1.2.3.4/32", desc="test"}
}
}
You can use better names than the terrible ones I've chosen and then refer to them in your resource:
resource "aws_security_group_rule" "ingress_rules" {
for_each = var.ingress_rules
type = "ingress"
from_port = each.value.from
to_port = each.value.to
protocol = each.value.proto
cidr_blocks = each.value.cidr
description = each.value.desc
security_group_id = aws_security_group.ec2_security_groups.id
}
You'll get multiple named copies of the aws_security_group_rule which better survives insertions and deletions from the ingress_rules variable and will save you headaches. Otherwise you'll get superfluous destroys and creates of rules and sometimes conflicts due to the indexed resources a count creates.
If you are feeling like having some better guardrails on people setting the ingress_rules value you can use object to require and restrict to a particular set of fields with certain types as follows:
variable "sg_ingress_rules" {
type = map(object(
{
from = number
to = number
proto = string
cidr = string
desc = string
}
))
default = {
thing1 = {from=22, to=22, proto="tcp", cidr="1.2.3.4/32", desc=test"]
thing2 = {from=23, to=23, proto="tcp", cidr="1.2.3.4/32", desc="test"}
}
}
There is a new way to manage multiple ingress rules, with a new terraform resource, named aws_security_group_rule
it is better than the other ways, using Attributes as Blocks
Sample for reference
resource "aws_security_group_rule" "example" {
type = "ingress"
from_port = 0
to_port = 65535
protocol = "tcp"
cidr_blocks = [aws_vpc.example.cidr_block]
ipv6_cidr_blocks = [aws_vpc.example.ipv6_cidr_block]
security_group_id = "sg-123456"
}
Ref: aws_security_group_rule
The easiest way to implement multiple rules in a security group looks a bit like the following example:
resource "aws_security_group" "sg_my_security_group" {
name = "sg_my_security_group"
description = "Implements some security"
vpc_id = var.your_vpc_id
ingress {
from_port = 3889
to_port = 3889
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 3889
to_port = 3889
protocol = "udp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "does_something_important"
}
}
Related
My code will create security groups as well as ingress/egress as we give the list of security groups and rules in the dev.tfvars file
The code ran successfully but created security groups takes ingress/egress rules from all given security groups.
./security.tf
resource "aws_security_group" "sg" {
count = length(var.vpc_config.security_groups)
name = var.vpc_config.security_groups[count.index].name
description = var.vpc_config.security_groups[count.index].description
vpc_id = var.vpc_id
dynamic "ingress" {
for_each = var.vpc_config.security_groups
content {
from_port = ingress.value.ingress.from_port
to_port = ingress.value.ingress.to_port
protocol = ingress.value.ingress.protocol
cidr_blocks = ingress.value.ingress.cidr_block
}
}
dynamic "egress" {
for_each = var.vpc_config.security_groups
content {
from_port = egress.value.egress.from_port
to_port = egress.value.egress.to_port
protocol = egress.value.egress.protocol
cidr_blocks = egress.value.egress.cidr_block
}
}
tags = {
Name = var.vpc_config.security_groups[count.index].name
Environment = var.vpc_config.environment
}
}
./dev.tfvars
vpc_config = {
security_groups = [ {
name = "sg_1"
description = "security group 1"
ingress = {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_block = ["0.0.0.0/0"]
}
egress = {
from_port = 0
to_port = 0
protocol = "-1"
cidr_block = ["0.0.0.0/0"]
}
},
{
name = "sg_2"
description = "security group 2"
ingress = {
from_port = 21
to_port = 21
protocol = "tcp"
cidr_block = ["0.0.0.0/0"]
}
egress = {
from_port = 443
to_port = 443
protocol = "http"
cidr_block = ["0.0.0.0/0"]
}
}
]
}
It will create two security groups with one ingress and one egress each but it creates two security groups with two ingress and two egress each.
If your goal is to create a 2 security groups, each having a certain ingress and egress rules explicitly defined, you do not want to have dynamic blocks. With dynamic blocks, you will create an inner loop, which is not what you would want.
I recommend using only one for_each at the resource level and no dynamic blocks:
resource "aws_security_group" "sg" {
for_each = {
for sg in var.vpc_config.security_groups : sg.name => sg
}
name = each.value.name
description = each.value.description
vpc_id = var.vpc_id
ingress {
from_port = each.value.ingress.from_port
to_port = each.value.ingress.to_port
protocol = each.value.ingress.protocol
cidr_blocks = each.value.ingress.cidr_block
}
egress {
from_port = each.value.egress.from_port
to_port = each.value.egress.to_port
protocol = each.value.egress.protocol
cidr_blocks = each.value.egress.cidr_block
}
tags = {
Name = each.value.name
Environment = var.vpc_config.environment
}
}
If you want to use count, you can do it as follows:
resource "aws_security_group" "sg" {
count = length(var.vpc_config.security_groups)
name = var.vpc_config.security_groups[count.index].name
description = var.vpc_config.security_groups[count.index].description
vpc_id = var.vpc_id
ingress {
from_port = var.vpc_config.security_groups[count.index].ingress.from_port
to_port = var.vpc_config.security_groups[count.index].ingress.to_port
protocol = var.vpc_config.security_groups[count.index].ingress.protocol
cidr_blocks = var.vpc_config.security_groups[count.index].ingress.cidr_block
}
egress {
from_port = var.vpc_config.security_groups[count.index].egress.from_port
to_port = var.vpc_config.security_groups[count.index].egress.to_port
protocol = var.vpc_config.security_groups[count.index].egress.protocol
cidr_blocks = var.vpc_config.security_groups[count.index].egress.cidr_block
}
tags = {
Name = var.vpc_config.security_groups[count.index].name
Environment = var.vpc_config.environment
}
}
My main goal is to remove hardcoded ingress and egress configuration blocks from our aws_security_group resources in our terraforms modules. I instead want to pass in one ingress and one egress input variable containing all the ingress and egress rules.
Current aws_security_group creation:
# main.tf
resource "aws_security_group" "sg" {
name = "Example security group"
egress {
from_port = 123
to_port = 123
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 53
to_port = 53
protocol = "tcp"
security_groups = [local.some_sg_id]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
}
vpc_id = var.vpc_id
}
What i want to do:
# main.tf
resource "aws_security_group" "sg" {
name = "Example security group"
egress = var.sg_egress
ingress = var.sg_ingress
vpc_id = var.vpc_id
}
The issue is that the ingress and egress blocks have optional parameters.
I.E on one ingress statement i have specified "cidr_blocks" and on one "security_groups".
This makes it hard to create a variable statement for these blocks.
I have managed to get it to work using this:
# terragrunt.hcl
# Note: we use terragrunt, but in the example below think of this as terraform.tfvars
locals {
some_sg_id = "sg-123abc456"
sg_defaults = {
"security_groups" = []
"cidr_blocks" = []
"ipv6_cidr_blocks" = []
"prefix_list_ids" = []
"self" = false
"description" = ""
}
}
inputs = {
sg_egress [
merge(local.sg_defaults, {
from_port = 123
to_port = 123
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}),
merge(local.sg_defaults, {
from_port = 53
to_port = 53
protocol = "tcp"
security_groups = [local.some_sg_id]
})
]
sg_ingress [
merge(local.sg_defaults, {
from_port = 123
to_port = 123
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
})
]
}
# variables.tf
variable "sg_ingress" {
type = list(object({
cidr_blocks = list(string)
description = string
from_port = number
ipv6_cidr_blocks = list(string)
prefix_list_ids = list(string)
protocol = string
security_groups = list(string)
self = bool
to_port = number
}))
default = []
}
variable "sg_egress" {
type = list(object({
cidr_blocks = list(string)
description = string
from_port = number
ipv6_cidr_blocks = list(string)
prefix_list_ids = list(string)
protocol = string
security_groups = list(string)
self = bool
to_port = number
}))
default = []
}
Here i create default (empty) values for the optional attributes and then merge them with the values in the input variable. This creates input variables that have all attributes filled in, with empty values if none were specified. This way i can just create a variable statement with all values specified, but it's not a very pretty solution...
Dynamic blocks can probobly be used to accomplish this but so far my smooth brain have not been able to make it work with those..
I have seen this similar StackOverflow question, but it does not go over using optional attributes.
I'm trying to create a security group that will automatically append the cidr blocks from 2 subnets based from the data source filtered results. However I'm getting the error when deploying using terraform v12 variant
data "aws_vpc" "my-vpc" {
filter {
name = "tag:MY_VPC"
values = ["TRUE"]
}
}
data "aws_subnet_ids" "my-subnets" {
vpc_id = data.aws_vpc.my-vpc.id
filter {
name = "tag:NAME"
values = ["MY_SUBNET"]
}
}
resource "aws_security_group" "my-sg" {
name = "my-sg"
description = "my-sg"
vpc_id = data.aws_vpc.my-vpc.id
ingress {
from_port = 443
protocol = "tcp"
to_port = 443
cidr_blocks = ["${data.aws_subnet_ids.my-subnets.*.cidr_block}"]
}
ingress {
from_port = 22
protocol = "tcp"
to_port = 22
cidr_blocks = ["${data.aws_subnet_ids.my-subnets.*.cidr_block}"]
}
ingress {
from_port = 80
protocol = "tcp"
to_port = 80
cidr_blocks = ["${data.aws_subnet_ids.my-subnets.*.cidr_block}"]
}
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["${data.aws_subnet_ids.my-subnets.*.cidr_block}"]
}
}
ERROR Im getting
on terraform/my-sg.tf line 27, in resource "aws_security_group" "my-sg":
31: cidr_blocks = ["${data.aws_subnet_ids.my-subnets.*.cidr_block}"]
This object does not have an attribute named "cidr_block".
Data source aws_subnet_ids only returns subnet ids, not cider ranges. To get cidr you have to use aws_subnet:
data "aws_subnet_ids" "my-subnets" {
vpc_id = data.aws_vpc.my-vpc.id
filter {
name = "tag:NAME"
values = ["MY_SUBNET"]
}
}
data "aws_subnet" "selected" {
for_each = data.aws_subnet_ids.my-subnets.ids
id = each.value
}
Then you would use the data:
cidr_blocks = "${values(data.aws_subnet.selected).*.cidr_block}"
Using Terraform version 12, I am attempting to create some AWS security group rules.
I need to create x number of rules which may have different from and to ports.
These rules need to be create for each security group returned from the sg_groups data lookup.
So I have a nested list/map.
I think this is doable using Terraform's for_each and for loop function but I struggling to get my head around how to make this work.
Can anybody help me getting looping syntax correct.
Note: The format of the sg_rules map is not set in stone and can be formatted in any way that works best.
variable "sg_rules" = {
type = map
default = {
80 = {
protocol = "tcp"
from_port = 80
to_port = 80
},
443 = {
protocol = "tcp"
from_port = 443
to_port = 443
},
service_ports = {
protocol = "tcp"
from_port = 60000
to_port = 60500
}
}
}
data "aws_security_groups" "sg_groups" {
filter {
name = "group-name"
values = var.sg_names
}
}
Here is an example in which I have created the list of AWS Security Groups using nested for_each.
One for_each for creating a list of AWS Security Groups and another for creating dynamic Ingress and Egress Rules.
main.tf
resource "aws_security_group" "security-groups" {
# Dynamic number of Security Groups
for_each = var.security_group_configurations.security_groups
name = each.value.name
description = each.value.description
vpc_id = var.vpc_id
# Dynamic number of Ingress Rules
dynamic ingress {
for_each = var.security_group_configurations.security_groups[each.key].ingress_rules
content {
description = ingress.value.description
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = lookup(ingress.value, "cidr_blocks", [])
ipv6_cidr_blocks = lookup(ingress.value, "ipv6_cidr_blocks", [])
security_group_id = lookup(ingress.value, "security_group_id", "")
}
}
# Dynamic number of Egress Rules
dynamic egress {
for_each = var.security_group_configurations.security_groups[each.key].egress_rules
content {
description = egress.value.description #Here the 'egress' is the dynamic egress block
from_port = egress.value.from_port
to_port = egress.value.to_port
protocol = egress.value.protocol
cidr_blocks = lookup(ingress.value, "cidr_blocks", [])
ipv6_cidr_blocks = lookup(ingress.value, "ipv6_cidr_blocks", [])
security_group_id = lookup(ingress.value, "security_group_id", "")
}
}
tags = each.value.tags
}
variables.tf
variable "security_group_configurations" {
description = "All Security_Groups related configuration"
}
variable "vpc_id" {
description = "Vpc Id for security_groups"
}
example.tfvars
vpc_id = "vpc-0be6071d37dsd985b"
security_group_configurations = {
security_groups = {
#--------------------->> Security Group 0 <-------------------------------------------
"0" = {
name = "security_group_0"
description = "security_group_0"
# Ingress Rules
ingress_rules = {
# Ingress Rule 0
0 = {
description = "TLS from Public Internet"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
},
# Ingress Rule 1
1 = {
description = "SSH from Public Internet"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
},
}
# Egress Rules
egress_rules = {
# Egress Rule 0
0 = {
description = "Allow all traffic to outside"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
},
# Egress Rule 1
##############
}
# Tags for Security Group 0
tags = {
Name = "security_group_0"
}
},
#--------------------->> Security Group 1 <-------------------------------------------
"1" = {
name = "security_group_1"
description = "security_group_1"
# Ingress Rules
ingress_rules = {
# Ingress Rule 0
0 = {
description = "TLS from Public Internet"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
},
# Ingress Rule 1
1 = {
description = "SSH from Public Internet"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
},
}
# Egress Rules
egress_rules = {
# Egress Rule 0
0 = {
description = "Allow all traffic to outside"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
},
# Egress Rule 1
####
####
}
# Tags for Security Group 1
tags = {
Name = "security_group_1"
}
}
#--------------------->> Security Group 2 <-------------------------------------------
#######
#######
}
}
In typical fashion as soon as I ask for help I end up figuring it out myself, or at least one way of doing it. Here is what I came up with, if anyone has any better ideas please feel free to say
variable "sg_rules" = {
type = map
default = [
{
protocol = "tcp"
from_port = 80
to_port = 80
},
{
protocol = "tcp"
from_port = 443
to_port = 443
},
{
protocol = "tcp"
from_port = 60000
to_port = 60500
}
}
}
locals {
gw_to_mx_rules = [
for pair in setproduct(data.aws_security_groups.sg_groups.ids, var.sg_rules) : {
sg = pair[0]
type = pair[1].type
protocol = pair[1].protocol
from_port = pair[1].from_port
to_port = pair[1].to_port
}
]
}
data "aws_security_groups" "sg_groups" {
filter {
name = "group-name"
values = var.sg_names
}
}
resource "aws_security_group_rule" "gw_to_mx" {
for_each = { for rule in local.gw_to_mx_rules : "${rule.type}.${rule.from_port}.${rule.to_port}.${rule.protocol}.${rule.sg}" => rule }
description = "MX Communication"
type = each.value.type
from_port = each.value.from_port
to_port = each.value.to_port
protocol = each.value.protocol
source_security_group_id = each.value.sg
security_group_id = aws_security_group.waf_instance_sg.id
}
I am new to terraform and trying to create an AWS security group with ingress and egress rules. Rather than hardcoding the values and creating multiple ingress and egress blocks, I am trying to make use of terraform lookup function.
main.tf file looks like this:
provider "aws" {
version = "~> 2.0"
region = var.region
profile = var.profile
}
resource "aws_security_group" "this" {
name = "test-sg"
description = "test security group"
dynamic "ingress" {
for_each = var.ingress_rules
content {
description = lookup(ingress.value, "description", null)
from_port = lookup(ingress.value, "from_port", null)
to_port = lookup(ingress.value, "to_port", null)
protocol = lookup(ingress.value, "protocol", null)
cidr_blocks = lookup(ingress.value, "cidr_blocks", null)
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "test-sg"
}
}
variables.tf file looks like this
variable "ingress_rules" {
default = {
"description" = ["For HTTP", "For SSH"]
"from_port" = ["80", "22"]
"to_port" = ["80", "22"]
"protocol" = ["tcp", "tcp"]
"cidr_blocks" = ["0.0.0.0/0", "0.0.0.0/0"]
}
type = map(list(string))
description = "Security group rules"
}
When I run terraform validate it shows configuration is valid, but when I run terraform plan, it shows the following error:
ingress.value is list of string with 2 elements
Invalid value for "inputMap" parameter: lookup() requires a map as the first
argument.
After spending a long time still, I am not able to figure out how to solve this error. What is the correct way to pass lookup values to variables.tf file.
You have constructed your variable's default value as five maps with a string key and list of strings value. You probably wanted a single map with a series of keys and values associated with the various attributes of your ingress rule. You can update the variable value accordingly like:
variable "ingress_rules" {
default = {
"my ingress rule" = {
"description" = "For HTTP"
"from_port" = "80"
"to_port" = "80"
"protocol" = "tcp"
"cidr_blocks" = ["0.0.0.0/0"]
},
"my other ingress rule" = {
"description" = "For SSH"
"from_port" = "22"
"to_port" = "22"
"protocol" = "tcp"
"cidr_blocks" = ["0.0.0.0/0"]
}
}
type = map(any)
description = "Security group rules"
}
Now, in your for_each iterator, the value of the first ingress.key will be my ingress rule, and the value of the first ingress.value will be your entire map of keys and strings. Before, the first ingress.key would have been description, and the first value would have been ["For HTTP", "For SSH"]. That is why you were getting that error: you cannot lookup a value with key description from a list of ["For HTTP", "For SSH"]. After making this variable value update, you should have your expected behavior.
Note that you can refine your type further with an object:
default = {
"my ingress rule" = {
description = "For HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
"my other ingress rule" = {
description = "For SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
type = map(object({
description = string
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
I would implement it as follows:
resource "aws_security_group" "test_security_group" {
name = "test-sg"
description = "test security group"
dynamic "ingress" {
for_each = var.sg_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
description = ingress.value.description
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "test security group"
}
}
variables.tf
variable "sg_ingress_rules" {
description = "Ingress security group rules"
type = map
}
my_vars.tfvars
sg_ingress_rules = {
"1" = {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP"
},
"2" = {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["<my_private_ip>/32"]
description = "SSH"
}
}
Hope it helps to understand further!