diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fd239b5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# CHANGELOG + +* v2.0.0 -- 20210528 + - create a common set of files to not replicate the logic + - consolidate all the submodules to use the common structure + +* v2.1.0 -- 20211021 + - sas + - add sas submodule, which can be used for a general module or a specific application module + +## web + +* v1.0.0 -- 20210604 + - add module version, update tags + +* v1.1.0 -- 20210915 + - enable use of ingress_networks and egress_networks for pre-defined port list + +* v1.1.1 -- 20210929 + - fix default egress to be 0/0 for web submodule diff --git a/common/README.md b/common/README.md new file mode 100644 index 0000000..6c851f6 --- /dev/null +++ b/common/README.md @@ -0,0 +1,48 @@ +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## 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_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_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 | +| [aws_vpc.this_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [egress\_networks](#input\_egress\_networks) | List of egress networks (with all pre-defined egress ports) | `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 access (with all pre-defined ingress ports) | `list(string)` | `[]` | no | +| [ingress\_security\_groups](#input\_ingress\_security\_groups) | List of ingress security groups for all ports | `list(string)` | `[]` | no | +| [tags](#input\_tags) | Extra security group tags | `map` | `{}` | 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/common/data.tf b/common/data.tf new file mode 100644 index 0000000..7e23a04 --- /dev/null +++ b/common/data.tf @@ -0,0 +1,8 @@ +data "aws_caller_identity" "current" {} + +data "aws_arn" "current" { + arn = data.aws_caller_identity.current.arn +} + +data "aws_region" "current" {} + diff --git a/common/data.vpc.tf b/common/data.vpc.tf new file mode 100644 index 0000000..bdc98ab --- /dev/null +++ b/common/data.vpc.tf @@ -0,0 +1,14 @@ +data "aws_vpc" "this_vpc" { + count = var.use_vpc_cidr ? 1 : 0 + id = var.vpc_id +} + +data "aws_security_group" "ingress_security_groups" { + count = length(var.ingress_security_groups) + id = element(var.ingress_security_groups, count.index) +} + +data "aws_security_group" "egress_security_groups" { + count = length(var.egress_security_groups) + id = element(var.egress_security_groups, count.index) +} diff --git a/common/output.tf b/common/output.tf new file mode 100644 index 0000000..fbdd35a --- /dev/null +++ b/common/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/common/ports.tf b/common/ports.tf new file mode 100644 index 0000000..ebb8931 --- /dev/null +++ b/common/ports.tf @@ -0,0 +1,37 @@ +# ports = list of list of +# from_port +# to_port +# proto +# description +# cidr_block +# list of: all, external (more added as needed) + +# example only. Use your own values as appropraite + +locals { + 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"] + + ports = [ + [80, 80, "tcp", "http", local.n_census, ["external"]], + [443, 443, "tcp", "https", local.n_census, ["external"]], + [8080, 8080, "tcp", "Tomcat-http", local.n_census, ["external"]], + [8443, 8443, "tcp", "Tomcat-https", local.n_census, ["external"]], + ] + + # ingress_networks = var.ingress_networks + ingress_networks = [] + # egress_networks = var.egress_networks + egress_networks = local.n_all + + # 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/common/resources.tf b/common/resources.tf new file mode 100644 index 0000000..41d3adb --- /dev/null +++ b/common/resources.tf @@ -0,0 +1,82 @@ +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] : [] +} + +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 = 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 ? flatten(compact(concat(local.external_ingress_networks, var.ingress_networks))) : 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 (list with one or zero items) + dynamic "ingress" { + for_each = local.self + iterator = sg + content { + description = "${local.short_description}: from self" + from_port = 0 + to_port = 0 + protocol = -1 + self = true + } + } + + # egress all + egress { + description = "${local.short_description}: All" + from_port = 0 + to_port = 0 + protocol = -1 + cidr_blocks = 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] + } + } + + tags = merge( + map("Name", "sg-${local.name}"), + var.tags, + map("boc:created_by", "terraform"), + map("boc:tf_module_version", local._module_version), + map("boc:vpc:info", join(" ", compact(list(var.vpc_id, var.vpc_full_name)))), + ) +} diff --git a/common/variables.common.tf b/common/variables.common.tf new file mode 100644 index 0000000..d001a04 --- /dev/null +++ b/common/variables.common.tf @@ -0,0 +1,41 @@ +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 +} + +variable "ingress_networks" { + description = "List of ingress networks for access (with all pre-defined ingress ports)" + type = list(string) + default = [] +} + +variable "egress_networks" { + description = "List of egress networks (with all pre-defined egress ports)" + type = list(string) + default = [] +} + +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 = {} +} diff --git a/common/variables.tf.example b/common/variables.tf.example new file mode 100644 index 0000000..1738dcf --- /dev/null +++ b/common/variables.tf.example @@ -0,0 +1,19 @@ +# copy this file, and replace it with the appropriate defaults for a module + +variable "name" { + description = "Security Group Name" + type = string +# default = "REPLACE" +} + +variable "description" { + description = "Security Group Description" + type = string +# default = "REPLACE" +} + +variable "short_description" { + description = "Security Group Short Description" + type = string +# default = "REPLACE" +} diff --git a/common/variables.vpc.tf b/common/variables.vpc.tf new file mode 100644 index 0000000..9e52219 --- /dev/null +++ b/common/variables.vpc.tf @@ -0,0 +1,12 @@ +variable "vpc_id" { + description = "VPC ID Number" + type = string +} + +variable "vpc_full_name" { + description = "VPC Name" + type = string + default = "" +} + + diff --git a/common/version.tf b/common/version.tf new file mode 100644 index 0000000..55a44df --- /dev/null +++ b/common/version.tf @@ -0,0 +1,3 @@ +locals { + _module_version = "2.1.0" +} diff --git a/common/versions.tf b/common/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/common/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/general/CHANGELOG.md b/general/CHANGELOG.md new file mode 100644 index 0000000..642dea2 --- /dev/null +++ b/general/CHANGELOG.md @@ -0,0 +1,2 @@ +# v1.0.0 -- 20210429 + * create new general submodule diff --git a/general/README.md b/general/README.md new file mode 100644 index 0000000..d4b7039 --- /dev/null +++ b/general/README.md @@ -0,0 +1,69 @@ +# About it-windows-base + +This describes how to use the aws-common-security-groups submodule for it-windows-base. + +Commonly used ports and services are set up here, including ICMP, AD, RDP, NTP, DNS, SNMP, +monit, munin, iperf, netperf, NetBackup and Opsware. + +## Usage + +```hcl +module "it-windows-base" { + source = "git@github.e.it.census.gov:terraform-modules/aws-common-security-groups.git//it-windows-base" + + # name = "it-windows-base" + vpc_id = var.vpc_id + # Name, CostAllocation, and Environment are pre-set, but they can be overriden + # tags = { } +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## 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_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 | +| [aws_vpc.selected](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | 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` | `"Windows Common Base Security Group"` | no | +| [egress\_networks](#input\_egress\_networks) | List of egress networks (all ports) | `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) | `list(string)` |
"0.0.0.0/0"
]
[| 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` | `"it-windows-base"` | no | +| [short\_description](#input\_short\_description) | Security Group Short Description | `string` | `"Windows"` | 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/general/main.tf b/general/main.tf
new file mode 100644
index 0000000..2c45a16
--- /dev/null
+++ b/general/main.tf
@@ -0,0 +1,121 @@
+/**
+* # About it-windows-base
+*
+* This describes how to use the aws-common-security-groups submodule for it-windows-base.
+*
+* Commonly used ports and services are set up here, including ICMP, AD, RDP, NTP, DNS, SNMP,
+* monit, munin, iperf, netperf, NetBackup and Opsware.
+*
+* ## Usage
+*
+* ```hcl
+* module "it-windows-base" {
+* source = "git@github.e.it.census.gov:terraform-modules/aws-common-security-groups.git//it-windows-base"
+*
+* # name = "it-windows-base"
+* vpc_id = var.vpc_id
+* # Name, CostAllocation, and Environment are pre-set, but they can be overriden
+* # tags = { }
+* }
+* ```
+*/
+
+data "aws_vpc" "this_vpc" {
+ count = var.use_vpc_cidr ? 1 : 0
+ id = var.vpc_id
+}
+
+data "aws_security_group" "ingress_security_groups" {
+ count = length(var.ingress_security_groups)
+ id = element(var.ingress_security_groups, count.index)
+}
+
+data "aws_security_group" "egress_security_groups" {
+ count = length(var.egress_security_groups)
+ id = element(var.egress_security_groups, count.index)
+}
+
+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
+ # vpc_id = "${data.aws_vpc.selected.id}"
+
+ # 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 ? local.external_ingress_networks : p.value["cidr"]
+ }
+ }
+
+ # 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 (list with one or zero items)
+ dynamic "ingress" {
+ for_each = local.self
+ iterator = sg
+ content {
+ description = "${local.short_description}: from self"
+ from_port = 0
+ to_port = 0
+ protocol = -1
+ self = true
+ }
+ }
+
+ # egress all
+ 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 = 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]
+ }
+ }
+
+ tags = merge(
+ map("Name", "sg-${local.name}"),
+ var.tags,
+ map("boc:created_by", "terraform"),
+ map("boc:tf_module_version", local._module_version),
+ map("boc:vpc:info", join(" ", compact(list(var.vpc_id, var.vpc_full_name)))),
+ )
+}
diff --git a/general/output.tf b/general/output.tf
new file mode 100644
index 0000000..fbdd35a
--- /dev/null
+++ b/general/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/general/ports.tf b/general/ports.tf
new file mode 100644
index 0000000..6b9aee2
--- /dev/null
+++ b/general/ports.tf
@@ -0,0 +1,59 @@
+# ports = list of list of
+# from_port
+# to_port
+# proto
+# description
+# cidr_block
+# list of: all, external (more added as needed)
+
+## % python modify-security-groups.py list sg-00fb5065
+## sg_id=sg-00fb5065 sg_name='it-windows-base' vpc_id=vpc-2ea5664b sg_description='Windows Common Base Security Group'
+## direction=ingress pft=udp,161,161 range=0.0.0.0/0
+## direction=ingress pft=tcp,1556,1556 range=10.193.0.0/22
+## direction=ingress pft=tcp,5986,5986 range=172.24.12.239/32
+## direction=ingress pft=tcp,3389,3389 range=148.129.0.0/16,192.168.0.0/16,172.16.0.0/12,10.0.0.0/8
+## direction=ingress pft=icmp,-1,-1 range=0.0.0.0/0
+## direction=egress pft=all range=0.0.0.0/0
+
+## this adds iperf3
+locals {
+ 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"]
+ n_mgmt = ["148.129.162.0/24", "148.129.95.0/24"]
+ n_backup = ["10.193.0.0/22"]
+ n_ansible = ["172.24.12.239/32"]
+ n_encase = ["148.129.121.72/32"]
+ n_riverbed = ["172.24.100.107/32"]
+ n_hpsa = ["172.24.100.141/32", "172.24.100.154/32", "172.24.100.165/32"]
+ n_hpom = ["172.24.105.24/32"]
+ source_groups = ["all", "external"]
+ name = var.name
+ ports = [
+ [-1, -1, "icmp", "ICMP", local.n_all, ["external"]],
+ [161, 161, "udp", "SNMP", local.n_all, ["external"]],
+ [5201, 5201, "tcp", "iperf3", local.n_all, ["external"]],
+ [5201, 5201, "udp", "iperf3", local.n_all, ["external"]],
+ [1556, 1556, "tcp", "Netbackup", local.n_backup, ["external"]],
+ [3389, 3389, "tcp", "RDP", local.n_census, ["external"]],
+ [4445, 4445, "tcp", "EnCase", local.n_encase, ["external"]],
+ [5986, 5986, "tcp", "WinRM-https", local.n_ansible, ["external"]],
+ [27401, 27401, "tcp", "TransactionAgent", local.n_riverbed, ["external"]],
+ [1002, 1002, "tcp", "HPSA", local.n_hpsa, ["external"]],
+ [383, 383, "tcp", "HPOM", local.n_hpom, ["external"]],
+ [383, 383, "udp", "HPOM", local.n_hpom, ["external"]],
+ ]
+
+ # these are ignored
+ ingress_networks = var.ingress_networks
+ egress_networks = 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/general/variables.tf b/general/variables.tf
new file mode 100644
index 0000000..0e4f382
--- /dev/null
+++ b/general/variables.tf
@@ -0,0 +1,83 @@
+#---
+# change between different modules as needed
+#---
+variable "name" {
+ description = "Security Group Name"
+ type = string
+ default = "it-windows-base"
+}
+
+variable "description" {
+ description = "Security Group Description"
+ type = string
+ default = "Windows Common Base Security Group"
+}
+
+variable "short_description" {
+ description = "Security Group Short Description"
+ type = string
+ default = "Windows"
+}
+
+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
+}
+
+data "aws_vpc" "selected" {
+ id = "${var.vpc_id}"
+}
+
+variable "vpc_full_name" {
+ description = "VPC Name"
+ type = string
+ default = ""
+}
+
+variable "ingress_networks" {
+ description = "List of ingress networks for external access (not all ports)"
+ 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"
+ }
+}
diff --git a/general/version.tf b/general/version.tf
new file mode 100644
index 0000000..1ee6619
--- /dev/null
+++ b/general/version.tf
@@ -0,0 +1,3 @@
+locals {
+ _module_version = "1.2.0"
+}
diff --git a/general/versions.tf b/general/versions.tf
new file mode 100644
index 0000000..ac97c6a
--- /dev/null
+++ b/general/versions.tf
@@ -0,0 +1,4 @@
+
+terraform {
+ required_version = ">= 0.12"
+}
diff --git a/sas/README.md b/sas/README.md
new file mode 100644
index 0000000..a53501b
--- /dev/null
+++ b/sas/README.md
@@ -0,0 +1,121 @@
+# About sas
+
+This describes how to use the aws-common-security-groups submodule for sas. For use as an application-specific
+security group, we recommend enabling `enable_self`, as this will apply so that all servers which hold this
+SG are able to communicate with each other. For a moduluar SAS global SG, like `m-sas`, this is not recommended
+and will actually be disabled (if the name is empty or `m-{something}`.
+
+The list of SAS ports is as follows:
+
+## General Purpose SG
+
+| Desscription | Protocol | Port Range | Direction | Source |
+|------------------|----------|------------|----------------|--------|
+| SAS OLAP Server | TCP | 5450-5460 | Inbound | All Client CIDRS: