How to add multiple rules to a security group in Terraform

table of contents

*Tsukemen Shigeta (Rokkomichi, Kobe)
Hello!
I'm Hide, the Ramen King from Beyond Inc.'s Osaka office.
This is my 10th post.
Last time, I wrote about how to set up URL redirection with the Google Cloud Load Balancing (GCLB) global external HTTP(S) load balancer!
The URL redirection settings are different between the latest and traditional models, which can be a little difficult, but it's useful to know, so if you're interested, please take a look below!
● Part 1: How to set up URL redirection with GCP's global external HTTP(S) load balancer (traditional type)
● Part 2: How to set up URL redirection with GCP's global external HTTP(S) load balancer
Adding multiple rules to a security group in Terraform
Normally, when creating a security group, multiple inbound rules are created manually, but you may want to create a security group with multiple inbound rules in Terraform as well and attach it to an instance, etc
We will introduce two ways to create these multiple rules
The final goal is to make it look like the image below!
Let's do our best!
How to set it up
The first setting method is to set two ingress (inbound rules) in aws_security_group.
This is very simple and easy to use.
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 setting method is to set aws_security_group_rule
This method involves not writing ingress in aws_security_group, but writing it in aws_security_group_rule. With this method, you can only write one rule in one aws_security_group_rule resource, so if you want to write multiple rules, you need to create an aws_security_group_rule resource with a different resource name as shown below and add the rules to it
However, while it may be useful if used properly, if you use this aws_security_group_rule to set rules, be sure to read the following before setting them up!
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 }
Do not set rules in both aws_security_group and aws_security_group_rule

"I set up ingress with aws_security_group, but
I want to add another ingress, so I'll add it with aws_security_group_rule!
I set ingress rules with aws_security_group like this, but when I add them with aws_security_group_rule,
the rules conflict and are created and deleted when I apply them, causing bugs...

"There's no way it'll bug out! What are you talking about?"
I'm sure there are people out there who have thought the same thing, and that's exactly what I thought when I first learned about it lol.
For those of you who feel the same way, I'll leave a log of my actual testing!
Apply the following in 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 }
After the first apply , the following will appear on the AWS side.
The inbound rules for ports 80 and 443 have been created without any issues.
However, when you apply it the second time, even though you haven't made any changes to main.tf, it will be marked as changed and anything set in aws_security_group_rule will be 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
The AWS screen after the second apply will look like this. The part set in aws_security_group_rule has disappeared
The official aws_security_group resource description states:
In other words, even if you set it in aws_security_group_rule, it will be overwritten by the setting in aws_security_group. If you operate without knowing this, it can be quite scary...
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 inline
Currently, you cannot use security groups with inline rules in combination with security group rule resources, as this will result in conflicting rule settings and overwriting the rules
● Reference: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
summary
This time, we introduced how to add multiple rules to a security group using Terraform. What did you think?
You can define multiple rules with aws_security_group and aws_security_group_rule, but be careful not to set rules at the same time as this can lead to serious mistakes!
It's up to you which one to use, but unless there is a special reason, I think setting multiple rules with aws_security_group is easier to manage and less likely to cause conflicts
Please use this as a reference when creating a security group!
5
