Skip to content

Commit

Permalink
Merge pull request #32 from terraform-modules/feature/add-prefix-list
Browse files Browse the repository at this point in the history
feature/add prefix list
  • Loading branch information
badra001 committed Aug 26, 2025
2 parents cf5aba7 + aa508ce commit 8b6221a
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,6 @@

* 2.6.2 -- 2025-05-29
- it-windows-base: remove app28.csvd.census.gov from hosts

* 2.7.0 -- 2025-08-26
- custom: add prefix list capability
2 changes: 1 addition & 1 deletion common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ No modules.
| <a name="input_ingress_security_groups"></a> [ingress\_security\_groups](#input\_ingress\_security\_groups) | List of ingress security groups for all ports | `list(string)` | `[]` | no |
| <a name="input_ingress_self_port_list"></a> [ingress\_self\_port\_list](#input\_ingress\_self\_port\_list) | Ingress port list of 4-tuple: from, to, proto, description | `list` | `[]` | no |
| <a name="input_ingress_self_port_map"></a> [ingress\_self\_port\_map](#input\_ingress\_self\_port\_map) | Ingress self access port list of objects: from, to, proto, description | <pre>list(object({<br/> from = number<br/> to = number<br/> proto = any<br/> description = string<br/> }))</pre> | `[]` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Extra security group tags | `map` | `{}` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Extra security group tags | `map(any)` | `{}` | no |
| <a name="input_use_vpc_cidr"></a> [use\_vpc\_cidr](#input\_use\_vpc\_cidr) | Enable\|Disable use of VPC CIDR block in the ingress\_networks | `bool` | `false` | no |
| <a name="input_vpc_full_name"></a> [vpc\_full\_name](#input\_vpc\_full\_name) | VPC Name | `string` | `""` | no |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | VPC ID Number | `string` | n/a | yes |
Expand Down
2 changes: 1 addition & 1 deletion common/variables.common.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ variable "egress_security_groups" {

variable "tags" {
description = "Extra security group tags"
type = map
type = map(any)
default = {}
}

Expand Down
2 changes: 1 addition & 1 deletion common/version.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
locals {
_module_version = "2.6.2"
_module_version = "2.7.0"
}
37 changes: 31 additions & 6 deletions custom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,36 @@ module "sg_test" {
}
```

## ingress\_prefix\_list\_names and ingress\_prefix\_list\_ports
In order to use a managed prefix list, you may pass a list of names in this field. The prefix lists
will be looked up and the resultant IDs used in the security group for inbound port access to
the port structure in `ingress_prefix_list_ports` as follows:

```hcl
[ { from = NUMBER, to = NUMBER, proto = NUMBER-OR-STRING, label = STRING }, ]
```

## egress\_prefix\_list\_names and egress\_prefix\_list\_ports
In order to use a managed prefix list, you may pass a list of names in this field. The prefix lists
will be looked up and the resultant IDs used in the security group for outbound port access to
the port structure in `egress_prefix_list_ports` as follows:

```hcl
[ { from = NUMBER, to = NUMBER, proto = NUMBER-OR-STRING, label = STRING }, ]
```

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.12 |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | n/a |
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.0 |

## Modules

Expand All @@ -123,6 +142,8 @@ No modules.
| [aws_security_group.this_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_arn.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/arn) | data source |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_ec2_managed_prefix_list.egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ec2_managed_prefix_list) | data source |
| [aws_ec2_managed_prefix_list.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ec2_managed_prefix_list) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
| [aws_security_group.egress_security_groups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/security_group) | data source |
| [aws_security_group.ingress_security_groups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/security_group) | data source |
Expand All @@ -133,19 +154,23 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_description"></a> [description](#input\_description) | Security Group Description | `string` | `""` | no |
| <a name="input_egress_networks"></a> [egress\_networks](#input\_egress\_networks) | List of egress networks (with all pre-defined egress ports) (default: any) | `list(string)` | <pre>[<br> "0.0.0.0/0"<br>]</pre> | no |
| <a name="input_egress_networks"></a> [egress\_networks](#input\_egress\_networks) | List of egress networks (with all pre-defined egress ports) (default: any) | `list(string)` | <pre>[<br/> "0.0.0.0/0"<br/>]</pre> | no |
| <a name="input_egress_prefix_list_names"></a> [egress\_prefix\_list\_names](#input\_egress\_prefix\_list\_names) | List of prefix list names for eggress access | `list(string)` | `[]` | no |
| <a name="input_egress_prefix_list_ports"></a> [egress\_prefix\_list\_ports](#input\_egress\_prefix\_list\_ports) | List of port objects (from,to,proto,label) for egress prefix lists | <pre>list(object({<br/> from = number<br/> to = number<br/> proto = optional(string, "tcp")<br/> label = optional(string)<br/> }))</pre> | <pre>[<br/> {<br/> "from": 0,<br/> "label": "all",<br/> "proto": -1,<br/> "to": 0<br/> }<br/>]</pre> | no |
| <a name="input_egress_security_groups"></a> [egress\_security\_groups](#input\_egress\_security\_groups) | List of egress security groups (all ports) | `list(string)` | `[]` | no |
| <a name="input_enable_default_egress"></a> [enable\_default\_egress](#input\_enable\_default\_egress) | Enable\|Disable default egress of ALL | `bool` | `true` | no |
| <a name="input_enable_self"></a> [enable\_self](#input\_enable\_self) | Enable\|Disable self full access | `bool` | `false` | no |
| <a name="input_ingress_networks"></a> [ingress\_networks](#input\_ingress\_networks) | List of ingress networks for access (with all pre-defined ingress ports) | `list(string)` | `[]` | no |
| <a name="input_ingress_port_list"></a> [ingress\_port\_list](#input\_ingress\_port\_list) | Ingress port list of 5-tuple: from, to, proto, description, and cidr(list) | `list` | `[]` | no |
| <a name="input_ingress_port_map"></a> [ingress\_port\_map](#input\_ingress\_port\_map) | Ingress port list of objects: from, to, proto, description and cidr(list) | <pre>list(object({<br> from = number<br> to = number<br> proto = any<br> description = string<br> cidr = list(string)<br> }))</pre> | `[]` | no |
| <a name="input_ingress_port_map"></a> [ingress\_port\_map](#input\_ingress\_port\_map) | Ingress port list of objects: from, to, proto, description and cidr(list) | <pre>list(object({<br/> from = number<br/> to = number<br/> proto = any<br/> description = string<br/> cidr = list(string)<br/> }))</pre> | `[]` | no |
| <a name="input_ingress_prefix_list_names"></a> [ingress\_prefix\_list\_names](#input\_ingress\_prefix\_list\_names) | List of prefix list names for ingress access | `list(string)` | `[]` | no |
| <a name="input_ingress_prefix_list_ports"></a> [ingress\_prefix\_list\_ports](#input\_ingress\_prefix\_list\_ports) | List of port objects (from,to,proto,label) for ingress prefix lists | <pre>list(object({<br/> from = number<br/> to = number<br/> proto = optional(string, "tcp")<br/> label = optional(string)<br/> }))</pre> | `[]` | no |
| <a name="input_ingress_security_groups"></a> [ingress\_security\_groups](#input\_ingress\_security\_groups) | List of ingress security groups for all ports | `list(string)` | `[]` | no |
| <a name="input_ingress_self_port_list"></a> [ingress\_self\_port\_list](#input\_ingress\_self\_port\_list) | Ingress port list of 4-tuple: from, to, proto, description | `list` | `[]` | no |
| <a name="input_ingress_self_port_map"></a> [ingress\_self\_port\_map](#input\_ingress\_self\_port\_map) | Ingress self access port list of objects: from, to, proto, description | <pre>list(object({<br> from = number<br> to = number<br> proto = any<br> description = string<br> }))</pre> | `[]` | no |
| <a name="input_ingress_self_port_map"></a> [ingress\_self\_port\_map](#input\_ingress\_self\_port\_map) | Ingress self access port list of objects: from, to, proto, description | <pre>list(object({<br/> from = number<br/> to = number<br/> proto = any<br/> description = string<br/> }))</pre> | `[]` | no |
| <a name="input_name"></a> [name](#input\_name) | Security Group Name (required) | `string` | n/a | yes |
| <a name="input_short_description"></a> [short\_description](#input\_short\_description) | Security Group Short Description | `string` | `""` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Extra security group tags | `map` | `{}` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Extra security group tags | `map(any)` | `{}` | no |
| <a name="input_use_vpc_cidr"></a> [use\_vpc\_cidr](#input\_use\_vpc\_cidr) | Enable\|Disable use of VPC CIDR block in the ingress\_networks | `bool` | `false` | no |
| <a name="input_vpc_full_name"></a> [vpc\_full\_name](#input\_vpc\_full\_name) | VPC Name | `string` | `""` | no |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | VPC ID Number | `string` | n/a | yes |
Expand Down
185 changes: 185 additions & 0 deletions custom/custom.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
locals {
vpc_networks = var.use_vpc_cidr ? [data.aws_vpc.this_vpc[0].cidr_block] : []
external_ingress_networks = compact(concat(local.vpc_networks, local.ingress_networks))
ingress_sg_names = zipmap(var.ingress_security_groups, data.aws_security_group.ingress_security_groups[*].name)
egress_sg_names = zipmap(var.egress_security_groups, data.aws_security_group.egress_security_groups[*].name)
# self = var.enable_self ? local.self_ports : []
}

resource "aws_security_group" "this_security_group" {
name = local.name
description = var.description
vpc_id = var.vpc_id

#---
# ingress
#---
# ingresss external port list (list + vpc if enabaled)
dynamic "ingress" {
for_each = local.port_map["external"]
iterator = p
content {
description = "${local.short_description}: ${p.value["description"]}"
from_port = p.value["from"]
to_port = p.value["to"]
protocol = p.value["proto"]
cidr_blocks = length(p.value["cidr"]) == 0 ? distinct(flatten(compact(concat(local.external_ingress_networks, var.ingress_networks)))) : distinct(flatten(compact(concat(p.value["cidr"], var.ingress_networks))))
}
}

# ingress module-defined ports
dynamic "ingress" {
for_each = local.port_map["module_ports"]
iterator = p
content {
description = "${local.short_description}: ${p.value["description"]}"
from_port = p.value["from"]
to_port = p.value["to"]
protocol = p.value["proto"]
cidr_blocks = length(p.value["cidr"]) == 0 ? distinct(flatten(compact(concat(local.external_ingress_networks, var.ingress_networks)))) : distinct(flatten(compact(concat(p.value["cidr"], var.ingress_networks))))
}
}

# ingress_ports
dynamic "ingress" {
for_each = local.port_map["ingress_ports"]
iterator = p
content {
description = "${local.short_description}: ${p.value["description"]}"
from_port = p.value["from"]
to_port = p.value["to"]
protocol = p.value["proto"]
cidr_blocks = length(p.value["cidr"]) == 0 ? distinct(flatten(compact(concat(local.external_ingress_networks, var.ingress_networks)))) : distinct(flatten(compact(concat(p.value["cidr"], var.ingress_networks))))
}
}

# ingress map
dynamic "ingress" {
for_each = local.port_map["ingress_map"]
iterator = p
content {
description = "${local.short_description}: ${p.value["description"]}"
from_port = p.value["from"]
to_port = p.value["to"]
protocol = p.value["proto"]
cidr_blocks = length(p.value["cidr"]) == 0 ? distinct(flatten(compact(concat(local.external_ingress_networks, var.ingress_networks)))) : distinct(flatten(compact(concat(p.value["cidr"], var.ingress_networks))))
}
}

# ingress security group ids (all)
dynamic "ingress" {
for_each = local.ingress_sg
iterator = sg
content {
description = "${local.short_description}: ${local.ingress_sg_names[sg.value]}"
from_port = 0
to_port = 0
protocol = -1
security_groups = [sg.value]
}
}

#---
# ingress self
#---
# ingress self port list
dynamic "ingress" {
for_each = var.enable_self ? local.self_port_map["ingress_ports"] : []
iterator = sg
content {
description = "${local.short_description}: self ${sg.value["description"]}"
from_port = sg.value["from"]
to_port = sg.value["to"]
protocol = sg.value["proto"]
self = true
}
}

# ingress self port map
dynamic "ingress" {
for_each = var.enable_self ? local.self_port_map["ingress_map"] : []
iterator = sg
content {
description = "${local.short_description}: self ${sg.value["description"]}"
from_port = sg.value["from"]
to_port = sg.value["to"]
protocol = sg.value["proto"]
self = true
}
}

# ingress self port default
dynamic "ingress" {
for_each = var.enable_self ? local.self_port_map["default"] : []
iterator = sg
content {
description = "${local.short_description}: self ${sg.value["description"]}"
from_port = sg.value["from"]
to_port = sg.value["to"]
protocol = sg.value["proto"]
self = true
}
}

# ingress with prefix lists
dynamic "ingress" {
for_each = length(var.ingress_prefix_list_names) > 0 && length(var.ingress_prefix_list_ports) > 0 ? toset(var.ingress_prefix_list_ports) : toset([])
iterator = p
content {
description = try(p.value.label, local.short_description)
from_port = p.value.from
to_port = p.value.to
protocol = p.value.proto
prefix_list_ids = [for pl in data.aws_ec2_managed_prefix_list.ingress : pl.id]
}
}

# egress all (with flag enable_default_egress)
dynamic "egress" {
for_each = var.enable_default_egress ? [1] : []
iterator = sg
content {
description = "${local.short_description}: All"
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = distinct(flatten(compact(concat(local.egress_networks, var.egress_networks))))
}
}

# egress security group ids (all)
dynamic "egress" {
for_each = local.egress_sg
iterator = sg
content {
description = "${local.short_description}: ${local.egress_sg_names[sg]}"
from_port = 0
to_port = 0
protocol = -1
security_groups = [sg]
}
}

# egress with prefix lists
dynamic "egress" {
for_each = length(var.egress_prefix_list_names) > 0 && length(var.egress_prefix_list_ports) > 0 ? toset(var.egress_prefix_list_ports) : toset([])
iterator = p
content {
description = try(p.value.label, local.short_description)
from_port = p.value.from
to_port = p.value.to
protocol = p.value.proto
prefix_list_ids = [for pl in data.aws_ec2_managed_prefix_list.egress : pl.id]
}
}

tags = merge(
var.tags,
{
"Name" = "sg-${local.name}"
"boc:created_by" = "terraform"
"boc:tf_module_version" = local._module_version
"boc:vpc:info" = join(" ", compact([var.vpc_id, var.vpc_full_name]))
}
)
}
1 change: 1 addition & 0 deletions custom/data.prefix_lists.tf
18 changes: 18 additions & 0 deletions custom/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,24 @@
* )
* }
* ```
*
* ## ingress_prefix_list_names and ingress_prefix_list_ports
* In order to use a managed prefix list, you may pass a list of names in this field. The prefix lists
* will be looked up and the resultant IDs used in the security group for inbound port access to
* the port structure in `ingress_prefix_list_ports` as follows:
*
* ```hcl
* [ { from = NUMBER, to = NUMBER, proto = NUMBER-OR-STRING, label = STRING }, ]
* ```
*
* ## egress_prefix_list_names and egress_prefix_list_ports
* In order to use a managed prefix list, you may pass a list of names in this field. The prefix lists
* will be looked up and the resultant IDs used in the security group for outbound port access to
* the port structure in `egress_prefix_list_ports` as follows:
*
* ```hcl
* [ { from = NUMBER, to = NUMBER, proto = NUMBER-OR-STRING, label = STRING }, ]
* ```
*/

# all of the code is in resource.tf, this is here for documention
1 change: 0 additions & 1 deletion custom/resources.tf

This file was deleted.

2 changes: 1 addition & 1 deletion custom/settings.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
locals {
name = var.name != "" ? var.name : local._defaults["name"]
is_modular = var.name == "" || length(regexall("^m-", var.name)) > 0
enable_self = var.enable_self ? ! local.is_modular : false
enable_self = var.enable_self ? !local.is_modular : false
description = var.description != "" ? var.description : local._defaults["description"]
short_description = var.short_description != "" ? var.short_description : local._defaults["short_description"]
}
1 change: 1 addition & 0 deletions custom/variables.prefix_lists.tf
22 changes: 22 additions & 0 deletions custom/variables.prefix_lists_ports.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
variable "ingress_prefix_list_ports" {
description = "List of port objects (from,to,proto,label) for ingress prefix lists"
type = list(object({
from = number
to = number
proto = optional(string, "tcp")
label = optional(string)
}))
default = []
}

variable "egress_prefix_list_ports" {
description = "List of port objects (from,to,proto,label) for egress prefix lists"
type = list(object({
from = number
to = number
proto = optional(string, "tcp")
label = optional(string)
}))
default = [{ from = 0, to = 0, proto = -1, label = "all" }]
}

26 changes: 26 additions & 0 deletions examples/custom-prefix-lists/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
data "aws_vpc" "vpc" {
filter {
name = "tag:Name"
values = [var.vpc_full_name]
}
}

module "sg_bigfix" {
source = "git@github.e.it.census.gov:terraform-modules/aws-common-security-groups.git//custom?ref=feature/add-prefix-list"
vpc_id = data.aws_vpc.vpc.id
name = "ois-bigfix"
description = "OIS Bigfix Service Port"
short_description = "BigFix"
enable_self = false

ingress_prefix_list_names = ["all-cloud.core"]
ingress_prefix_list_ports = [
{ from = 52311, to = 52311, proto = "tcp", label = "BigFix-Relay" },
]

tags = merge(
local.base_tags,
# var.application_tags,
# etc
)
}

0 comments on commit 8b6221a

Please sign in to comment.