diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4fa2920d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.terraform +terraform.tfstate +*.tfstate* +terraform.tfvars diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..51fca54c --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 00000000..e80b77dc --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +AWS EC2-VPC Security Group Terraform module +=========================================== + +Terraform module which creates [EC2 security group within VPC](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_SecurityGroups.html) on AWS. + +These types of resources are supported: + +* [EC2-VPC Security Group](https://www.terraform.io/docs/providers/aws/r/security_group.html) +* [EC2-VPC Security Group Rules](https://www.terraform.io/docs/providers/aws/r/security_group_rule.html) + +Root module creates security group with provided arguments. + +Modules in [modules directory](modules) has been configured with the list of ingress (inbound) and egress (outbound) ports open for common scenarios (eg, [ssh](modules/ssh), [http](modules/http), [mysql](modules/mysql)). + +Code in this module aims to implement **ALL** combinations of arguments (IPV4/IPV6 CIDR blocks, [VPC endpoint prefix lists](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-endpoints.html), source security groups, self), named rules. + +If there is something missing - [open an issue](https://github.com/terraform-aws-modules/terraform-aws-security-group/issues/new). + +Usage +----- + +There are two ways to create security groups using this module: + +##### 1. Security group with pre-defined rules + +```hcl +module "web_server_sg" { + source = "terraform-aws-modules/security-group/aws//modules/http" + + name = "web-server" + description = "Security group for web-server with HTTP ports open within VPC" + vpc_id = "vpc-12345678" + + ingress_cidr_blocks = ["10.10.0.0/16"] +} +``` + +##### 2. Security group with custom rules + +```hcl +module "vote_service_sg" { + source = "terraform-aws-modules/security-group/aws" + + name = "user-service" + description = "Security group for user-service with custom ports open within VPC, and PostgreSQL publicly open" + vpc_id = "vpc-12345678" + + ingress_cidr_blocks = ["10.10.0.0/16"] + ingress_rules = ["mysql"] + ingress_with_cidr_blocks = [ + { + from_port = 8080 + to_port = 8090 + protocol = 6 + description = "User-service ports" + cidr_blocks = "10.10.0.0/16" + }, + { + rule = "postgres" + cidr_blocks = "0.0.0.0/0" + }, + ] +} +``` + +Parameters +---------- + +Ingress and egress rules can be configured in a variety of ways as listed on [the registry](https://registry.terraform.io/modules/terraform-aws-modules/security-group/aws/?tab=inputs). + +Examples +-------- + +* [Complete Security Group example](https://github.com/terraform-aws-modules/terraform-aws-security-group/tree/master/examples/complete) +* [HTTP Security Group example](https://github.com/terraform-aws-modules/terraform-aws-security-group/tree/master/examples/http) + +Authors +------- + +Module managed by [Anton Babenko](https://github.com/antonbabenko). + +License +------- + +Apache 2 Licensed. See LICENSE for full details. \ No newline at end of file diff --git a/examples/complete/README.md b/examples/complete/README.md new file mode 100644 index 00000000..501001fd --- /dev/null +++ b/examples/complete/README.md @@ -0,0 +1,19 @@ +Complete Security Group example +=============================== + +Configuration in this directory creates set of Security Group and Security Group Rules resources in various combination. + +Data sources are used to discover existing VPC resources (VPC and default security group). + +Usage +===== + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. diff --git a/examples/complete/main.tf b/examples/complete/main.tf new file mode 100644 index 00000000..80c6e6f2 --- /dev/null +++ b/examples/complete/main.tf @@ -0,0 +1,157 @@ +provider "aws" { + region = "eu-west-1" +} + +############################################################# +# Data sources to get VPC and default security group details +############################################################# +data "aws_vpc" "default" { + default = true +} + +data "aws_security_group" "default" { + name = "default" + vpc_id = "${data.aws_vpc.default.id}" +} + +################################################ +# Security group with complete set of arguments +################################################ +module "complete_sg" { + source = "../../" + + name = "complete-sg" + description = "Security group with all available arguments set (this is just an example)" + vpc_id = "${data.aws_vpc.default.id}" + + tags = { + Cash = "king" + Department = "kingdom" + } + + # Default CIDR blocks, which will be used for all ingress rules in this module. Typically these are CIDR blocks of the VPC. + # If this is not specified then world-open CIDR blocks are used. + ingress_cidr_blocks = ["10.10.0.0/16"] + + ingress_ipv6_cidr_blocks = ["2001:db8::/64"] + + # Prefix list ids to use in all ingress rules in this module. + # ingress_prefix_list_ids = ["pl-123456"] + + # Open for all CIDRs defined in ingress_cidr_blocks + ingress_rules = ["http"] + # Open to CIDRs blocks (rule or from_port+to_port+protocol+description) + ingress_with_cidr_blocks = [ + { + rule = "postgres" + cidr_blocks = "0.0.0.0/0,2.2.2.2/32" + ipv6_cidr_blocks = "2001:db8::/60" + }, + { + rule = "postgres" + cidr_blocks = "30.30.30.30/32" + }, + { + from_port = 10 + to_port = 20 + protocol = 6 + description = "Service name" + cidr_blocks = "10.10.0.0/20" + }, + ] + # Open for security group id (rule or from_port+to_port+protocol+description) + ingress_with_source_security_group_id = [ + { + rule = "mysql" + source_security_group_id = "${data.aws_security_group.default.id}" + }, + { + from_port = 10 + to_port = 10 + protocol = 6 + description = "Service name" + source_security_group_id = "${data.aws_security_group.default.id}" + }, + ] + # Open for self (rule or from_port+to_port+protocol+description) + ingress_with_self = [ + { + rule = "all-all" + }, + { + from_port = 30 + to_port = 40 + protocol = 6 + description = "Service name" + self = true + }, + { + from_port = 41 + to_port = 51 + protocol = 6 + self = false + }, + ] + # Default CIDR blocks, which will be used for all egress rules in this module. Typically these are CIDR blocks of the VPC. + # If this is not specified then world-open CIDR blocks are used. + egress_cidr_blocks = ["10.10.0.0/16"] + egress_ipv6_cidr_blocks = ["2001:db8::/64"] + + # Prefix list ids to use in all egress rules in this module. + # egress_prefix_list_ids = ["pl-123456"] + + # Open for all CIDRs defined in egress_cidr_blocks + egress_rules = ["http"] + # Open to CIDRs blocks (rule or from_port+to_port+protocol+description) + egress_with_cidr_blocks = [ + { + rule = "postgres" + cidr_blocks = "0.0.0.0/0,2.2.2.2/32" + ipv6_cidr_blocks = "2001:db8::/60" + }, + { + rule = "postgres" + cidr_blocks = "30.30.30.30/32" + }, + { + from_port = 10 + to_port = 20 + protocol = 6 + description = "Service name" + cidr_blocks = "10.10.0.0/20" + }, + ] + # Open for security group id (rule or from_port+to_port+protocol+description) + egress_with_source_security_group_id = [ + { + rule = "mysql" + source_security_group_id = "${data.aws_security_group.default.id}" + }, + { + from_port = 10 + to_port = 10 + protocol = 6 + description = "Service name" + source_security_group_id = "${data.aws_security_group.default.id}" + }, + ] + # Open for self (rule or from_port+to_port+protocol+description) + egress_with_self = [ + { + rule = "all-all" + }, + { + from_port = 30 + to_port = 40 + protocol = 6 + description = "Service name" + self = true + }, + { + from_port = 41 + to_port = 51 + protocol = 6 + self = false + }, + ] +} diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf new file mode 100644 index 00000000..4c27b42c --- /dev/null +++ b/examples/complete/outputs.tf @@ -0,0 +1,34 @@ +output "this_security_group_id" { + description = "The ID of the security group" + value = "${module.complete_sg.this_security_group_id}" +} + +output "this_security_group_vpc_id" { + description = "The VPC ID" + value = "${module.complete_sg.this_security_group_vpc_id}" +} + +output "this_security_group_owner_id" { + description = "The owner ID" + value = "${module.complete_sg.this_security_group_owner_id}" +} + +output "this_security_group_name" { + description = "The name of the security group" + value = "${module.complete_sg.this_security_group_name}" +} + +output "this_security_group_description" { + description = "The description of the security group" + value = "${module.complete_sg.this_security_group_description}" +} + +output "this_security_group_ingress" { + description = "The ingress rules" + value = "${module.complete_sg.this_security_group_ingress}" +} + +output "this_security_group_egress" { + description = "The egress rules" + value = "${module.complete_sg.this_security_group_egress}" +} diff --git a/examples/http/README.md b/examples/http/README.md new file mode 100644 index 00000000..501001fd --- /dev/null +++ b/examples/http/README.md @@ -0,0 +1,19 @@ +Complete Security Group example +=============================== + +Configuration in this directory creates set of Security Group and Security Group Rules resources in various combination. + +Data sources are used to discover existing VPC resources (VPC and default security group). + +Usage +===== + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. diff --git a/examples/http/main.tf b/examples/http/main.tf new file mode 100644 index 00000000..ef18ef70 --- /dev/null +++ b/examples/http/main.tf @@ -0,0 +1,101 @@ +provider "aws" { + region = "eu-west-1" +} + +############################################################# +# Data sources to get VPC and default security group details +############################################################# +data "aws_vpc" "default" { + default = true +} + +data "aws_security_group" "default" { + name = "default" + vpc_id = "${data.aws_vpc.default.id}" +} + +########################### +# Security groups examples +########################### + +####### +# HTTP +####### +module "http_sg" { + source = "../../modules/http" + + name = "http-sg" + description = "Security group with HTTP ports open for everybody, egress ports are all world open" + vpc_id = "${data.aws_vpc.default.id}" +} + +##################### +# HTTP with MySQL #1 +##################### +module "http_mysql_1_sg" { + source = "../../modules/http" + + name = "http-mysql-1" + description = "Security group with HTTP and MySQL ports open for everybody globally" + vpc_id = "${data.aws_vpc.default.id}" + + # Add MySQL rules + ingress_rules = ["mysql"] +} + +##################### +# HTTP with MySQL #2 +##################### +module "http_mysql_2_sg" { + source = "../../modules/http" + + name = "http-mysql-2" + description = "Security group with HTTP and MySQL ports open within current VPC" + vpc_id = "${data.aws_vpc.default.id}" + + # Add mysql rules + ingress_rules = ["mysql"] + + # Allow ingress rules to be accessed only within current VPC + ingress_cidr_blocks = ["${data.aws_vpc.default.cidr_block}"] + ingress_ipv6_cidr_blocks = [] # Not all VPCs have IPv6 enabled, but if you have it enabled, then this will work - ["${data.aws_vpc.default.ipv6_cidr_block}"] +} + +########################### +# HTTP with egress minimal +########################### +module "http_with_egress_minimal_sg" { + source = "../../modules/http" + + name = "http-with-egress-minimal" + description = "Security group with HTTP ports open within current VPC, and allow egress access to HTTP ports to the whole world" + vpc_id = "${data.aws_vpc.default.id}" + + # Allow ingress rules to be accessed only within current VPC + ingress_cidr_blocks = ["${data.aws_vpc.default.cidr_block}"] + + # Allow all rules for all protocols + egress_rules = ["http"] +} + +########################### +# HTTP with egress limited +########################### +module "http_with_egress_sg" { + source = "../../modules/http" + + name = "http-with-egress" + description = "Security group with HTTP ports open within current VPC, and allow egress access just to small subnet" + vpc_id = "${data.aws_vpc.default.id}" + + # Add mysql rules + ingress_rules = ["mysql"] + + # Allow ingress rules to be accessed only within current VPC + ingress_cidr_blocks = ["${data.aws_vpc.default.cidr_block}"] + ingress_ipv6_cidr_blocks = [] # Not all VPCs have IPv6 enabled, but if you have it enabled, then this will work - ["${data.aws_vpc.default.ipv6_cidr_block}"] + + # Allow egress rules to access anything (empty list means everything) + egress_cidr_blocks = ["10.10.10.0/28"] + egress_ipv6_cidr_blocks = [] # Not all VPCs have IPv6 enabled, but if you have it enabled, then this will work - ["${data.aws_vpc.default.ipv6_cidr_block}"] +} diff --git a/examples/http/outputs.tf b/examples/http/outputs.tf new file mode 100644 index 00000000..95633b76 --- /dev/null +++ b/examples/http/outputs.tf @@ -0,0 +1,34 @@ +output "this_security_group_id" { + description = "The ID of the security group" + value = "${module.http_sg.this_security_group_id}" +} + +output "this_security_group_vpc_id" { + description = "The VPC ID" + value = "${module.http_sg.this_security_group_vpc_id}" +} + +output "this_security_group_owner_id" { + description = "The owner ID" + value = "${module.http_sg.this_security_group_owner_id}" +} + +output "this_security_group_name" { + description = "The name of the security group" + value = "${module.http_sg.this_security_group_name}" +} + +output "this_security_group_description" { + description = "The description of the security group" + value = "${module.http_sg.this_security_group_description}" +} + +output "this_security_group_ingress" { + description = "The ingress rules" + value = "${module.http_sg.this_security_group_ingress}" +} + +output "this_security_group_egress" { + description = "The egress rules" + value = "${module.http_sg.this_security_group_egress}" +} diff --git a/main.tf b/main.tf new file mode 100644 index 00000000..ffdc8d4d --- /dev/null +++ b/main.tf @@ -0,0 +1,159 @@ +################# +# Security group +################# +resource "aws_security_group" "this" { + name = "${var.name}" + description = "${var.description}" + vpc_id = "${var.vpc_id}" + + tags = "${merge(var.tags, map("Name", format("%s", var.name)))}" +} + +################################### +# Ingress - List of rules (simple) +################################### +# Security group rules with "cidr_blocks" and it uses list of rules names +resource "aws_security_group_rule" "ingress_rules" { + count = "${length(var.ingress_rules)}" + + security_group_id = "${aws_security_group.this.id}" + type = "ingress" + + cidr_blocks = ["${var.ingress_cidr_blocks}"] + ipv6_cidr_blocks = ["${var.ingress_ipv6_cidr_blocks}"] + prefix_list_ids = ["${var.ingress_prefix_list_ids}"] + + from_port = "${element(var.rules[var.ingress_rules[count.index]], 0)}" + to_port = "${element(var.rules[var.ingress_rules[count.index]], 1)}" + protocol = "${element(var.rules[var.ingress_rules[count.index]], 2)}" +} + +########################## +# Ingress - Maps of rules +########################## +# Security group rules with "source_security_group_id", but without "cidr_blocks" and "self" +resource "aws_security_group_rule" "ingress_with_source_security_group_id" { + count = "${length(var.ingress_with_source_security_group_id)}" + + security_group_id = "${aws_security_group.this.id}" + type = "ingress" + + source_security_group_id = "${lookup(var.ingress_with_source_security_group_id[count.index], "source_security_group_id")}" + ipv6_cidr_blocks = ["${var.ingress_ipv6_cidr_blocks}"] + prefix_list_ids = ["${var.ingress_prefix_list_ids}"] + + from_port = "${lookup(var.ingress_with_source_security_group_id[count.index], "from_port", element(var.rules[lookup(var.ingress_with_source_security_group_id[count.index], "rule", "_")], 0))}" + to_port = "${lookup(var.ingress_with_source_security_group_id[count.index], "to_port", element(var.rules[lookup(var.ingress_with_source_security_group_id[count.index], "rule", "_")], 1))}" + protocol = "${lookup(var.ingress_with_source_security_group_id[count.index], "protocol", element(var.rules[lookup(var.ingress_with_source_security_group_id[count.index], "rule", "_")], 2))}" +} + +# Security group rules with "cidr_blocks", but without "source_security_group_id" and "self" +resource "aws_security_group_rule" "ingress_with_cidr_blocks" { + count = "${length(var.ingress_with_cidr_blocks)}" + + security_group_id = "${aws_security_group.this.id}" + type = "ingress" + + cidr_blocks = ["${split(",", lookup(var.ingress_with_cidr_blocks[count.index], "cidr_blocks", join(",", var.ingress_cidr_blocks)))}"] + ipv6_cidr_blocks = ["${split(",", lookup(var.ingress_with_cidr_blocks[count.index], "ipv6_cidr_blocks", join(",", var.ingress_ipv6_cidr_blocks)))}"] + prefix_list_ids = ["${var.ingress_prefix_list_ids}"] + + from_port = "${lookup(var.ingress_with_cidr_blocks[count.index], "from_port", element(var.rules[lookup(var.ingress_with_cidr_blocks[count.index], "rule", "_")], 0))}" + to_port = "${lookup(var.ingress_with_cidr_blocks[count.index], "to_port", element(var.rules[lookup(var.ingress_with_cidr_blocks[count.index], "rule", "_")], 1))}" + protocol = "${lookup(var.ingress_with_cidr_blocks[count.index], "protocol", element(var.rules[lookup(var.ingress_with_cidr_blocks[count.index], "rule", "_")], 2))}" +} + +# Security group rules with "self", but without "cidr_blocks" and "source_security_group_id" +resource "aws_security_group_rule" "ingress_with_self" { + count = "${length(var.ingress_with_self)}" + + security_group_id = "${aws_security_group.this.id}" + type = "ingress" + + self = "${lookup(var.ingress_with_self[count.index], "self", true)}" + ipv6_cidr_blocks = ["${var.ingress_ipv6_cidr_blocks}"] + prefix_list_ids = ["${var.ingress_prefix_list_ids}"] + + from_port = "${lookup(var.ingress_with_self[count.index], "from_port", element(var.rules[lookup(var.ingress_with_self[count.index], "rule", "_")], 0))}" + to_port = "${lookup(var.ingress_with_self[count.index], "to_port", element(var.rules[lookup(var.ingress_with_self[count.index], "rule", "_")], 1))}" + protocol = "${lookup(var.ingress_with_self[count.index], "protocol", element(var.rules[lookup(var.ingress_with_self[count.index], "rule", "_")], 2))}" +} + +################# +# End of ingress +################# + +################################## +# Egress - List of rules (simple) +################################## +# Security group rules with "cidr_blocks" and it uses list of rules names +resource "aws_security_group_rule" "egress_rules" { + count = "${length(var.egress_rules)}" + + security_group_id = "${aws_security_group.this.id}" + type = "egress" + + cidr_blocks = ["${var.egress_cidr_blocks}"] + ipv6_cidr_blocks = ["${var.egress_ipv6_cidr_blocks}"] + prefix_list_ids = ["${var.egress_prefix_list_ids}"] + + from_port = "${element(var.rules[var.egress_rules[count.index]], 0)}" + to_port = "${element(var.rules[var.egress_rules[count.index]], 1)}" + protocol = "${element(var.rules[var.egress_rules[count.index]], 2)}" +} + +######################### +# Egress - Maps of rules +######################### +# Security group rules with "source_security_group_id", but without "cidr_blocks" and "self" +resource "aws_security_group_rule" "egress_with_source_security_group_id" { + count = "${length(var.egress_with_source_security_group_id)}" + + security_group_id = "${aws_security_group.this.id}" + type = "egress" + + source_security_group_id = "${lookup(var.egress_with_source_security_group_id[count.index], "source_security_group_id")}" + ipv6_cidr_blocks = ["${var.egress_ipv6_cidr_blocks}"] + prefix_list_ids = ["${var.egress_prefix_list_ids}"] + + from_port = "${lookup(var.egress_with_source_security_group_id[count.index], "from_port", element(var.rules[lookup(var.egress_with_source_security_group_id[count.index], "rule", "_")], 0))}" + to_port = "${lookup(var.egress_with_source_security_group_id[count.index], "to_port", element(var.rules[lookup(var.egress_with_source_security_group_id[count.index], "rule", "_")], 1))}" + protocol = "${lookup(var.egress_with_source_security_group_id[count.index], "protocol", element(var.rules[lookup(var.egress_with_source_security_group_id[count.index], "rule", "_")], 2))}" +} + +# Security group rules with "cidr_blocks", but without "source_security_group_id" and "self" +resource "aws_security_group_rule" "egress_with_cidr_blocks" { + count = "${length(var.egress_with_cidr_blocks)}" + + security_group_id = "${aws_security_group.this.id}" + type = "egress" + + cidr_blocks = ["${split(",", lookup(var.egress_with_cidr_blocks[count.index], "cidr_blocks", join(",", var.egress_cidr_blocks)))}"] + ipv6_cidr_blocks = ["${split(",", lookup(var.egress_with_cidr_blocks[count.index], "ipv6_cidr_blocks", join(",", var.egress_ipv6_cidr_blocks)))}"] + prefix_list_ids = ["${var.egress_prefix_list_ids}"] + + from_port = "${lookup(var.egress_with_cidr_blocks[count.index], "from_port", element(var.rules[lookup(var.egress_with_cidr_blocks[count.index], "rule", "_")], 0))}" + to_port = "${lookup(var.egress_with_cidr_blocks[count.index], "to_port", element(var.rules[lookup(var.egress_with_cidr_blocks[count.index], "rule", "_")], 1))}" + protocol = "${lookup(var.egress_with_cidr_blocks[count.index], "protocol", element(var.rules[lookup(var.egress_with_cidr_blocks[count.index], "rule", "_")], 2))}" +} + +# Security group rules with "self", but without "cidr_blocks" and "source_security_group_id" +resource "aws_security_group_rule" "egress_with_self" { + count = "${length(var.egress_with_self)}" + + security_group_id = "${aws_security_group.this.id}" + type = "egress" + + self = "${lookup(var.egress_with_self[count.index], "self", true)}" + ipv6_cidr_blocks = ["${var.egress_ipv6_cidr_blocks}"] + prefix_list_ids = ["${var.egress_prefix_list_ids}"] + + from_port = "${lookup(var.egress_with_self[count.index], "from_port", element(var.rules[lookup(var.egress_with_self[count.index], "rule", "_")], 0))}" + to_port = "${lookup(var.egress_with_self[count.index], "to_port", element(var.rules[lookup(var.egress_with_self[count.index], "rule", "_")], 1))}" + protocol = "${lookup(var.egress_with_self[count.index], "protocol", element(var.rules[lookup(var.egress_with_self[count.index], "rule", "_")], 2))}" +} + +################ +# End of egress +################ + diff --git a/modules/README.md b/modules/README.md new file mode 100644 index 00000000..5350ff14 --- /dev/null +++ b/modules/README.md @@ -0,0 +1,6 @@ +List of Security Groups implemented as Terraform modules +======================================================== + + +* [http](http) +* [ssh](ssh) diff --git a/modules/_templates/README.md b/modules/_templates/README.md new file mode 100644 index 00000000..42165482 --- /dev/null +++ b/modules/_templates/README.md @@ -0,0 +1 @@ +Code in this directory is used as a template for other modules. Change carefully, test thoughtfully! :) \ No newline at end of file diff --git a/modules/_templates/main.tf b/modules/_templates/main.tf new file mode 100644 index 00000000..395cbf7b --- /dev/null +++ b/modules/_templates/main.tf @@ -0,0 +1,52 @@ +module "sg" { + source = "../../" + + name = "${var.name}" + description = "${var.description}" + vpc_id = "${var.vpc_id}" + tags = "${var.tags}" + + ########## + # Ingress + ########## + # Rules by names - open for default CIDR + ingress_rules = ["${sort(distinct(concat(var.auto_ingress_rules, var.ingress_rules)))}"] + + # Open for self + ingress_with_self = ["${concat(var.auto_ingress_with_self, var.ingress_with_self)}"] + + # Open to cidr_blocks + ingress_with_cidr_blocks = ["${var.ingress_with_cidr_blocks}"] + + # Open for security group id + ingress_with_source_security_group_id = ["${var.ingress_with_source_security_group_id}"] + + # Default ingress CIDR blocks + ingress_cidr_blocks = ["${var.ingress_cidr_blocks}"] + ingress_ipv6_cidr_blocks = ["${var.ingress_ipv6_cidr_blocks}"] + + # Default prefix list ids + ingress_prefix_list_ids = ["${var.ingress_prefix_list_ids}"] + + ######### + # Egress + ######### + # Rules by names - open for default CIDR + egress_rules = ["${sort(distinct(concat(var.auto_egress_rules, var.egress_rules)))}"] + + # Open for self + egress_with_self = ["${concat(var.auto_egress_with_self, var.egress_with_self)}"] + + # Open to cidr_blocks + egress_with_cidr_blocks = ["${var.egress_with_cidr_blocks}"] + + # Open for security group id + egress_with_source_security_group_id = ["${var.egress_with_source_security_group_id}"] + + # Default egress CIDR blocks + egress_cidr_blocks = ["${var.egress_cidr_blocks}"] + egress_ipv6_cidr_blocks = ["${var.egress_ipv6_cidr_blocks}"] + + # Default prefix list ids + egress_prefix_list_ids = ["${var.egress_prefix_list_ids}"] +} diff --git a/modules/_templates/outputs.tf b/modules/_templates/outputs.tf new file mode 100644 index 00000000..fa040089 --- /dev/null +++ b/modules/_templates/outputs.tf @@ -0,0 +1,34 @@ +output "this_security_group_id" { + description = "The ID of the security group" + value = "${module.sg.this_security_group_id}" +} + +output "this_security_group_vpc_id" { + description = "The VPC ID" + value = "${module.sg.this_security_group_vpc_id}" +} + +output "this_security_group_owner_id" { + description = "The owner ID" + value = "${module.sg.this_security_group_owner_id}" +} + +output "this_security_group_name" { + description = "The name of the security group" + value = "${module.sg.this_security_group_name}" +} + +output "this_security_group_description" { + description = "The description of the security group" + value = "${module.sg.this_security_group_description}" +} + +output "this_security_group_ingress" { + description = "The ingress rules" + value = "${module.sg.this_security_group_ingress}" +} + +output "this_security_group_egress" { + description = "The egress rules" + value = "${module.sg.this_security_group_egress}" +} diff --git a/modules/_templates/variables.tf b/modules/_templates/variables.tf new file mode 100644 index 00000000..8fcc5ef9 --- /dev/null +++ b/modules/_templates/variables.tf @@ -0,0 +1,96 @@ +################# +# Security group +################# +variable "vpc_id" { + description = "ID of VPC to create security group into" +} + +variable "name" { + description = "Name of security group" +} + +variable "description" { + description = "Description of security group" + default = "Security Group managed by Terraform" +} + +variable "tags" { + description = "A mapping of tags to assign to security group" + default = {} +} + +########## +# Ingress +########## +variable "ingress_rules" { + description = "List of ingress rules to create by name" + default = [] +} + +variable "ingress_with_self" { + description = "List of ingress rules to create where 'self' is defined" + default = [] +} + +variable "ingress_with_cidr_blocks" { + description = "List of ingress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "ingress_with_source_security_group_id" { + description = "List of ingress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "ingress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all ingress rules" + default = ["0.0.0.0/0"] +} + +variable "ingress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all ingress rules" + default = ["::/0"] +} + +variable "ingress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all ingress rules" + default = [] +} + +######### +# Egress +######### +variable "egress_rules" { + description = "List of egress rules to create by name" + default = [] +} + +variable "egress_with_self" { + description = "List of egress rules to create where 'self' is defined" + default = [] +} + +variable "egress_with_cidr_blocks" { + description = "List of egress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "egress_with_source_security_group_id" { + description = "List of egress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "egress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all egress rules" + default = ["0.0.0.0/0"] +} + +variable "egress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all egress rules" + default = ["::/0"] +} + +variable "egress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all egress rules" + default = [] +} diff --git a/modules/http/auto_values.tf b/modules/http/auto_values.tf new file mode 100644 index 00000000..176a6640 --- /dev/null +++ b/modules/http/auto_values.tf @@ -0,0 +1,28 @@ +# This file was generated from values defined in rules.tf using update_groups.sh. +################################### +# DO NOT CHANGE THIS FILE MANUALLY +################################### + +variable "auto_ingress_rules" { + description = "List of ingress rules to add automatically" + type = "list" + default = ["http"] +} + +variable "auto_ingress_with_self" { + description = "List of ingress rules with self to add automatically" + type = "list" + default = [] +} + +variable "auto_egress_rules" { + description = "List of egress rules to add automatically" + type = "list" + default = ["all-all"] +} + +variable "auto_egress_with_self" { + description = "List of egress rules with self to add automatically" + type = "list" + default = [] +} diff --git a/modules/http/main.tf b/modules/http/main.tf new file mode 100644 index 00000000..395cbf7b --- /dev/null +++ b/modules/http/main.tf @@ -0,0 +1,52 @@ +module "sg" { + source = "../../" + + name = "${var.name}" + description = "${var.description}" + vpc_id = "${var.vpc_id}" + tags = "${var.tags}" + + ########## + # Ingress + ########## + # Rules by names - open for default CIDR + ingress_rules = ["${sort(distinct(concat(var.auto_ingress_rules, var.ingress_rules)))}"] + + # Open for self + ingress_with_self = ["${concat(var.auto_ingress_with_self, var.ingress_with_self)}"] + + # Open to cidr_blocks + ingress_with_cidr_blocks = ["${var.ingress_with_cidr_blocks}"] + + # Open for security group id + ingress_with_source_security_group_id = ["${var.ingress_with_source_security_group_id}"] + + # Default ingress CIDR blocks + ingress_cidr_blocks = ["${var.ingress_cidr_blocks}"] + ingress_ipv6_cidr_blocks = ["${var.ingress_ipv6_cidr_blocks}"] + + # Default prefix list ids + ingress_prefix_list_ids = ["${var.ingress_prefix_list_ids}"] + + ######### + # Egress + ######### + # Rules by names - open for default CIDR + egress_rules = ["${sort(distinct(concat(var.auto_egress_rules, var.egress_rules)))}"] + + # Open for self + egress_with_self = ["${concat(var.auto_egress_with_self, var.egress_with_self)}"] + + # Open to cidr_blocks + egress_with_cidr_blocks = ["${var.egress_with_cidr_blocks}"] + + # Open for security group id + egress_with_source_security_group_id = ["${var.egress_with_source_security_group_id}"] + + # Default egress CIDR blocks + egress_cidr_blocks = ["${var.egress_cidr_blocks}"] + egress_ipv6_cidr_blocks = ["${var.egress_ipv6_cidr_blocks}"] + + # Default prefix list ids + egress_prefix_list_ids = ["${var.egress_prefix_list_ids}"] +} diff --git a/modules/http/outputs.tf b/modules/http/outputs.tf new file mode 100644 index 00000000..fa040089 --- /dev/null +++ b/modules/http/outputs.tf @@ -0,0 +1,34 @@ +output "this_security_group_id" { + description = "The ID of the security group" + value = "${module.sg.this_security_group_id}" +} + +output "this_security_group_vpc_id" { + description = "The VPC ID" + value = "${module.sg.this_security_group_vpc_id}" +} + +output "this_security_group_owner_id" { + description = "The owner ID" + value = "${module.sg.this_security_group_owner_id}" +} + +output "this_security_group_name" { + description = "The name of the security group" + value = "${module.sg.this_security_group_name}" +} + +output "this_security_group_description" { + description = "The description of the security group" + value = "${module.sg.this_security_group_description}" +} + +output "this_security_group_ingress" { + description = "The ingress rules" + value = "${module.sg.this_security_group_ingress}" +} + +output "this_security_group_egress" { + description = "The egress rules" + value = "${module.sg.this_security_group_egress}" +} diff --git a/modules/http/variables.tf b/modules/http/variables.tf new file mode 100644 index 00000000..8fcc5ef9 --- /dev/null +++ b/modules/http/variables.tf @@ -0,0 +1,96 @@ +################# +# Security group +################# +variable "vpc_id" { + description = "ID of VPC to create security group into" +} + +variable "name" { + description = "Name of security group" +} + +variable "description" { + description = "Description of security group" + default = "Security Group managed by Terraform" +} + +variable "tags" { + description = "A mapping of tags to assign to security group" + default = {} +} + +########## +# Ingress +########## +variable "ingress_rules" { + description = "List of ingress rules to create by name" + default = [] +} + +variable "ingress_with_self" { + description = "List of ingress rules to create where 'self' is defined" + default = [] +} + +variable "ingress_with_cidr_blocks" { + description = "List of ingress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "ingress_with_source_security_group_id" { + description = "List of ingress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "ingress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all ingress rules" + default = ["0.0.0.0/0"] +} + +variable "ingress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all ingress rules" + default = ["::/0"] +} + +variable "ingress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all ingress rules" + default = [] +} + +######### +# Egress +######### +variable "egress_rules" { + description = "List of egress rules to create by name" + default = [] +} + +variable "egress_with_self" { + description = "List of egress rules to create where 'self' is defined" + default = [] +} + +variable "egress_with_cidr_blocks" { + description = "List of egress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "egress_with_source_security_group_id" { + description = "List of egress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "egress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all egress rules" + default = ["0.0.0.0/0"] +} + +variable "egress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all egress rules" + default = ["::/0"] +} + +variable "egress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all egress rules" + default = [] +} diff --git a/modules/ssh/auto_values.tf b/modules/ssh/auto_values.tf new file mode 100644 index 00000000..1029221f --- /dev/null +++ b/modules/ssh/auto_values.tf @@ -0,0 +1,28 @@ +# This file was generated from values defined in rules.tf using update_groups.sh. +################################### +# DO NOT CHANGE THIS FILE MANUALLY +################################### + +variable "auto_ingress_rules" { + description = "List of ingress rules to add automatically" + type = "list" + default = ["http", "ssh"] +} + +variable "auto_ingress_with_self" { + description = "List of ingress rules with self to add automatically" + type = "list" + default = [] +} + +variable "auto_egress_rules" { + description = "List of egress rules to add automatically" + type = "list" + default = ["all-all"] +} + +variable "auto_egress_with_self" { + description = "List of egress rules with self to add automatically" + type = "list" + default = [] +} diff --git a/modules/ssh/main.tf b/modules/ssh/main.tf new file mode 100644 index 00000000..395cbf7b --- /dev/null +++ b/modules/ssh/main.tf @@ -0,0 +1,52 @@ +module "sg" { + source = "../../" + + name = "${var.name}" + description = "${var.description}" + vpc_id = "${var.vpc_id}" + tags = "${var.tags}" + + ########## + # Ingress + ########## + # Rules by names - open for default CIDR + ingress_rules = ["${sort(distinct(concat(var.auto_ingress_rules, var.ingress_rules)))}"] + + # Open for self + ingress_with_self = ["${concat(var.auto_ingress_with_self, var.ingress_with_self)}"] + + # Open to cidr_blocks + ingress_with_cidr_blocks = ["${var.ingress_with_cidr_blocks}"] + + # Open for security group id + ingress_with_source_security_group_id = ["${var.ingress_with_source_security_group_id}"] + + # Default ingress CIDR blocks + ingress_cidr_blocks = ["${var.ingress_cidr_blocks}"] + ingress_ipv6_cidr_blocks = ["${var.ingress_ipv6_cidr_blocks}"] + + # Default prefix list ids + ingress_prefix_list_ids = ["${var.ingress_prefix_list_ids}"] + + ######### + # Egress + ######### + # Rules by names - open for default CIDR + egress_rules = ["${sort(distinct(concat(var.auto_egress_rules, var.egress_rules)))}"] + + # Open for self + egress_with_self = ["${concat(var.auto_egress_with_self, var.egress_with_self)}"] + + # Open to cidr_blocks + egress_with_cidr_blocks = ["${var.egress_with_cidr_blocks}"] + + # Open for security group id + egress_with_source_security_group_id = ["${var.egress_with_source_security_group_id}"] + + # Default egress CIDR blocks + egress_cidr_blocks = ["${var.egress_cidr_blocks}"] + egress_ipv6_cidr_blocks = ["${var.egress_ipv6_cidr_blocks}"] + + # Default prefix list ids + egress_prefix_list_ids = ["${var.egress_prefix_list_ids}"] +} diff --git a/modules/ssh/outputs.tf b/modules/ssh/outputs.tf new file mode 100644 index 00000000..fa040089 --- /dev/null +++ b/modules/ssh/outputs.tf @@ -0,0 +1,34 @@ +output "this_security_group_id" { + description = "The ID of the security group" + value = "${module.sg.this_security_group_id}" +} + +output "this_security_group_vpc_id" { + description = "The VPC ID" + value = "${module.sg.this_security_group_vpc_id}" +} + +output "this_security_group_owner_id" { + description = "The owner ID" + value = "${module.sg.this_security_group_owner_id}" +} + +output "this_security_group_name" { + description = "The name of the security group" + value = "${module.sg.this_security_group_name}" +} + +output "this_security_group_description" { + description = "The description of the security group" + value = "${module.sg.this_security_group_description}" +} + +output "this_security_group_ingress" { + description = "The ingress rules" + value = "${module.sg.this_security_group_ingress}" +} + +output "this_security_group_egress" { + description = "The egress rules" + value = "${module.sg.this_security_group_egress}" +} diff --git a/modules/ssh/variables.tf b/modules/ssh/variables.tf new file mode 100644 index 00000000..8fcc5ef9 --- /dev/null +++ b/modules/ssh/variables.tf @@ -0,0 +1,96 @@ +################# +# Security group +################# +variable "vpc_id" { + description = "ID of VPC to create security group into" +} + +variable "name" { + description = "Name of security group" +} + +variable "description" { + description = "Description of security group" + default = "Security Group managed by Terraform" +} + +variable "tags" { + description = "A mapping of tags to assign to security group" + default = {} +} + +########## +# Ingress +########## +variable "ingress_rules" { + description = "List of ingress rules to create by name" + default = [] +} + +variable "ingress_with_self" { + description = "List of ingress rules to create where 'self' is defined" + default = [] +} + +variable "ingress_with_cidr_blocks" { + description = "List of ingress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "ingress_with_source_security_group_id" { + description = "List of ingress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "ingress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all ingress rules" + default = ["0.0.0.0/0"] +} + +variable "ingress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all ingress rules" + default = ["::/0"] +} + +variable "ingress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all ingress rules" + default = [] +} + +######### +# Egress +######### +variable "egress_rules" { + description = "List of egress rules to create by name" + default = [] +} + +variable "egress_with_self" { + description = "List of egress rules to create where 'self' is defined" + default = [] +} + +variable "egress_with_cidr_blocks" { + description = "List of egress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "egress_with_source_security_group_id" { + description = "List of egress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "egress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all egress rules" + default = ["0.0.0.0/0"] +} + +variable "egress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all egress rules" + default = ["::/0"] +} + +variable "egress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all egress rules" + default = [] +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 00000000..a3357999 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,34 @@ +output "this_security_group_id" { + description = "The ID of the security group" + value = "${aws_security_group.this.id}" +} + +output "this_security_group_vpc_id" { + description = "The VPC ID" + value = "${aws_security_group.this.vpc_id}" +} + +output "this_security_group_owner_id" { + description = "The owner ID" + value = "${aws_security_group.this.owner_id}" +} + +output "this_security_group_name" { + description = "The name of the security group" + value = "${aws_security_group.this.name}" +} + +output "this_security_group_description" { + description = "The description of the security group" + value = "${aws_security_group.this.description}" +} + +output "this_security_group_ingress" { + description = "The ingress rules" + value = "${aws_security_group.this.ingress}" +} + +output "this_security_group_egress" { + description = "The egress rules" + value = "${aws_security_group.this.egress}" +} diff --git a/rules.tf b/rules.tf new file mode 100644 index 00000000..378bdfde --- /dev/null +++ b/rules.tf @@ -0,0 +1,221 @@ +variable "rules" { + description = "Map of known security group rules (define as 'name' = ['from port', 'to port', 'protocol', 'description'])" + type = "map" + + # Protocols: All = -1, IPV4-ICMP = 1, TCP = 6, UDP = 16, IPV6-ICMP = 58 + default = { + http = [8080, 8088, 6, "HTTP"] + mysql = [81, 81, 6, "MySQL"] + postgres = [82, 82, 6, "PostgreSQL"] + + carbon-line-up-tcp = [2003, 2003, 6, "Carbon"] + carbon-line-up-udp = [2003, 2003, 16, "Carbon"] + "2013-tcp" = [2013, 2013, 6, "Carbon"] + "2013-udp" = [2013, 2013, 16, "Carbon"] + + all-all = [0, 65535, -1, "All protocols"] + all-icmp = [0, 65535, 1, "All IPV4 ICMP"] + all-ipv6-icmp = [0, 65535, 58, "All IPV6 ICMP"] + all-tcp = [0, 65535, 6, "All TCP"] + all-udp = [0, 65535, 16, "All"] + + # This is a fallback rule to pass to lookup() as default. It does not open anything, because it should never be used. + _ = ["", "", ""] + } +} + +variable "auto_groups" { + description = "Map of groups of security group rules to use to generate modules (see update_groups.sh)" + type = "map" + + # Valid keys - ingress_rules, egress_rules, ingress_with_self, egress_with_self + default = { + ssh = { + ingress_rules = ["http", "ssh"] + egress_rules = ["all-all"] + } + + http = { + ingress_rules = ["http"] + egress_rules = ["all-all"] + } + } +} + +/* +List of protocols (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml): +Decimal,Keyword,Protocol,IPv6 Extension Header,Reference +0,HOPOPT,IPv6 Hop-by-Hop Option,Y,[RFC-ietf-6man-rfc2460bis-13] +1,ICMP,Internet Control Message,,[RFC792] +2,IGMP,Internet Group Management,,[RFC1112] +3,GGP,Gateway-to-Gateway,,[RFC823] +4,IPv4,IPv4 encapsulation,,[RFC2003] +5,ST,Stream,,[RFC1190][RFC1819] +6,TCP,Transmission Control,,[RFC793] +7,CBT,CBT,,[Tony_Ballardie] +8,EGP,Exterior Gateway Protocol,,[RFC888][David_Mills] +9,IGP,"any private interior gateway +(used by Cisco for their IGRP)",,[Internet_Assigned_Numbers_Authority] +10,BBN-RCC-MON,BBN RCC Monitoring,,[Steve_Chipman] +11,NVP-II,Network Voice Protocol,,[RFC741][Steve_Casner] +12,PUP,PUP,,"[Boggs, D., J. Shoch, E. Taft, and R. Metcalfe, ""PUP: An +Internetwork Architecture"", XEROX Palo Alto Research Center, +CSL-79-10, July 1979 also in IEEE Transactions on +Communication, Volume COM-28, Number 4, April 1980.][[XEROX]]" +13,ARGUS (deprecated),ARGUS,,[Robert_W_Scheifler] +14,EMCON,EMCON,,[] +15,XNET,Cross Net Debugger,,"[Haverty, J., ""XNET Formats for Internet Protocol Version 4"", +IEN 158, October 1980.][Jack_Haverty]" +16,CHAOS,Chaos,,[J_Noel_Chiappa] +17,UDP,User Datagram,,[RFC768][Jon_Postel] +18,MUX,Multiplexing,,"[Cohen, D. and J. Postel, ""Multiplexing Protocol"", IEN 90, +USC/Information Sciences Institute, May 1979.][Jon_Postel]" +19,DCN-MEAS,DCN Measurement Subsystems,,[David_Mills] +20,HMP,Host Monitoring,,[RFC869][Bob_Hinden] +21,PRM,Packet Radio Measurement,,[Zaw_Sing_Su] +22,XNS-IDP,XEROX NS IDP,,"[""The Ethernet, A Local Area Network: Data Link Layer and +Physical Layer Specification"", AA-K759B-TK, Digital +Equipment Corporation, Maynard, MA. Also as: ""The +Ethernet - A Local Area Network"", Version 1.0, Digital +Equipment Corporation, Intel Corporation, Xerox +Corporation, September 1980. And: ""The Ethernet, A Local +Area Network: Data Link Layer and Physical Layer +Specifications"", Digital, Intel and Xerox, November 1982. +And: XEROX, ""The Ethernet, A Local Area Network: Data Link +Layer and Physical Layer Specification"", X3T51/80-50, +Xerox Corporation, Stamford, CT., October 1980.][[XEROX]]" +23,TRUNK-1,Trunk-1,,[Barry_Boehm] +24,TRUNK-2,Trunk-2,,[Barry_Boehm] +25,LEAF-1,Leaf-1,,[Barry_Boehm] +26,LEAF-2,Leaf-2,,[Barry_Boehm] +27,RDP,Reliable Data Protocol,,[RFC908][Bob_Hinden] +28,IRTP,Internet Reliable Transaction,,[RFC938][Trudy_Miller] +29,ISO-TP4,ISO Transport Protocol Class 4,,[RFC905][] +30,NETBLT,Bulk Data Transfer Protocol,,[RFC969][David_Clark] +31,MFE-NSP,MFE Network Services Protocol,,"[Shuttleworth, B., ""A Documentary of MFENet, a National +Computer Network"", UCRL-52317, Lawrence Livermore Labs, +Livermore, California, June 1977.][Barry_Howard]" +32,MERIT-INP,MERIT Internodal Protocol,,[Hans_Werner_Braun] +33,DCCP,Datagram Congestion Control Protocol,,[RFC4340] +34,3PC,Third Party Connect Protocol,,[Stuart_A_Friedberg] +35,IDPR,Inter-Domain Policy Routing Protocol,,[Martha_Steenstrup] +36,XTP,XTP,,[Greg_Chesson] +37,DDP,Datagram Delivery Protocol,,[Wesley_Craig] +38,IDPR-CMTP,IDPR Control Message Transport Proto,,[Martha_Steenstrup] +39,TP++,TP++ Transport Protocol,,[Dirk_Fromhein] +40,IL,IL Transport Protocol,,[Dave_Presotto] +41,IPv6,IPv6 encapsulation,,[RFC2473] +42,SDRP,Source Demand Routing Protocol,,[Deborah_Estrin] +43,IPv6-Route,Routing Header for IPv6,Y,[Steve_Deering] +44,IPv6-Frag,Fragment Header for IPv6,Y,[Steve_Deering] +45,IDRP,Inter-Domain Routing Protocol,,[Sue_Hares] +46,RSVP,Reservation Protocol,,[RFC2205][RFC3209][Bob_Braden] +47,GRE,Generic Routing Encapsulation,,[RFC2784][Tony_Li] +48,DSR,Dynamic Source Routing Protocol,,[RFC4728] +49,BNA,BNA,,[Gary Salamon] +50,ESP,Encap Security Payload,Y,[RFC4303] +51,AH,Authentication Header,Y,[RFC4302] +52,I-NLSP,Integrated Net Layer Security TUBA,,[K_Robert_Glenn] +53,SWIPE (deprecated),IP with Encryption,,[John_Ioannidis] +54,NARP,NBMA Address Resolution Protocol,,[RFC1735] +55,MOBILE,IP Mobility,,[Charlie_Perkins] +56,TLSP,"Transport Layer Security Protocol +using Kryptonet key management",,[Christer_Oberg] +57,SKIP,SKIP,,[Tom_Markson] +58,IPv6-ICMP,ICMP for IPv6,,[RFC-ietf-6man-rfc2460bis-13] +59,IPv6-NoNxt,No Next Header for IPv6,,[RFC-ietf-6man-rfc2460bis-13] +60,IPv6-Opts,Destination Options for IPv6,Y,[RFC-ietf-6man-rfc2460bis-13] +61,,any host internal protocol,,[Internet_Assigned_Numbers_Authority] +62,CFTP,CFTP,,"[Forsdick, H., ""CFTP"", Network Message, Bolt Beranek and +Newman, January 1982.][Harry_Forsdick]" +63,,any local network,,[Internet_Assigned_Numbers_Authority] +64,SAT-EXPAK,SATNET and Backroom EXPAK,,[Steven_Blumenthal] +65,KRYPTOLAN,Kryptolan,,[Paul Liu] +66,RVD,MIT Remote Virtual Disk Protocol,,[Michael_Greenwald] +67,IPPC,Internet Pluribus Packet Core,,[Steven_Blumenthal] +68,,any distributed file system,,[Internet_Assigned_Numbers_Authority] +69,SAT-MON,SATNET Monitoring,,[Steven_Blumenthal] +70,VISA,VISA Protocol,,[Gene_Tsudik] +71,IPCV,Internet Packet Core Utility,,[Steven_Blumenthal] +72,CPNX,Computer Protocol Network Executive,,[David Mittnacht] +73,CPHB,Computer Protocol Heart Beat,,[David Mittnacht] +74,WSN,Wang Span Network,,[Victor Dafoulas] +75,PVP,Packet Video Protocol,,[Steve_Casner] +76,BR-SAT-MON,Backroom SATNET Monitoring,,[Steven_Blumenthal] +77,SUN-ND,SUN ND PROTOCOL-Temporary,,[William_Melohn] +78,WB-MON,WIDEBAND Monitoring,,[Steven_Blumenthal] +79,WB-EXPAK,WIDEBAND EXPAK,,[Steven_Blumenthal] +80,ISO-IP,ISO Internet Protocol,,[Marshall_T_Rose] +81,VMTP,VMTP,,[Dave_Cheriton] +82,SECURE-VMTP,SECURE-VMTP,,[Dave_Cheriton] +83,VINES,VINES,,[Brian Horn] +84,TTP,Transaction Transport Protocol,,[Jim_Stevens] +84,IPTM,Internet Protocol Traffic Manager,,[Jim_Stevens] +85,NSFNET-IGP,NSFNET-IGP,,[Hans_Werner_Braun] +86,DGP,Dissimilar Gateway Protocol,,"[M/A-COM Government Systems, ""Dissimilar Gateway Protocol +Specification, Draft Version"", Contract no. CS901145, +November 16, 1987.][Mike_Little]" +87,TCF,TCF,,[Guillermo_A_Loyola] +88,EIGRP,EIGRP,,[RFC7868] +89,OSPFIGP,OSPFIGP,,[RFC1583][RFC2328][RFC5340][John_Moy] +90,Sprite-RPC,Sprite RPC Protocol,,"[Welch, B., ""The Sprite Remote Procedure Call System"", +Technical Report, UCB/Computer Science Dept., 86/302, +University of California at Berkeley, June 1986.][Bruce Willins]" +91,LARP,Locus Address Resolution Protocol,,[Brian Horn] +92,MTP,Multicast Transport Protocol,,[Susie_Armstrong] +93,AX.25,AX.25 Frames,,[Brian_Kantor] +94,IPIP,IP-within-IP Encapsulation Protocol,,[John_Ioannidis] +95,MICP (deprecated),Mobile Internetworking Control Pro.,,[John_Ioannidis] +96,SCC-SP,Semaphore Communications Sec. Pro.,,[Howard_Hart] +97,ETHERIP,Ethernet-within-IP Encapsulation,,[RFC3378] +98,ENCAP,Encapsulation Header,,[RFC1241][Robert_Woodburn] +99,,any private encryption scheme,,[Internet_Assigned_Numbers_Authority] +100,GMTP,GMTP,,[[RXB5]] +101,IFMP,Ipsilon Flow Management Protocol,,"[Bob_Hinden][November 1995, 1997.]" +102,PNNI,PNNI over IP,,[Ross_Callon] +103,PIM,Protocol Independent Multicast,,[RFC7761][Dino_Farinacci] +104,ARIS,ARIS,,[Nancy_Feldman] +105,SCPS,SCPS,,[Robert_Durst] +106,QNX,QNX,,[Michael_Hunter] +107,A/N,Active Networks,,[Bob_Braden] +108,IPComp,IP Payload Compression Protocol,,[RFC2393] +109,SNP,Sitara Networks Protocol,,[Manickam_R_Sridhar] +110,Compaq-Peer,Compaq Peer Protocol,,[Victor_Volpe] +111,IPX-in-IP,IPX in IP,,[CJ_Lee] +112,VRRP,Virtual Router Redundancy Protocol,,[RFC5798] +113,PGM,PGM Reliable Transport Protocol,,[Tony_Speakman] +114,,any 0-hop protocol,,[Internet_Assigned_Numbers_Authority] +115,L2TP,Layer Two Tunneling Protocol,,[RFC3931][Bernard_Aboba] +116,DDX,D-II Data Exchange (DDX),,[John_Worley] +117,IATP,Interactive Agent Transfer Protocol,,[John_Murphy] +118,STP,Schedule Transfer Protocol,,[Jean_Michel_Pittet] +119,SRP,SpectraLink Radio Protocol,,[Mark_Hamilton] +120,UTI,UTI,,[Peter_Lothberg] +121,SMP,Simple Message Protocol,,[Leif_Ekblad] +122,SM (deprecated),Simple Multicast Protocol,,[Jon_Crowcroft][draft-perlman-simple-multicast] +123,PTP,Performance Transparency Protocol,,[Michael_Welzl] +124,ISIS over IPv4,,,[Tony_Przygienda] +125,FIRE,,,[Criag_Partridge] +126,CRTP,Combat Radio Transport Protocol,,[Robert_Sautter] +127,CRUDP,Combat Radio User Datagram,,[Robert_Sautter] +128,SSCOPMCE,,,[Kurt_Waber] +129,IPLT,,,[[Hollbach]] +130,SPS,Secure Packet Shield,,[Bill_McIntosh] +131,PIPE,Private IP Encapsulation within IP,,[Bernhard_Petri] +132,SCTP,Stream Control Transmission Protocol,,[Randall_R_Stewart] +133,FC,Fibre Channel,,[Murali_Rajagopal][RFC6172] +134,RSVP-E2E-IGNORE,,,[RFC3175] +135,Mobility Header,,Y,[RFC6275] +136,UDPLite,,,[RFC3828] +137,MPLS-in-IP,,,[RFC4023] +138,manet,MANET Protocols,,[RFC5498] +139,HIP,Host Identity Protocol,Y,[RFC7401] +140,Shim6,Shim6 Protocol,Y,[RFC5533] +141,WESP,Wrapped Encapsulating Security Payload,,[RFC5840] +142,ROHC,Robust Header Compression,,[RFC5858] +143-252,,Unassigned,,[Internet_Assigned_Numbers_Authority] +253,,Use for experimentation and testing,Y,[RFC3692] +254,,Use for experimentation and testing,Y,[RFC3692] +255,Reserved,,,[Internet_Assigned_Numbers_Authority] +*/ + diff --git a/update_groups.sh b/update_groups.sh new file mode 100755 index 00000000..a3babae4 --- /dev/null +++ b/update_groups.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash + +# @todo: generate content of each public module (eg, "http") from the json list. +# outputs.tf and variables.tf for all group modules are the same for all + +set -e + +# Change location to the directory where this script it located +cd "$(dirname "${BASH_SOURCE[0]}")" + + +# Assert that a given binary is installed +function assert_is_installed { + local readonly name="$1" + +} + +check_dependencies() { + if [[ ! $(command -v json2hcl) ]]; then + echo "ERROR: The binary 'json2hcl' is required by this script but is not installed or in the system's PATH." + echo "Check documentation: https://github.com/kvz/json2hcl" + exit 1 + fi + + if [[ ! $(command -v jq) ]]; then + echo "ERROR: The binary 'jq' is required by this script but is not installed or in the system's PATH." + echo "Check documentation: https://github.com/stedolan/jq" + exit 1 + fi +} + +auto_groups_data() { + json2hcl -reverse < rules.tf | jq -r '..|.auto_groups?|values|.[0]|.default|.[0]' +} + +auto_groups_keys() { + local readonly data=$1 + + echo $data | jq -r ".|keys|@sh" | tr -d "'" +} + +get_auto_value() { + local readonly data=$1 + local readonly group=$2 + local readonly var=$3 + + echo $data | jq -rc '.[$group][0][$var]' --arg group "$group" --arg var "$var" +} + +set_list_if_null() { + if [[ "null" == "$1" ]]; then + echo "[]" + else + echo "$1" + fi +} + +main() { + check_dependencies + + readonly local auto_groups_data="$(auto_groups_data)" + + if [[ -z "$(auto_groups_data)" ]]; then + echo "There are no modules to update. Check values of auto_groups inside rules.tf" + exit 0 + fi + + readonly local auto_groups_keys=($(auto_groups_keys "$auto_groups_data")) + + local ingress_rules="" + local ingress_with_self="" + local egress_rules="" + local egress_with_self="" + local list_of_modules="" + + for group in "${auto_groups_keys[@]}"; do + + echo "Making group: $group" + + mkdir -p "modules/$group" + cp modules/_templates/{main,outputs,variables}.tf "modules/$group" + + # Get group values + ingress_rules=$(get_auto_value "$auto_groups_data" "$group" "ingress_rules") + ingress_with_self=$(get_auto_value "$auto_groups_data" "$group" "ingress_with_self") + egress_rules=$(get_auto_value "$auto_groups_data" "$group" "egress_rules") + egress_with_self=$(get_auto_value "$auto_groups_data" "$group" "egress_with_self") + + # Set to empty lists, if no value was specified + ingress_rules=$(set_list_if_null "$ingress_rules") + ingress_with_self=$(set_list_if_null "$ingress_with_self") + egress_rules=$(set_list_if_null "$egress_rules") + egress_with_self=$(set_list_if_null "$egress_with_self") + + # ingress_with_self and egress_with_self are stored as simple lists (like this - ["all-all","all-tcp"]), + # so we make map (like this - [{"rule"="all-all"},{"rule"="all-tcp"}]) + ingress_with_self=$(echo "$ingress_with_self" | jq -rc "[{rule:.[]}]" | tr ':' '=') + egress_with_self=$(echo "$egress_with_self" | jq -rc "[{rule:.[]}]" | tr ':' '=') + + cat < "modules/$group/auto_values.tf" +# This file was generated from values defined in rules.tf using update_groups.sh. +################################### +# DO NOT CHANGE THIS FILE MANUALLY +################################### + +variable "auto_ingress_rules" { + description = "List of ingress rules to add automatically" + type = "list" + default = $ingress_rules +} + +variable "auto_ingress_with_self" { + description = "List of ingress rules with self to add automatically" + type = "list" + default = $ingress_with_self +} + +variable "auto_egress_rules" { + description = "List of egress rules to add automatically" + type = "list" + default = $egress_rules +} + +variable "auto_egress_with_self" { + description = "List of egress rules with self to add automatically" + type = "list" + default = $egress_with_self +} +EOF + + local list_of_modules=$(echo "$list_of_modules"; echo "* [$group]($group)") + +# terraform fmt -diff=true "modules/$group" + done + + + echo "Updating list of security group modules" + + cat < modules/README.md +List of Security Groups implemented as Terraform modules +======================================================== + +$list_of_modules +EOF + + echo "Done!" +} + +main \ No newline at end of file diff --git a/variables.tf b/variables.tf new file mode 100644 index 00000000..7cf7a264 --- /dev/null +++ b/variables.tf @@ -0,0 +1,96 @@ +################# +# Security group +################# +variable "vpc_id" { + description = "ID of the VPC where to create security group" +} + +variable "name" { + description = "Name of security group" +} + +variable "description" { + description = "Description of security group" + default = "Security Group managed by Terraform" +} + +variable "tags" { + description = "A mapping of tags to assign to security group" + default = {} +} + +########## +# Ingress +########## +variable "ingress_rules" { + description = "List of ingress rules to create by name" + default = [] +} + +variable "ingress_with_self" { + description = "List of ingress rules to create where 'self' is defined" + default = [] +} + +variable "ingress_with_cidr_blocks" { + description = "List of ingress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "ingress_with_source_security_group_id" { + description = "List of ingress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "ingress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all ingress rules" + default = ["0.0.0.0/0"] +} + +variable "ingress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all ingress rules" + default = ["::/0"] +} + +variable "ingress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all ingress rules" + default = [] +} + +######### +# Egress +######### +variable "egress_rules" { + description = "List of egress rules to create by name" + default = [] +} + +variable "egress_with_self" { + description = "List of egress rules to create where 'self' is defined" + default = [] +} + +variable "egress_with_cidr_blocks" { + description = "List of egress rules to create where 'cidr_blocks' is used" + default = [] +} + +variable "egress_with_source_security_group_id" { + description = "List of egress rules to create where 'source_security_group_id' is used" + default = [] +} + +variable "egress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all egress rules" + default = ["0.0.0.0/0"] +} + +variable "egress_ipv6_cidr_blocks" { + description = "List of IPv6 CIDR ranges to use on all egress rules" + default = ["::/0"] +} + +variable "egress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all egress rules" + default = [] +}