diff --git a/README.md b/README.md
index 43c4c91..30945e9 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,11 @@ Terraform Modules from [this package](https://github.com/tedilabs/terraform-aws-
- [vpc-simple](./examples/vpc-simple)
- [vpc-with-ipam](./examples/vpc-with-ipam)
+### Security Group
+
+- [security-group-simple](./examples/security-group-simple)
+- [security-group-with-ipv4-cidrs](./examples/security-group-with-ipv4-cidrs)
+
### NAT Gateway
- [nat-gateway-public](./examples/nat-gateway-public/)
diff --git a/examples/security-group-simple/main.tf b/examples/security-group-simple/main.tf
new file mode 100644
index 0000000..b5fd32f
--- /dev/null
+++ b/examples/security-group-simple/main.tf
@@ -0,0 +1,26 @@
+provider "aws" {
+ region = "us-east-1"
+}
+
+data "aws_vpc" "default" {
+ default = true
+}
+
+
+###################################################
+# Security Group
+###################################################
+
+module "security_group" {
+ source = "../../modules/security-group"
+ # source = "tedilabs/ipam/aws//modules/security-group"
+ # version = "~> 0.30.0"
+
+ vpc_id = data.aws_vpc.default.id
+
+ name = "hello-world"
+
+ tags = {
+ "project" = "terraform-aws-network-examples"
+ }
+}
diff --git a/examples/security-group-simple/outputs.tf b/examples/security-group-simple/outputs.tf
new file mode 100644
index 0000000..ee0168f
--- /dev/null
+++ b/examples/security-group-simple/outputs.tf
@@ -0,0 +1,4 @@
+output "security_group" {
+ description = "The Security Group."
+ value = module.security_group
+}
diff --git a/examples/security-group-simple/versions.tf b/examples/security-group-simple/versions.tf
new file mode 100644
index 0000000..59c42e8
--- /dev/null
+++ b/examples/security-group-simple/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.5"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 5.0"
+ }
+ }
+}
diff --git a/examples/security-group-with-ipv4-cidrs/main.tf b/examples/security-group-with-ipv4-cidrs/main.tf
new file mode 100644
index 0000000..9b71880
--- /dev/null
+++ b/examples/security-group-with-ipv4-cidrs/main.tf
@@ -0,0 +1,50 @@
+provider "aws" {
+ region = "us-east-1"
+}
+
+data "aws_vpc" "default" {
+ default = true
+}
+
+
+###################################################
+# Security Group
+###################################################
+
+module "security_group" {
+ source = "../../modules/security-group"
+ # source = "tedilabs/ipam/aws//modules/security-group"
+ # version = "~> 0.30.0"
+
+ vpc_id = data.aws_vpc.default.id
+
+ name = "hello-world-ipv4-cidrs"
+ description = "Sample Security Group with IPv4 CIDRs."
+
+ revoke_rules_on_delete = true
+
+ ingress_rules = [
+ {
+ id = "tcp/80"
+ description = "Allow HTTP from VPC"
+ from_port = 80
+ to_port = 80
+ protocol = "tcp"
+ ipv4_cidrs = ["192.168.0.0/16", "10.0.0.0/8", "172.168.0.0/24"]
+ },
+ ]
+ egress_rules = [
+ {
+ id = "all/all"
+ description = "Allow all traffics to the internet"
+ from_port = 0
+ to_port = 0
+ protocol = "-1"
+ ipv4_cidrs = ["0.0.0.0/0"]
+ },
+ ]
+
+ tags = {
+ "project" = "terraform-aws-network-examples"
+ }
+}
diff --git a/examples/security-group-with-ipv4-cidrs/outputs.tf b/examples/security-group-with-ipv4-cidrs/outputs.tf
new file mode 100644
index 0000000..ee0168f
--- /dev/null
+++ b/examples/security-group-with-ipv4-cidrs/outputs.tf
@@ -0,0 +1,4 @@
+output "security_group" {
+ description = "The Security Group."
+ value = module.security_group
+}
diff --git a/examples/security-group-with-ipv4-cidrs/versions.tf b/examples/security-group-with-ipv4-cidrs/versions.tf
new file mode 100644
index 0000000..59c42e8
--- /dev/null
+++ b/examples/security-group-with-ipv4-cidrs/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.5"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 5.0"
+ }
+ }
+}
diff --git a/modules/security-group/README.md b/modules/security-group/README.md
index 054d8a1..513082d 100644
--- a/modules/security-group/README.md
+++ b/modules/security-group/README.md
@@ -3,21 +3,22 @@
This module creates following resources.
- `aws_security_group`
-- `aws_security_group_rule` (optional)
+- `aws_vpc_security_group_ingress_rule` (optional)
+- `aws_vpc_security_group_egress_rule` (optional)
## Requirements
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.5 |
-| [aws](#requirement\_aws) | >= 3.45 |
+| [terraform](#requirement\_terraform) | >= 1.6 |
+| [aws](#requirement\_aws) | >= 5.3 |
## Providers
| Name | Version |
|------|---------|
-| [aws](#provider\_aws) | 5.19.0 |
+| [aws](#provider\_aws) | 5.24.0 |
## Modules
@@ -30,8 +31,8 @@ This module creates following resources.
| Name | Type |
|------|------|
| [aws_security_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
-| [aws_security_group_rule.egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
-| [aws_security_group_rule.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
+| [aws_vpc_security_group_egress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource |
+| [aws_vpc_security_group_ingress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource |
## Inputs
@@ -40,10 +41,9 @@ This module creates following resources.
| [name](#input\_name) | (Required) The name of the security group. | `string` | n/a | yes |
| [vpc\_id](#input\_vpc\_id) | (Required) The ID of the associated VPC. | `string` | n/a | yes |
| [description](#input\_description) | (Optional) The security group description. This field maps to the AWS `GroupDescription` attribute, for which there is no Update API. | `string` | `"Managed by Terraform."` | no |
-| [egress\_rules](#input\_egress\_rules) | (Optional) A list of egress rules in a security group. | `any` | `[]` | no |
-| [ingress\_rules](#input\_ingress\_rules) | (Optional) A list of ingress rules in a security group. | `any` | `[]` | no |
+| [egress\_rules](#input\_egress\_rules) | (Optional) The configuration for egress rules of the security group. Each block of `egress_rules` as defined below.
(Required) `id` - The ID of the egress rule. This value is only used internally within Terraform code.
(Optional) `description` - The description of the rule.
(Required) `protocol` - The protocol to match. Note that if `protocol` is set to `-1`, it translates to all protocols, all port ranges, and `from_port` and `to_port` values should not be defined.
(Required) `from_port` - The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 type.
(Required) `to_port` - The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code.
(Optional) `ipv4_cidrs` - The IPv4 network ranges to allow, in CIDR notation.
(Optional) `ipv6_cidrs` - The IPv6 network ranges to allow, in CIDR notation.
(Optional) `prefix_lists` - The prefix list IDs to allow.
(Optional) `security_groups` - The source security group IDs to allow.
(Optional) `self` - Whether the security group itself will be added as a source to this ingress rule. |
list(object({| `[]` | no | +| [ingress\_rules](#input\_ingress\_rules) | (Optional) The configuration for ingress rules of the security group. Each block of `ingress_rules` as defined below.
id = string
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(list(string), [])
ipv6_cidrs = optional(list(string), [])
prefix_lists = optional(list(string), [])
security_groups = optional(list(string), [])
self = optional(bool, false)
}))
list(object({| `[]` | no | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | -| [name\_prefix](#input\_name\_prefix) | (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`. | `string` | `null` | no | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | @@ -55,7 +55,10 @@ This module creates following resources. | Name | Description | |------|-------------| | [arn](#output\_arn) | The ARN of the security group. | +| [description](#output\_description) | The description of the security group. | +| [egress\_rules](#output\_egress\_rules) | The configuration of the security group egress rules. | | [id](#output\_id) | The ID of the security group. | +| [ingress\_rules](#output\_ingress\_rules) | The configuration of the security group ingress rules. | | [name](#output\_name) | The name of the security group. | | [owner\_id](#output\_owner\_id) | The ID of the AWS account that owns the security group. | | [vpc\_id](#output\_vpc\_id) | The ID of the associated VPC. | diff --git a/modules/security-group/main.tf b/modules/security-group/main.tf index 1dd6c1c..d2b3e93 100644 --- a/modules/security-group/main.tf +++ b/modules/security-group/main.tf @@ -14,11 +14,21 @@ locals { } : {} } + +################################################### +# Security Group +################################################### + +# INFO: Not supported attributes +# - `name_prefix` +# INFO: Use a separate resource +# - `egress` +# - `ingress` resource "aws_security_group" "this" { vpc_id = var.vpc_id - name = var.name - name_prefix = var.name_prefix + name = var.name + # name_prefix = var.name_prefix description = var.description revoke_rules_on_delete = var.revoke_rules_on_delete @@ -31,85 +41,3 @@ resource "aws_security_group" "this" { var.tags, ) } - - -################################################### -# Security Group Rules -################################################### - -locals { - normalized_ingress_rules = [ - for rule in var.ingress_rules : { - id = rule.id - description = lookup(rule, "description", "Managed by Terraform") - - protocol = rule.protocol - from_port = rule.from_port - to_port = rule.to_port - - cidr_blocks = try(sort(compact(rule.cidr_blocks)), null) - ipv6_cidr_blocks = try(sort(compact(rule.ipv6_cidr_blocks)), null) - prefix_list_ids = try(sort(compact(rule.prefix_list_ids)), null) - source_security_group_id = try(rule.source_security_group_id, null) - self = try(rule.self, false) ? true : null - } - ] - normalized_egress_rules = [ - for rule in var.egress_rules : { - id = rule.id - description = lookup(rule, "description", "Managed by Terraform") - - protocol = rule.protocol - from_port = rule.from_port - to_port = rule.to_port - - cidr_blocks = try(sort(compact(rule.cidr_blocks)), null) - ipv6_cidr_blocks = try(sort(compact(rule.ipv6_cidr_blocks)), null) - prefix_list_ids = try(sort(compact(rule.prefix_list_ids)), null) - source_security_group_id = try(rule.source_security_group_id, null) - self = try(rule.self, false) ? true : null - } - ] -} - -resource "aws_security_group_rule" "ingress" { - for_each = { - for rule in local.normalized_ingress_rules : - rule.id => rule - } - - security_group_id = aws_security_group.this.id - type = "ingress" - description = each.value.description - - protocol = each.value.protocol - from_port = each.value.from_port - to_port = each.value.to_port - - cidr_blocks = each.value.cidr_blocks - ipv6_cidr_blocks = each.value.ipv6_cidr_blocks - prefix_list_ids = each.value.prefix_list_ids - source_security_group_id = each.value.source_security_group_id - self = each.value.self -} - -resource "aws_security_group_rule" "egress" { - for_each = { - for rule in local.normalized_egress_rules : - rule.id => rule - } - - security_group_id = aws_security_group.this.id - type = "egress" - description = each.value.description - - protocol = each.value.protocol - from_port = each.value.from_port - to_port = each.value.to_port - - cidr_blocks = each.value.cidr_blocks - ipv6_cidr_blocks = each.value.ipv6_cidr_blocks - prefix_list_ids = each.value.prefix_list_ids - source_security_group_id = each.value.source_security_group_id - self = each.value.self -} diff --git a/modules/security-group/outputs.tf b/modules/security-group/outputs.tf index 2260b4f..e1287bf 100644 --- a/modules/security-group/outputs.tf +++ b/modules/security-group/outputs.tf @@ -13,6 +13,11 @@ output "name" { value = aws_security_group.this.name } +output "description" { + description = "The description of the security group." + value = aws_security_group.this.description +} + output "owner_id" { description = "The ID of the AWS account that owns the security group." value = aws_security_group.this.owner_id @@ -22,3 +27,39 @@ output "vpc_id" { description = "The ID of the associated VPC." value = aws_security_group.this.vpc_id } + +output "ingress_rules" { + description = <
id = string
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(list(string), [])
ipv6_cidrs = optional(list(string), [])
prefix_lists = optional(list(string), [])
security_groups = optional(list(string), [])
self = optional(bool, false)
}))
object({| `{}` | no | -| [default\_security\_group](#input\_default\_security\_group) | (Optional) The configuration for the default Security Group of the VPC. `default_security_group` as defined below.
name = optional(string)
ingress_rules = optional(set(object({
priority = number
action = string
protocol = string
from_port = number
to_port = number
ipv4_cidr = optional(string)
ipv6_cidr = optional(string)
icmp_type = optional(number, 0)
icmp_code = optional(number, 0)
})))
egress_rules = optional(set(object({
priority = number
action = string
protocol = string
from_port = number
to_port = number
ipv4_cidr = optional(string)
ipv6_cidr = optional(string)
icmp_type = optional(number, 0)
icmp_code = optional(number, 0)
})))
})
object({| `{}` | no | +| [default\_security\_group](#input\_default\_security\_group) | (Optional) The configuration for the default Security Group of the VPC. `default_security_group` as defined below.
name = optional(string)
ingress_rules = optional(set(object({
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(set(string))
ipv6_cidrs = optional(set(string))
prefix_lists = optional(set(string))
security_groups = optional(set(string))
self = optional(bool, false)
})))
egress_rules = optional(set(object({
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(set(string))
ipv6_cidrs = optional(set(string))
prefix_lists = optional(set(string))
security_groups = optional(set(string))
self = optional(bool, false)
})))
})
object({| `{}` | no | | [dhcp\_options](#input\_dhcp\_options) | (Optional) The configuration for a DHCP option set of the VPC. Dynamic Host Configuration Protocol (DHCP) provides a standard for passing configuration information to hosts on a TCP/IP network. `dhcp_options` as defined below.
name = optional(string)
ingress_rules = optional(set(object({
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(set(string))
ipv6_cidrs = optional(set(string))
prefix_lists = optional(set(string))
security_groups = optional(set(string))
self = optional(bool, false)
})))
egress_rules = optional(set(object({
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(set(string))
ipv6_cidrs = optional(set(string))
prefix_lists = optional(set(string))
security_groups = optional(set(string))
self = optional(bool, false)
})))
})
object({| `{}` | no | | [dns\_dnssec\_validation\_enabled](#input\_dns\_dnssec\_validation\_enabled) | (Optional) Should be true to enable Route53 DNSSEC validation in the VPC. | `bool` | `false` | no | | [dns\_hostnames\_enabled](#input\_dns\_hostnames\_enabled) | (Optional) Whether instances launched in the VPC receive public DNS hostnames that correspond to their public IP addresses. Defaults to `true`. | `bool` | `true` | no | diff --git a/modules/vpc/variables.tf b/modules/vpc/variables.tf index 7806fc3..531a97a 100644 --- a/modules/vpc/variables.tf +++ b/modules/vpc/variables.tf @@ -207,18 +207,20 @@ variable "default_security_group" { (Required) `from_port` - The from port to match. (Required) `to_port` - The to port to match. (Optional) `ipv4_cidrs` - The IPv4 network ranges to allow, in CIDR notation. Cannot be specified with `ipv6_cidrs`. - (Optional) `ipv6_cidr` - The IPv6 network ranges to allow, in CIDR notation. Cannot be specified with `ipv4_cidrs`. - (Optional) `icmp_code` - The ICMP code to be used. Defaults to `0`. - (Optional) `egress_rules` - A set of egress rules in the default Network ACL. If not explicitly defined, the AWS default rules are applied. `egress_rules` as defined below. - (Required) `priority` - The rule priority. The rule number. Used for ordering. - (Required) `action` - The action to indicate whether to allow or deny the traffic that matches the rule. Valid values are `ALLOW` and `DENY`. + (Optional) `ipv6_cidrs` - The IPv6 network ranges to allow, in CIDR notation. Cannot be specified with `ipv4_cidrs`. + (Optional) `prefix_lists` - The prefix list IDs to allow. + (Optional) `security_groups` - The source security group IDs to allow. + (Optional) `self` - Whether the security group itself will be added as a source to this ingress rule. + (Optional) `egress_rules` - A set of egress rules in the default Security Group. If not explicitly defined, the AWS default rules are applied. `egress_rules` as defined below. + (Optional) `description` - The description of the rule. (Required) `protocol` - The protocol to match. If using the `-1` 'all' protocol, you must specify a from and to port of `0`. (Required) `from_port` - The from port to match. (Required) `to_port` - The to port to match. - (Optional) `ipv4_cidr` - The IPv4 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv6_cidr`. - (Optional) `ipv6_cidr` - The IPv6 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv4_cidr`. - (Optional) `icmp_type` - The ICMP type to be used. Defaults to `0`. - (Optional) `icmp_code` - The ICMP code to be used. Defaults to `0`. + (Optional) `ipv4_cidrs` - The IPv4 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv6_cidrs`. + (Optional) `ipv6_cidrs` - The IPv6 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv4_cidrs`. + (Optional) `prefix_lists` - The prefix list IDs to allow. + (Optional) `security_groups` - The source security group IDs to allow. + (Optional) `self` - Whether the security group itself will be added as a source to this ingress rule. EOF type = object({ name = optional(string)
enabled = optional(bool, false)
name = optional(string)
domain_name = optional(string)
domain_name_servers = optional(list(string), ["AmazonProvidedDNS"])
netbios_name_servers = optional(list(string), [])
netbios_node_type = optional(number, 2)
ntp_servers = optional(list(string), [])
})