diff --git a/.github/workflows/commit-to-pr.yaml b/.github/workflows/commit-to-pr.yaml
index 2bd9dc0..dc34f33 100644
--- a/.github/workflows/commit-to-pr.yaml
+++ b/.github/workflows/commit-to-pr.yaml
@@ -20,7 +20,7 @@ jobs:
validation:
strategy:
matrix:
- folder: ["add", "folders", "here"]
+ folder: ["./", "examples/security_group"]
name: Terraform validate for ${{ matrix.folder }}
runs-on: ubuntu-20.04
steps:
@@ -41,7 +41,7 @@ jobs:
linting:
strategy:
matrix:
- folder: ["add", "folders", "here"]
+ folder: ["./", "examples/security_group"]
name: Terraform lint for ${{ matrix.folder }}
runs-on: ubuntu-20.04
steps:
@@ -59,7 +59,7 @@ jobs:
plan:
strategy:
matrix:
- folder: ["add", "folders", "here"]
+ folder: ["examples/security_group"]
name: Terraform plan for ${{ matrix.folder }}
runs-on: ubuntu-20.04
needs: [validation, linting]
diff --git a/.terraform-version b/.terraform-version
new file mode 100644
index 0000000..8e03717
--- /dev/null
+++ b/.terraform-version
@@ -0,0 +1 @@
+1.5.1
\ No newline at end of file
diff --git a/README.md b/README.md
index 323b31c..5cc34f4 100644
--- a/README.md
+++ b/README.md
@@ -42,11 +42,72 @@ The below documentation is intended to assist users in utilising the module, the
the module itself, and the [examples](#examples) section which has examples of how to utilise the module.
+## Requirements
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.5.0 |
+| [aws](#requirement\_aws) | >= 5.61.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 5.67.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_security_group.groups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
+| [aws_security_group_rule.rule](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [application\_name](#input\_application\_name) | Name of the application utilising resource. | `string` | n/a | yes |
+| [environment](#input\_environment) | Which environment this is being instantiated in. | `string` | n/a | yes |
+| [raw\_security\_groups](#input\_raw\_security\_groups) | Data structure
---------------
A list of dictionaries, where each dictionary has the following attributes:
REQUIRED
---------
- suffix : Security group suffix to use for naming and unique identifiers
- description : Description to give to the security group
OPTIONAL
---------
- rules: A list of dictionaries, where each dictionary has the following values:
-- name : Friendly name used through Terraform for instantiation and cross-referencing
-- type : Ingress/egress
-- from\_port : Start port
-- to\_port : End port
-- protocol : Protocol. If not icmp, icmpv6, tcp, udp, or all use the protocol number.
-- description : Friendly description of the rule, required for auditing purposes.
In addition, the following optional args are available:
-- cidr\_blocks : List of CIDR blocks. Cannot be specified with source\_security\_group\_id or self.
-- ipv6\_cidr\_blocks : List of IPv6 CIDR blocks. Cannot be specified with source\_security\_group\_id or self.
-- prefix\_list\_ids : List of Prefix List IDs.
-- self : Whether the security group itself will be added as a source to this ingress rule. Cannot be specified with cidr\_blocks, ipv6\_cidr\_blocks, or source\_security\_group\_id.
-- source\_security\_group\_id : Security group id to allow access to/from, depending on the type. Cannot be specified with cidr\_blocks, ipv6\_cidr\_blocks, or self. |
list(
object({
suffix : string,
description : string,
rules : optional(list(
object({
name = string,
type = string,
from_port = string,
to_port = string,
protocol = string,
description = string,
cidr_blocks = optional(list(string), null),
ipv6_cidr_blocks = optional(list(string), null),
prefix_list_ids = optional(list(string), null),
self = optional(bool, null),
source_security_group_id = optional(string, null)
})
), [])
})
)
| n/a | yes |
+| [vpc\_config](#input\_vpc\_config) | AWS VPC ID within which to create the security group. | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
## Data structure
-
+```
+Data structure
+---------------
+A list of dictionaries, where each dictionary has the following attributes:
+
+REQUIRED
+---------
+- suffix : Security group suffix to use for naming and unique identifiers
+- description : Description to give to the security group
+
+OPTIONAL
+---------
+- rules: A list of dictionaries, where each dictionary has the following values:
+-- name : Friendly name used through Terraform for instantiation and cross-referencing
+-- type : Ingress/egress
+-- from_port : Start port
+-- to_port : End port
+-- protocol : Protocol. If not icmp, icmpv6, tcp, udp, or all use the protocol number.
+-- description : Friendly description of the rule, required for auditing purposes.
+
+In addition, the following optional args are available:
+-- cidr_blocks : List of CIDR blocks. Cannot be specified with source_security_group_id or self.
+-- ipv6_cidr_blocks : List of IPv6 CIDR blocks. Cannot be specified with source_security_group_id or self.
+-- prefix_list_ids : List of Prefix List IDs.
+-- self : Whether the security group itself will be added as a source to this ingress rule. Cannot be specified with cidr_blocks, ipv6_cidr_blocks, or source_security_group_id.
+-- source_security_group_id : Security group id to allow access to/from, depending on the type. Cannot be specified with cidr_blocks, ipv6_cidr_blocks, or self.
+```
## Examples
See `examples` folder for an example setup.
diff --git a/aws_security_group.tf b/aws_security_group.tf
new file mode 100644
index 0000000..08fd3f3
--- /dev/null
+++ b/aws_security_group.tf
@@ -0,0 +1,11 @@
+resource "aws_security_group" "groups" {
+ for_each = { for group in var.raw_security_groups : group.suffix => group }
+
+ name = upper(format("aws-%s-%s-%s-SG",
+ var.environment,
+ var.application_name,
+ each.value["suffix"])
+ )
+ description = format("%s - Managed by Terraform", each.value["description"])
+ vpc_id = var.vpc_config
+}
\ No newline at end of file
diff --git a/aws_security_group_rule.tf b/aws_security_group_rule.tf
new file mode 100644
index 0000000..6daba57
--- /dev/null
+++ b/aws_security_group_rule.tf
@@ -0,0 +1,30 @@
+locals {
+ actual_security_group_rules = flatten([
+ for group in var.raw_security_groups : [
+ for rule in group.rules : merge(rule, {
+ identifier : format("%s/%s", group.suffix, rule.name),
+ security_group_id = aws_security_group.groups[group.suffix].id
+ })
+ ]
+ ])
+}
+
+resource "aws_security_group_rule" "rule" {
+ for_each = { for rule in local.actual_security_group_rules : rule.identifier => rule }
+ type = each.value["type"]
+ from_port = each.value["from_port"]
+ to_port = each.value["to_port"]
+ protocol = each.value["protocol"]
+ security_group_id = each.value["security_group_id"]
+ description = each.value["description"]
+
+ cidr_blocks = try(each.value["cidr_blocks"], null)
+ ipv6_cidr_blocks = try(each.value["ipv6_cidr_blocks"], null)
+ prefix_list_ids = try(each.value["prefix_list_ids"], null)
+ self = try(each.value["self"], null)
+ source_security_group_id = try(each.value["source_security_group_id"], null)
+
+ depends_on = [
+ aws_security_group.groups
+ ]
+}
\ No newline at end of file
diff --git a/examples/security_group/.terraform-version b/examples/security_group/.terraform-version
new file mode 100644
index 0000000..8e03717
--- /dev/null
+++ b/examples/security_group/.terraform-version
@@ -0,0 +1 @@
+1.5.1
\ No newline at end of file
diff --git a/examples/security_group/data.tf b/examples/security_group/data.tf
new file mode 100644
index 0000000..287398b
--- /dev/null
+++ b/examples/security_group/data.tf
@@ -0,0 +1,2 @@
+# Get default VPC
+data "aws_vpc" "vpc" {}
\ No newline at end of file
diff --git a/examples/security_group/locals.tf b/examples/security_group/locals.tf
new file mode 100644
index 0000000..49187f0
--- /dev/null
+++ b/examples/security_group/locals.tf
@@ -0,0 +1,37 @@
+locals {
+ raw_security_groups = [
+ {
+ "suffix" : "lambda",
+ "description" : "Lambda Function security group",
+ "rules" : [
+ {
+ "name" : "All traffic from VPC",
+ "type" : "ingress",
+ "from_port" : "0",
+ "to_port" : "0",
+ "protocol" : "-1",
+ "description" : "VPC Traffic (Ingress)",
+ "cidr_blocks" : ["1.2.3.0/24"]
+ },
+ {
+ "name" : "All traffic to VPC",
+ "type" : "egress",
+ "from_port" : "0",
+ "to_port" : "0",
+ "protocol" : "-1",
+ "description" : "VPC Traffic (Egress)",
+ "cidr_blocks" : ["1.2.3.0/24"]
+ },
+ {
+ "name" : "Public endpoint traffic",
+ "type" : "egress",
+ "from_port" : "443",
+ "to_port" : "443",
+ "protocol" : "tcp",
+ "description" : "Public Endpoint traffic (Egress)",
+ "cidr_blocks" : ["0.0.0.0/0"]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/security_group/main.tf b/examples/security_group/main.tf
new file mode 100644
index 0000000..72f8b92
--- /dev/null
+++ b/examples/security_group/main.tf
@@ -0,0 +1,21 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 5.61.0"
+ }
+ }
+ required_version = "~> 1.5.0"
+}
+
+provider "aws" {
+ region = "eu-west-2"
+}
+
+module "security_group" {
+ source = "github.com/sudoblark/sudoblark.terraform.module.aws.security_group?ref=1.0.0"
+ environment = var.environment
+ application_name = var.application_name
+ raw_security_groups = local.raw_security_groups
+ vpc_config = data.aws_vpc.vpc.id
+}
\ No newline at end of file
diff --git a/examples/security_group/variables.tf b/examples/security_group/variables.tf
new file mode 100644
index 0000000..9ccf4b8
--- /dev/null
+++ b/examples/security_group/variables.tf
@@ -0,0 +1,15 @@
+variable "environment" {
+ description = "Which environment this is being instantiated in."
+ type = string
+ validation {
+ condition = contains(["dev", "test", "prod"], var.environment)
+ error_message = "Must be either dev, test or prod"
+ }
+ default = "prod"
+}
+
+variable "application_name" {
+ description = "Name of the application utilising the resource resource."
+ type = string
+ default = "demo-app"
+}
\ No newline at end of file
diff --git a/main.tf b/main.tf
new file mode 100644
index 0000000..f022823
--- /dev/null
+++ b/main.tf
@@ -0,0 +1,9 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 5.61.0"
+ }
+ }
+ required_version = "~> 1.5.0"
+}
\ No newline at end of file
diff --git a/variables.tf b/variables.tf
new file mode 100644
index 0000000..3b427e5
--- /dev/null
+++ b/variables.tf
@@ -0,0 +1,73 @@
+# Input variable definitions
+variable "environment" {
+ description = "Which environment this is being instantiated in."
+ type = string
+ validation {
+ condition = contains(["dev", "test", "prod"], var.environment)
+ error_message = "Must be either dev, test or prod"
+ }
+}
+
+variable "application_name" {
+ description = "Name of the application utilising resource."
+ type = string
+}
+
+variable "vpc_config" {
+ description = "AWS VPC ID within which to create the security group."
+ type = string
+}
+
+variable "raw_security_groups" {
+ description = <