An easier method to deal with AWS Security Groups via Terraform

As I continue my Terraform journey, I am always trying to find better ways to deal with the complexities of the code and the resulting resources built from the code. Security Groups are no execption.

I did some web searching and found some code to parse a CSV and create a security group rule set. I took that idea and expanded on it. The idea is you pass a CSV with all the rules and the code is designed to create the Security Group (SG) and add the rules within the given SG.

A sample CSV:

id,type,name,cidr_block,protocol,from_port,to_port,description
1,egress,security-group-1,"10.2.20.0/24,10.2.21.0/24",tcp,27017,27017,docdb - 27017
2,egress,security-group-1,"10.2.20.0/24,10.2.21.0/24",tcp,6379,6379,docdb - 6379
3,egress,security-group-1,"10.2.20.0/24,10.2.21.0/24",tcp,8089,8089,docdb - 8089
4,egress,security-group-1,10.202.1.24/32,tcp,6611,6611,app1 - 6611
5,egress,security-group-1,10.202.1.24/32,tcp,6613,6613,app1 - 6613
6,egress,security-group-1,10.202.1.24/32,tcp,6617,6717,app1 - 6617
7,egress,security-group-1,10.202.1.24/32,tcp,6646,6647,app1 - 6646-6647
8,egress,security-group-1,192.168.27.7/32,tcp,6331,6331,app1-test - 6331
9,egress,security-group-1,192.168.27.7/32,tcp,6609,6609,app1-test - 6609
10,egress,security-group-1,192.168.27.7/32,tcp,6612,6613,app1-test 6612 - 6613
11,egress,security-group-2,192.168.1.101/32,tcp,876,876,app3-test
12,egress,security-group-2,192.168.1.101/32,tcp,877,876,app3-test
13,egress,security-group-2,192.168.1.101/32,tcp,999,999,app3-test
14,egress,security-group-2,192.168.1.101/32,tcp,989,989,app3-test

The above CSV is passed to the TF code and results in creating two Security Groups – “security-group-1” with 9 rules and “security-group-2” with 4 rules. The first column is used by the TF code to determine the each rule by id (sudo index).

Here’s the TF code:

data "aws_caller_identity" "current" {}
locals {

  csv_data_app = file("${path.module}/securitygrouprules.csv")
  appip        = csvdecode(local.csv_data_app)
  vpc_id       = "vpc-001abc002efg0003"

  sg_app_details = flatten([

    for sg in local.appip : {
      id          = sg.id
      type        = sg.type
      name        = sg.name
      description = sg.description
      protocol    = sg.protocol
      from_port   = sg.from_port
      to_port     = sg.to_port
      cidr_blocks = sg.cidr_block
    }
  ])

  sg_app_names = distinct(flatten([

    for sg in local.appip : {
      name = sg.name
    }
  ]))
}


resource "aws_security_group" "security_groups" {
  for_each = { 
    for key in local.sg_app_names : key.name => key }
  name     = each.value.name
  vpc_id   = local.vpc_id
}


resource "aws_security_group_rule" "samplesg_ingress" {
  for_each          = { for key in local.sg_app_details : key.id => key }
  security_group_id = aws_security_group.security_groups["${each.value.name}"].id
  type              = each.value.type
  description       = each.value.description
  protocol          = each.value.protocol
  from_port         = each.value.from_port
  to_port           = each.value.to_port
  cidr_blocks       = split(",", each.value.cidr_blocks)
}


output "sgs" {
  value = values(aws_security_group.security_groups)[*].id
}

output "account" {
  value = data.aws_caller_identity.current.account_id
}
The results of an apply

Fun problem to work on.
Happy Building,

D

An easier method to deal with AWS Security Groups via Terraform

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top