Hi!
Usually, when you create security groups, you create inbound rules manually but you may also want to create a security group that has multiple inbound rules with Terraform and attach them to instances.
I’m going to introduce two ways of creating multiple rules.
Let’s try that out!
How to set up
The first way of the setup method is to set two ingresses (inbound rules) to an aws_security_group.
This method is very simple and useful.
resource "aws_security_group" "test-sg" {
name = "test-sg"
description = "test-sg"
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
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"]
}
}
The second method is setting an aws_security_goup_rule.
In this method, you set an ingress to an aws_security_group_rule, but not to an aws_security_group.
You can set only one rule in one aws_security_goup_rule resource. So, when you want to set multiple rules, you have to create an aws_security_group_rule resource that has a different name and then add a rule to it.
Although it will be useful if you know how to do this, when you set rules using this aws_security_group_rule, you must read the following first before you try.
resource "aws_security_group" test-sg" {
name = "test-sg"
description = "test-sg"
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}
resource "aws_security_group_rule" "test-sg-inbound-http" {
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [
"0.0.0.0/0"
]
security_group_id = aws_security_group.test-sg.id
}
resource "aws_security_group_rule" "test-sg-inbound-https" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [
"0.0.0.0/0"
]
security_group_id = aws_security_group.test-sg.id
}
you cannot set rules to both aws_security_group and aws_security_group_rule
“I set ingress in aws_security_group and I’m going to add one more ingress to aws_security_goup_rule!”
Just like him, if you add another ingress rule to an aws_security_group_rule even after you already set an ingress rule to an aws_security_group, it becomes buggy with conflicting rules that have been created and disappear when they are applied.\
“There is no way it’s going to be buggy! what on earth are you talking about?”
You may think this way just like I did before lol
So I’m going to leave the log result of the inspection I did.
Apply under main.tf
resource "aws_security_group" "test-sg" {
name = "test-sg"
description = "test-sg"
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group_rule" "test-sg-inbound-https" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [
"0.0.0.0/0"
]
security_group_id = aws_security_group.test-sg.id
}
You can see that 80 and 443’s inbound rules are successfully created on the AWS console .
But after the second attempt , you see the status is “changed” even though you didn’t make any changes in main.tf, and the settings in the aws_security_group_rule is deleted.
aws_security_group.test-sg: Refreshing state... [id=sg-063e7c33de8e1dc09]
aws_security_group_rule.test-sg-inbound-https: Refreshing state... [id=sgrule-4193634971]
aws_instance.test: Refreshing state... [id=i-07125d27a59e1b8f5]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_security_group.test-sg will be updated in-place
~ resource "aws_security_group" "test-sg" {
id = "sg-063e7c33de8e1dc09"
~ ingress = [
- {
- cidr_blocks = [
- "0.0.0.0/0",
]
- description = ""
- from_port = 443
- ipv6_cidr_blocks = []
- prefix_list_ids = []
- protocol = "tcp"
- security_groups = []
- self = false
- to_port = 443
},
- {
- cidr_blocks = [
- "0.0.0.0/0",
]
- description = ""
- from_port = 80
- ipv6_cidr_blocks = []
- prefix_list_ids = []
- protocol = "tcp"
- security_groups = []
- self = false
- to_port = 80
},
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ description = null
+ from_port = 80
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 80
},
]
name = "test-sg"
tags = {}
# (7 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
If you check AWS, It seems the setting part that was in an aws_security_group_rule has disappeared…
The official aws_security_group resource’s description is written like this.
Even if you set a rule to an aws_security_group_rule, it’s going to be overwritten to what you set in the aws_security_group_rule.
NOTE on Security Groups and Security Group Rules:
Terraform currently provides both a standalone Security Group Rule resource (a single ingress or egress rule), and a Security Group resource with ingress and egress rules defined in-line. At this time you cannot use a Security Group with in-line rules in conjunction with any Security Group Rule resources. Doing so will cause a conflict of rule settings and will overwrite rules.
Summary
I introduced how to add multiple rules to security groups, how did you like it?
It is possible to set multiple rules to an aws_security_group and an aws_security_group_rule but you have to be aware that if you set rules to both of them at the same time, it might cause serious incidents.
It’s totally up to you how you are going to do it, but as long as you don’t have special reasons, setting multiple rules to an aws_security_group is an easier way to manage and has no risk of conflict of rules settings.
Thank you!
This blog post is translated from a blog post written by Hide@infrastructure engineer on our Japanese website Beyond Co..
Comments