diff --git a/CHANGELOG.md b/CHANGELOG.md index 2185061..f2fadfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,3 +74,5 @@ - emr - add emr-workspace +* 2.6.0 -- 2025-01-28 + - redshift: new submodule diff --git a/common/version.tf b/common/version.tf index c3236f6..b061df5 100644 --- a/common/version.tf +++ b/common/version.tf @@ -1,3 +1,3 @@ locals { - _module_version = "2.5.2" + _module_version = "2.6.0" } diff --git a/redshift/README.md b/redshift/README.md new file mode 100644 index 0000000..7bba0f6 --- /dev/null +++ b/redshift/README.md @@ -0,0 +1,90 @@ +# About redshift + +This describes how to use the aws-common-security-groups submodule for redshift. + +Default and auxilliary ports are included in this. They are opened to everything. + +## Usage + +```hcl +module "redshift" { + source = "git@github.e.it.census.gov:terraform-modules/aws-common-security-groups.git//redshift?ref=tf-ugprade" + + vpc_id = var.vpc_id + ## optional + # name = "m-redshift" + # ingress_prefix_list_names = [ "wifi-networks.core", "vpn-networks.core" ] + # egress_prefix_list_names = [ ] + + ## tags for Name, CostAllocation, and Environment are pre-set, but they can be overriden + # tags = { } +} +``` + +## ingress\_networks +This is the list of network CIDR blocks for inbound access to the ports defined for Redshift. +There is a default set of CIDR blocks provided if this field is not populated. This is comprised of the +Census networks: +* 148.129.0.0/16: Census class B +* 172.16.0.0/12: Census private class B +* 192.168.0.0/16: Census private class C +* 10.0.0.0/8: Census private class A + +Passing a null or empty list to this field will ignore the ingress setting on these networks. + +## ingress\_prefix\_list\_names +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 Redshift. +This will fail if the prefix list does not exist. + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [aws](#requirement\_aws) | >= 5.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_security_group.this_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [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_vpc.this_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [description](#input\_description) | Security Group Description | `string` | `"Redshift Security Group"` | no | +| [egress\_networks](#input\_egress\_networks) | List of egress networks (all ports) | `list(string)` |
[| no | +| [egress\_prefix\_list\_names](#input\_egress\_prefix\_list\_names) | List of prefix list names for eggress access | `list(string)` | `[]` | no | +| [egress\_security\_groups](#input\_egress\_security\_groups) | List of egress security groups (all ports) | `list(string)` | `[]` | no | +| [enable\_self](#input\_enable\_self) | Enable\|Disable self full access | `bool` | `false` | no | +| [ingress\_networks](#input\_ingress\_networks) | List of ingress networks for external access (not all ports). Use null to disable built-in settings | `list(string)` |
"0.0.0.0/0"
]
[| no | +| [ingress\_prefix\_list\_names](#input\_ingress\_prefix\_list\_names) | List of prefix list names for ingress access | `list(string)` | `[]` | no | +| [ingress\_security\_groups](#input\_ingress\_security\_groups) | List of ingress security groups for all ports | `list(string)` | `[]` | no | +| [name](#input\_name) | Security Group Name | `string` | `"m-redshift"` | no | +| [short\_description](#input\_short\_description) | Security Group Short Description | `string` | `"redshift"` | no | +| [tags](#input\_tags) | Extra security group tags | `map` |
"0.0.0.0/0"
]
{
"CostAllocation": "csvd:infrastructure",
"Environment": "csvd-infrastructure"
} | no |
+| [use\_vpc\_cidr](#input\_use\_vpc\_cidr) | Enable\|Disable use of VPC CIDR block in the ingress\_networks | `bool` | `false` | no |
+| [vpc\_full\_name](#input\_vpc\_full\_name) | VPC Name | `string` | `""` | no |
+| [vpc\_id](#input\_vpc\_id) | VPC ID Number | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [this\_security\_group\_arn](#output\_this\_security\_group\_arn) | Created security group ARN |
+| [this\_security\_group\_id](#output\_this\_security\_group\_id) | Created security group ID |
diff --git a/redshift/data.prefix_lists.tf b/redshift/data.prefix_lists.tf
new file mode 100644
index 0000000..23af189
--- /dev/null
+++ b/redshift/data.prefix_lists.tf
@@ -0,0 +1,15 @@
+data "aws_ec2_managed_prefix_list" "ingress" {
+ for_each = toset(var.ingress_prefix_list_names)
+ filter {
+ name = "prefix-list-name"
+ values = [each.key]
+ }
+}
+
+data "aws_ec2_managed_prefix_list" "egress" {
+ for_each = toset(var.egress_prefix_list_names)
+ filter {
+ name = "prefix-list-name"
+ values = [each.key]
+ }
+}
diff --git a/redshift/main.tf b/redshift/main.tf
new file mode 100644
index 0000000..8057d27
--- /dev/null
+++ b/redshift/main.tf
@@ -0,0 +1,172 @@
+/**
+* # About redshift
+*
+* This describes how to use the aws-common-security-groups submodule for redshift.
+*
+* Default and auxilliary ports are included in this. They are opened to everything.
+*
+* ## Usage
+*
+* ```hcl
+* module "redshift" {
+* source = "git@github.e.it.census.gov:terraform-modules/aws-common-security-groups.git//redshift?ref=tf-ugprade"
+*
+* vpc_id = var.vpc_id
+* ## optional
+* # name = "m-redshift"
+* # ingress_prefix_list_names = [ "wifi-networks.core", "vpn-networks.core" ]
+* # egress_prefix_list_names = [ ]
+*
+* ## tags for Name, CostAllocation, and Environment are pre-set, but they can be overriden
+* # tags = { }
+* }
+* ```
+*
+* ## ingress_networks
+* This is the list of network CIDR blocks for inbound access to the ports defined for Redshift.
+* There is a default set of CIDR blocks provided if this field is not populated. This is comprised of the
+* Census networks:
+* * 148.129.0.0/16: Census class B
+* * 172.16.0.0/12: Census private class B
+* * 192.168.0.0/16: Census private class C
+* * 10.0.0.0/8: Census private class A
+*
+* Passing a null or empty list to this field will ignore the ingress setting on these networks.
+*
+* ## ingress_prefix_list_names
+* 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 Redshift.
+* This will fail if the prefix list does not exist.
+*/
+
+data "aws_vpc" "this_vpc" {
+ count = var.use_vpc_cidr ? 1 : 0
+ id = var.vpc_id
+}
+
+## data "aws_security_group" "ingress_security_groups" {
+## for_each = toset(var.ingress_security_groups))
+## id = each.key
+## }
+##
+## data "aws_security_group" "egress_security_groups" {
+## for_each = toset(var.egress_security_groups)
+## id = each.key
+## }
+
+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 ? [1] : []
+ short_description = var.short_description == "" ? var.description : var.short_description
+}
+
+resource "aws_security_group" "this_security_group" {
+ name = local.name
+ description = var.description
+ vpc_id = var.vpc_id
+
+ # ingresss external port list (list + vpc if enabaled)
+ dynamic "ingress" {
+ for_each = (var.ingress_networks != null && length(local.ingress_networks) > 0) ? local.port_map["external"] : toset([])
+ 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(local.external_ingress_networks) > 0 ? local.external_ingress_networks : p.value["cidr"]
+ }
+ }
+
+
+ # ingress with prefix lists
+ dynamic "ingress" {
+ for_each = length(var.ingress_prefix_list_names) > 0 ? local.port_map["external"] : toset([])
+ iterator = p
+ content {
+ description = "${local.short_description}: ${p.value["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]
+ }
+ }
+
+
+ # ingress security group ids (just defined ports)
+ dynamic "ingress" {
+ for_each = length(local.ingress_sg) > 0 ? local.port_map["external"] : toset([])
+ iterator = p
+ content {
+ description = "${local.short_description}: ${p.value["description"]}"
+ from_port = p.value["from"]
+ to_port = p.value["to"]
+ protocol = p.value["proto"]
+ security_groups = local.ingress_sg
+ }
+ }
+
+
+ # ingress self (list with one or zero items)
+ dynamic "ingress" {
+ for_each = var.enable_self ? local.port_map["external"] : toset([])
+ iterator = p
+ content {
+ description = "${local.short_description}: ${p.value["description"]}"
+ from_port = p.value["from"]
+ to_port = p.value["to"]
+ protocol = p.value["proto"]
+ self = true
+ }
+ }
+
+
+ # egress all
+ # for_each = (var.egress_networks != null && length(local.egress_networks) > 0) ? local.port_map["external"] : toset([])
+ egress {
+ description = "${local.short_description}: All"
+ from_port = 0
+ to_port = 0
+ protocol = -1
+ cidr_blocks = local.egress_networks
+ }
+
+ # egress security group ids (all)
+ dynamic "egress" {
+ for_each = length(local.egress_sg) > 0 ? { 1 = 1 } : {}
+ iterator = sg
+ content {
+ description = "${local.short_description}"
+ from_port = 0
+ to_port = 0
+ protocol = -1
+ security_groups = local.egress_sg
+ }
+ }
+
+ # egress with prefix lists
+ dynamic "egress" {
+ for_each = length(var.egress_prefix_list_names) > 0 ? { 1 = 1 } : {}
+ iterator = p
+ content {
+ description = "${local.short_description}"
+ from_port = 0
+ to_port = 0
+ protocol = -1
+ 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]))
+ }
+ )
+}
diff --git a/redshift/output.tf b/redshift/output.tf
new file mode 100644
index 0000000..fbdd35a
--- /dev/null
+++ b/redshift/output.tf
@@ -0,0 +1,9 @@
+output "this_security_group_id" {
+ description = "Created security group ID"
+ value = aws_security_group.this_security_group.id
+}
+
+output "this_security_group_arn" {
+ description = "Created security group ARN"
+ value = aws_security_group.this_security_group.arn
+}
diff --git a/redshift/ports.tf b/redshift/ports.tf
new file mode 100644
index 0000000..c7d6184
--- /dev/null
+++ b/redshift/ports.tf
@@ -0,0 +1,33 @@
+# ports = list of list of
+# from_port
+# to_port
+# proto
+# description
+# cidr_block
+# list of: all, external (more added as needed)
+
+locals {
+ description = "module: Redshift"
+ n_all = ["0.0.0.0/0"]
+ n_census = ["148.129.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "10.0.0.0/8"]
+ source_groups = ["all", "external"]
+
+ name = var.name
+ ports = [
+ [5439, 5439, "tcp", "redshift", local.n_census, ["external"]],
+ ]
+
+ # these are ignored
+ ingress_networks = var.ingress_networks == null ? [] : var.ingress_networks
+ egress_networks = var.egress_networks == null ? [] : var.egress_networks
+
+ # these are ignored
+ ingress_sg = var.ingress_security_groups
+ egress_sg = var.egress_security_groups
+
+ p_fields = ["from", "to", "proto", "description", "cidr", "source_group"]
+ p_map = [for p in local.ports : zipmap(local.p_fields, p)]
+ port_map = { for s in local.source_groups :
+ s => [for p in local.p_map : p if contains(p["source_group"], s)]
+ }
+}
diff --git a/redshift/variables.tf b/redshift/variables.tf
new file mode 100644
index 0000000..8061571
--- /dev/null
+++ b/redshift/variables.tf
@@ -0,0 +1,91 @@
+#---
+# change between different modules as needed
+#---
+variable "name" {
+ description = "Security Group Name"
+ type = string
+ default = "m-redshift"
+}
+
+variable "description" {
+ description = "Security Group Description"
+ type = string
+ default = "Redshift Security Group"
+}
+
+variable "short_description" {
+ description = "Security Group Short Description"
+ type = string
+ default = "redshift"
+}
+
+variable "enable_self" {
+ description = "Enable|Disable self full access"
+ type = bool
+ default = false
+}
+
+variable "use_vpc_cidr" {
+ description = "Enable|Disable use of VPC CIDR block in the ingress_networks"
+ type = bool
+ default = false
+}
+
+#---
+# others with defaults
+#---
+variable "vpc_id" {
+ description = "VPC ID Number"
+ type = string
+}
+
+variable "vpc_full_name" {
+ description = "VPC Name"
+ type = string
+ default = ""
+}
+
+variable "ingress_networks" {
+ description = "List of ingress networks for external access (not all ports). Use null to disable built-in settings"
+ type = list(string)
+ default = ["0.0.0.0/0"]
+}
+
+variable "egress_networks" {
+ description = "List of egress networks (all ports)"
+ type = list(string)
+ default = ["0.0.0.0/0"]
+}
+
+variable "ingress_security_groups" {
+ description = "List of ingress security groups for all ports"
+ type = list(string)
+ default = []
+}
+
+variable "egress_security_groups" {
+ description = "List of egress security groups (all ports)"
+ type = list(string)
+ default = []
+}
+
+variable "tags" {
+ description = "Extra security group tags"
+ type = map
+ default = {
+ "CostAllocation" = "csvd:infrastructure"
+ "Environment" = "csvd-infrastructure"
+ }
+}
+
+variable "ingress_prefix_list_names" {
+ description = "List of prefix list names for ingress access"
+ type = list(string)
+ default = []
+}
+
+variable "egress_prefix_list_names" {
+ description = "List of prefix list names for eggress access"
+ type = list(string)
+ default = []
+}
diff --git a/redshift/version.tf b/redshift/version.tf
new file mode 120000
index 0000000..b83c5b7
--- /dev/null
+++ b/redshift/version.tf
@@ -0,0 +1 @@
+../common/version.tf
\ No newline at end of file
diff --git a/redshift/versions.tf b/redshift/versions.tf
new file mode 120000
index 0000000..41bb22f
--- /dev/null
+++ b/redshift/versions.tf
@@ -0,0 +1 @@
+../common/versions.tf
\ No newline at end of file