From 4e88667312a4fa57a01b3f09b4103f853c4e08db Mon Sep 17 00:00:00 2001 From: yoctoalex Date: Fri, 3 Nov 2023 21:56:45 +0100 Subject: [PATCH] Initial commit --- .gitignore | 35 +++ LICENSE | 201 +++++++++++++ README.md | 37 +++ examples/vpc-for-ingress-egress-gw/README.md | 16 ++ examples/vpc-for-ingress-egress-gw/main.tf | 16 ++ examples/vpc-for-ingress-egress-gw/outputs.tf | 64 +++++ .../terraform.tfvars.example | 2 + .../vpc-for-ingress-egress-gw/variables.tf | 12 + .../vpc-for-ingress-egress-gw/versions.tf | 10 + main.tf | 207 ++++++++++++++ modules/aws-sg/main.tf | 264 ++++++++++++++++++ modules/aws-sg/outputs.tf | 19 ++ modules/aws-sg/variables.tf | 35 +++ modules/aws-sg/versions.tf | 10 + outputs.tf | 64 +++++ variables.tf | 108 +++++++ versions.tf | 10 + 17 files changed, 1110 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 examples/vpc-for-ingress-egress-gw/README.md create mode 100644 examples/vpc-for-ingress-egress-gw/main.tf create mode 100644 examples/vpc-for-ingress-egress-gw/outputs.tf create mode 100644 examples/vpc-for-ingress-egress-gw/terraform.tfvars.example create mode 100644 examples/vpc-for-ingress-egress-gw/variables.tf create mode 100644 examples/vpc-for-ingress-egress-gw/versions.tf create mode 100644 main.tf create mode 100644 modules/aws-sg/main.tf create mode 100644 modules/aws-sg/outputs.tf create mode 100644 modules/aws-sg/variables.tf create mode 100644 modules/aws-sg/versions.tf create mode 100644 outputs.tf create mode 100644 variables.tf create mode 100644 versions.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..791ad1c --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +.DS_Store + +# Local .terraform directories +**/.terraform/* + +# Terraform lockfile +.terraform.lock.hcl + +# .tfstate files +*.tfstate +*.tfstate.* +*.tfplan + +# Crash log files +crash.log + +# Exclude all .tfvars files, which are likely to contain sentitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# Ignore XC Cloud Certificates +*.p12 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 0000000..e25c4ab --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# AWS Networking module for F5 Distributed Cloud (XC) AWS VPC Site + +This Terraform module provisions a VPC network in AWS that is required for XC Cloud AWS VPC Site. It creates a VPC, subnets, route tables, and security groups with whitelisted IP ranges. + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](https://github.com/hashicorp/terraform) | >= 1.0 | +| [aws](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) | >= 5.0 | + +## Usage + + +To use this module and create a VPC configured for XC Cloud AWS VPC Site on AWS Cloud, include the following code in your Terraform configuration: + +```hcl +module "aws_vpc" { + source = "f5devcentral/aws-vpc-site-networking/xc" + version = "0.0.5" + + name = "aws-tf-demo-creds" + az_names = ["us-west-2a", "us-west-2b", "us-west-2c"] + vpc_cidr = "192.168.0.0/16" + outside_subnets = ["192.168.11.0/24", "192.168.12.0/24", "192.168.13.0/24"] + inside_subnets = ["192.168.21.0/24", "192.168.22.0/24", "192.168.23.0/24"] + workload_subnets = ["192.168.31.0/24", "192.168.32.0/24", "192.168.33.0/24"] +} +``` + +## Contributing + +Contributions to this module are welcome! Please see the contribution guidelines for more information. + +## License + +This module is licensed under the Apache 2.0 License. \ No newline at end of file diff --git a/examples/vpc-for-ingress-egress-gw/README.md b/examples/vpc-for-ingress-egress-gw/README.md new file mode 100644 index 0000000..ddfd5cb --- /dev/null +++ b/examples/vpc-for-ingress-egress-gw/README.md @@ -0,0 +1,16 @@ +# AWS VPC for F5 XC Cloud Ingress/Egress GW AWS VPC Site + +The following example will create an AWS VPC with 3 AZs, 3 subnets per AZ, and a security group. The security groups will be configured with whitelisted IP ranges for the XC Cloud Ingress/Egress GW AWS VPC Site. + +```hcl +module "aws_vpc" { + source = "../.." + + name = "aws-tf-demo-creds" + az_names = ["us-west-2a", "us-west-2b", "us-west-2c"] + vpc_cidr = "192.168.0.0/16" + outside_subnets = ["192.168.11.0/24", "192.168.12.0/24", "192.168.13.0/24"] + inside_subnets = ["192.168.21.0/24", "192.168.22.0/24", "192.168.23.0/24"] + workload_subnets = ["192.168.31.0/24", "192.168.32.0/24", "192.168.33.0/24"] +} +``` \ No newline at end of file diff --git a/examples/vpc-for-ingress-egress-gw/main.tf b/examples/vpc-for-ingress-egress-gw/main.tf new file mode 100644 index 0000000..12a017a --- /dev/null +++ b/examples/vpc-for-ingress-egress-gw/main.tf @@ -0,0 +1,16 @@ +provider "aws" { + access_key = var.aws_access_key + secret_key = var.aws_secret_key + region = "us-west-2" +} + +module "aws_vpc" { + source = "../.." + + name = "aws-tf-demo-creds" + az_names = ["us-west-2a", "us-west-2b", "us-west-2c"] + vpc_cidr = "192.168.0.0/16" + outside_subnets = ["192.168.11.0/24", "192.168.12.0/24", "192.168.13.0/24"] + inside_subnets = ["192.168.21.0/24", "192.168.22.0/24", "192.168.23.0/24"] + workload_subnets = ["192.168.31.0/24", "192.168.32.0/24", "192.168.33.0/24"] +} diff --git a/examples/vpc-for-ingress-egress-gw/outputs.tf b/examples/vpc-for-ingress-egress-gw/outputs.tf new file mode 100644 index 0000000..e974a7f --- /dev/null +++ b/examples/vpc-for-ingress-egress-gw/outputs.tf @@ -0,0 +1,64 @@ +output "vpc_id" { + value = module.aws_vpc.vpc_id + description = "The ID of the VPC." +} + +output "vpc_name" { + value = module.aws_vpc.vpc_name + description = "The name of the VPC." +} + +output "vpc_cird" { + value = module.aws_vpc.vpc_cidr + description = "The CIDR block of the VPC." +} + +output "outside_subnet_ids" { + value = module.aws_vpc.outside_subnet_ids + description = "The IDs of the outside subnets." +} + +output "inside_subnet_ids" { + value = module.aws_vpc.inside_subnet_ids + description = "The IDs of the inside subnets." +} + +output "workload_subnet_ids" { + value = module.aws_vpc.workload_subnet_ids + description = "The IDs of the workload subnets." +} + +output "local_subnet_ids" { + value = module.aws_vpc.local_subnet_ids + description = "The IDs of the local subnets." +} + +output "outside_route_table_id" { + value = module.aws_vpc.outside_route_table_id + description = "The ID of the outside route table." +} + +output "internet_gateway_id" { + value = module.aws_vpc.internet_gateway_id + description = "The ID of the internet gateway." +} + +output "outside_security_group_id" { + value = module.aws_vpc.outside_security_group_id + description = "The ID of the outside security group." +} + +output "inside_security_group_id" { + value = module.aws_vpc.inside_security_group_id + description = "The ID of the inside security group." +} + +output "default_security_group_id" { + value = module.aws_vpc.default_security_group_id + description = "The ID of the default security group." +} + +output "az_names" { + value = module.aws_vpc.az_names + description = "Availability zones." +} \ No newline at end of file diff --git a/examples/vpc-for-ingress-egress-gw/terraform.tfvars.example b/examples/vpc-for-ingress-egress-gw/terraform.tfvars.example new file mode 100644 index 0000000..6860aa2 --- /dev/null +++ b/examples/vpc-for-ingress-egress-gw/terraform.tfvars.example @@ -0,0 +1,2 @@ +aws_access_key = "your_aws_access_key" +aws_secret_key = "your_aws_secret_key" \ No newline at end of file diff --git a/examples/vpc-for-ingress-egress-gw/variables.tf b/examples/vpc-for-ingress-egress-gw/variables.tf new file mode 100644 index 0000000..830a355 --- /dev/null +++ b/examples/vpc-for-ingress-egress-gw/variables.tf @@ -0,0 +1,12 @@ +variable "aws_access_key" { + type = string + default = null + description = "AWS access key" +} + +variable "aws_secret_key" { + type = string + sensitive = true + description = "AWS secret key" + default = null +} \ No newline at end of file diff --git a/examples/vpc-for-ingress-egress-gw/versions.tf b/examples/vpc-for-ingress-egress-gw/versions.tf new file mode 100644 index 0000000..5ba03d3 --- /dev/null +++ b/examples/vpc-for-ingress-egress-gw/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=5.0" + } + } +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..4e10e94 --- /dev/null +++ b/main.tf @@ -0,0 +1,207 @@ +resource "random_string" "random" { + length = 8 + special = false + numeric = false + lower = true +} + +data "aws_availability_zones" "available" { + state = "available" +} + +locals { + create_vpc = (null == var.existing_vpc_id) + create_outside_subnet = local.outside_subnets_len > 0 + create_local_subnet = local.local_subnets_len > 0 + create_inside_subnet = local.inside_subnets_len > 0 + create_workload_subnet = local.workload_subnets_len > 0 + outside_subnets_len = length(var.outside_subnets) + local_subnets_len = length(var.local_subnets) + inside_subnets_len = length(var.inside_subnets) + workload_subnets_len = length(var.workload_subnets) + vpc_name = var.name != null ? var.name : format("%s-vpc", random_string.random.result) + vpc_id = var.existing_vpc_id != null ? var.existing_vpc_id : aws_vpc.this[0].id + az_names = length(var.az_names) > 0 ? var.az_names : slice(data.aws_availability_zones.available.names, 0, max(local.outside_subnets_len, local.local_subnets_len, local.inside_subnets_len, local.workload_subnets_len)) +} + +resource "aws_vpc" "this" { + count = local.create_vpc ? 1 : 0 + + cidr_block = var.vpc_cidr + instance_tenancy = var.vpc_instance_tenancy + enable_dns_hostnames = var.vpc_enable_dns_hostnames + enable_dns_support = var.vpc_enable_dns_support + enable_network_address_usage_metrics = var.vpc_enable_network_address_usage_metrics + + tags = merge( + { + Name = local.vpc_name + }, + var.tags, + ) +} + +resource "aws_subnet" "outside" { + count = local.create_outside_subnet ? local.outside_subnets_len : 0 + + availability_zone = element(local.az_names, count.index) + cidr_block = element(var.outside_subnets, count.index) + vpc_id = local.vpc_id + + tags = merge( + { + Name = format("%s-outside-%s", local.vpc_name, element(local.az_names, count.index)) + }, + var.tags, + ) + + depends_on = [ + aws_vpc.this, + ] +} + +resource "aws_subnet" "local" { + count = local.create_local_subnet ? local.local_subnets_len : 0 + + availability_zone = element(local.az_names, count.index) + cidr_block = element(var.local_subnets, count.index) + vpc_id = local.vpc_id + + tags = merge( + { + Name = format("%s-local-%s", local.vpc_name, element(local.az_names, count.index)) + }, + var.tags, + ) + + depends_on = [ + aws_vpc.this, + ] +} + +resource "aws_subnet" "inside" { + count = local.create_inside_subnet ? local.inside_subnets_len : 0 + + availability_zone = element(local.az_names, count.index) + cidr_block = element(var.inside_subnets, count.index) + vpc_id = local.vpc_id + + tags = merge( + { + Name = format("%s-inside-%s", local.vpc_name, element(local.az_names, count.index)) + }, + var.tags, + ) + + depends_on = [ + aws_vpc.this, + ] +} + +resource "aws_subnet" "workload" { + count = local.create_workload_subnet ? local.workload_subnets_len : 0 + + availability_zone = element(local.az_names, count.index) + cidr_block = element(var.workload_subnets, count.index) + vpc_id = local.vpc_id + + tags = merge( + { + Name = format("%s-workload-%s", local.vpc_name, element(local.az_names, count.index)) + }, + var.tags, + ) + + depends_on = [ + aws_vpc.this, + ] +} + +resource "aws_route_table" "outside" { + count = var.create_outside_route_table && (null != var.outside_subnets || null != var.local_subnets) ? 1 : 0 + + vpc_id = local.vpc_id + + tags = merge( + { + Name = format("%s-outside-rt", local.vpc_name) + }, + var.tags, + ) + + depends_on = [ + aws_vpc.this, + ] +} + +resource "aws_route_table_association" "outside" { + count = var.create_outside_route_table ? local.outside_subnets_len : 0 + + subnet_id = element(aws_subnet.outside[*].id, count.index) + route_table_id = aws_route_table.outside[0].id +} + +resource "aws_route_table_association" "local" { + count = var.create_outside_route_table ? local.local_subnets_len : 0 + + subnet_id = element(aws_subnet.local[*].id, count.index) + route_table_id = aws_route_table.outside[0].id +} + +resource "aws_route" "internet_gateway" { + count = var.create_internet_gateway ? 1 : 0 + + route_table_id = aws_route_table.outside[0].id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.this[0].id +} + +resource "aws_internet_gateway" "this" { + count = var.create_internet_gateway ? 1 : 0 + + vpc_id = local.vpc_id + + tags = merge( + { + Name = format("%s-igw", local.vpc_name) + }, + var.tags, + ) + + depends_on = [ + aws_vpc.this, + ] +} + +resource "aws_default_security_group" "default" { + count = local.create_vpc ? 1 : 0 + + vpc_id = local.vpc_id + + tags = merge( + { + Name = format("%s-default-sg", local.vpc_name) + }, + var.tags, + ) + + depends_on = [ + aws_vpc.this, + ] +} + +module "aws_vpc_sg" { + source = "./modules/aws-sg" + + vpc_id = local.vpc_id + prefix = local.vpc_name + + create_inside_security_group = var.create_inside_security_group + create_outside_security_group = var.create_outside_security_group + create_udp_security_group_rules = var.create_udp_security_group_rules + + + depends_on = [ + aws_vpc.this, + ] +} \ No newline at end of file diff --git a/modules/aws-sg/main.tf b/modules/aws-sg/main.tf new file mode 100644 index 0000000..e5beb5b --- /dev/null +++ b/modules/aws-sg/main.tf @@ -0,0 +1,264 @@ +data "aws_vpc" "this" { + id = var.vpc_id +} + +locals { + prefix = var.prefix != "" ? format("%s-", var.prefix) : "" +} + +locals { + americas_tcp_80_443_range = [ + "5.182.215.0/25", + "84.54.61.0/25", + "23.158.32.0/25", + "84.54.62.0/25", + "185.94.142.0/25", + "185.94.143.0/25", + "159.60.190.0/24", + "159.60.168.0/24", + ] + europe_tcp_80_443_range = [ + "5.182.213.0/25", + "5.182.212.0/25", + "5.182.213.128/25", + "5.182.214.0/25", + "84.54.60.0/25", + "185.56.154.0/25", + "159.60.160.0/24", + "159.60.162.0/24", + "159.60.188.0/24", + ] + asia_tcp_80_443_range = [ + "103.135.56.0/25", + "103.135.57.0/25", + "103.135.56.128/25", + "103.135.59.0/25", + "103.135.58.128/25", + "103.135.58.0/25", + "159.60.189.0/24", + "159.60.166.0/24", + "159.60.164.0/24", + ] + americas_udp_4500_range = [ + "5.182.215.0/25", + "84.54.61.0/25", + "23.158.32.0/25", + "84.54.62.0/25", + "185.94.142.0/25", + "185.94.143.0/25", + "159.60.190.0/24", + ] + europe_udp_4500_range = [ + "5.182.213.0/25", + "5.182.212.0/25", + "5.182.213.128/25", + "5.182.214.0/25", + "84.54.60.0/25", + "185.56.154.0/25", + "159.60.160.0/24", + "159.60.162.0/24", + "159.60.188.0/24", + ] + asia_udp_4500_range = [ + "103.135.56.0/25", + "103.135.57.0/25", + "103.135.56.128/25", + "103.135.59.0/25", + "103.135.58.128/25", + "103.135.58.0/25", + "159.60.189.0/24", + "159.60.166.0/24", + "159.60.164.0/24", + ] +} + +resource "aws_ec2_managed_prefix_list" "tcp_80" { + count = var.create_outside_security_group ? 1 : 0 + + name = "XC Cloud TCP 80 IPv4 Subnet Ranges" + address_family = "IPv4" + max_entries = 30 + + dynamic "entry" { + for_each =local.americas_tcp_80_443_range + content { + description = "Americas IPv4 Subnet Ranges" + cidr = entry.value + } + } + + dynamic "entry" { + for_each = local.europe_tcp_80_443_range + content { + description = "Europe IPv4 Subnet Ranges" + cidr = entry.value + } + } + + dynamic "entry" { + for_each = local.asia_tcp_80_443_range + content { + description = "Asia IPv4 Subnet Ranges" + cidr = entry.value + } + } + + tags = var.tags +} + +resource "aws_ec2_managed_prefix_list" "tcp_443" { + count = var.create_outside_security_group ? 1 : 0 + + name = "XC Cloud TCP 443 IPv4 Subnet Ranges" + address_family = "IPv4" + max_entries = 30 + + dynamic "entry" { + for_each = local.americas_tcp_80_443_range + content { + description = "Americas IPv4 Subnet Ranges" + cidr = entry.value + } + } + + dynamic "entry" { + for_each = local.europe_tcp_80_443_range + content { + description = "Europe IPv4 Subnet Ranges" + cidr = entry.value + } + } + + dynamic "entry" { + for_each = local.asia_tcp_80_443_range + content { + description = "Asia IPv4 Subnet Ranges" + cidr = entry.value + } + } + + tags = var.tags +} + +resource "aws_ec2_managed_prefix_list" "udp_4500" { + count = var.create_outside_security_group && var.create_udp_security_group_rules ? 1 : 0 + + name = "XC Cloud UDP 4500 IPv4 Subnet Ranges" + address_family = "IPv4" + max_entries = 30 + + dynamic "entry" { + for_each = local.americas_udp_4500_range + content { + description = "Americas IPv4 Subnet Ranges" + cidr = entry.value + } + } + + dynamic "entry" { + for_each = local.europe_udp_4500_range + content { + description = "Europe IPv4 Subnet Ranges" + cidr = entry.value + } + } + + dynamic "entry" { + for_each = local.asia_udp_4500_range + content { + description = "Asia IPv4 Subnet Ranges" + cidr = entry.value + } + } + + tags = var.tags +} + +resource "aws_security_group" "outside" { + count = var.create_outside_security_group ? 1 : 0 + + description = "Outside security group" + vpc_id = var.vpc_id + name = format("%soutside-sg", local.prefix) + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] + } + + ingress { + description = "Local traffic" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [ data.aws_vpc.this.cidr_block ] + } + + ingress { + description = "TCP 80 IPv4 Subnet Ranges" + from_port = 80 + to_port = 80 + protocol = "tcp" + prefix_list_ids = [ aws_ec2_managed_prefix_list.tcp_80[0].id ] + } + + ingress { + description = "TCP 443 IPv4 Subnet Ranges" + from_port = 443 + to_port = 443 + protocol = "tcp" + prefix_list_ids = [ aws_ec2_managed_prefix_list.tcp_443[0].id ] + } + + dynamic "ingress" { + for_each = var.create_udp_security_group_rules ? [0] : [] + + content { + description = "UDP 4500 IPv4 Subnet Ranges" + from_port = 4500 + to_port = 4500 + protocol = "udp" + prefix_list_ids = [ aws_ec2_managed_prefix_list.udp_4500[0].id ] + } + } + + tags = merge( + { + Name = format("%soutside-sg", local.prefix) + }, + var.tags, + ) +} + +resource "aws_security_group" "inside" { + count = var.create_inside_security_group ? 1 : 0 + + description = "Inside security group for" + vpc_id = var.vpc_id + name = format("%sinside-sg", local.prefix) + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] + } + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [ data.aws_vpc.this.cidr_block ] + } + + tags = merge( + { + Name = format("%sinside-sg", local.prefix) + }, + var.tags, + ) +} \ No newline at end of file diff --git a/modules/aws-sg/outputs.tf b/modules/aws-sg/outputs.tf new file mode 100644 index 0000000..6e113e3 --- /dev/null +++ b/modules/aws-sg/outputs.tf @@ -0,0 +1,19 @@ +output "vpc_id" { + value = var.vpc_id + description = "The ID of the VPC." +} + +output "vpc_cidr" { + value = data.aws_vpc.this.cidr_block + description = "The CIDR block of the VPC." +} + +output "outside_security_group_id" { + value = var.create_inside_security_group ? aws_security_group.outside[0].id : null + description = "The ID of the outside security group." +} + +output "inside_security_group_id" { + value = var.create_inside_security_group ? aws_security_group.inside[0].id : null + description = "The ID of the inside security group." +} diff --git a/modules/aws-sg/variables.tf b/modules/aws-sg/variables.tf new file mode 100644 index 0000000..03e755c --- /dev/null +++ b/modules/aws-sg/variables.tf @@ -0,0 +1,35 @@ +variable "vpc_id" { + description = "The ID of an existing VPC." + type = string + nullable = false +} + +variable "prefix" { + description = "The prefix to use for all resource names." + type = string + default = "" +} + +variable "create_outside_security_group" { + description = "Whether to create an outside security group." + type = bool + default = true +} + +variable "create_inside_security_group" { + description = "Whether to create an inside security group." + type = bool + default = true +} + +variable "create_udp_security_group_rules" { + description = "Whether to create UDP security group rules." + type = bool + default = true +} + +variable "tags" { + description = "A map of tags to add to all resources." + type = map(string) + default = {} +} \ No newline at end of file diff --git a/modules/aws-sg/versions.tf b/modules/aws-sg/versions.tf new file mode 100644 index 0000000..a0ec97b --- /dev/null +++ b/modules/aws-sg/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=5.0" + } + } +} \ No newline at end of file diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..20b0e28 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,64 @@ +output "vpc_id" { + value = local.vpc_id + description = "The ID of the VPC." +} + +output "vpc_name" { + value = local.vpc_name + description = "The name of the VPC." +} + +output "vpc_cidr" { + value = var.vpc_cidr + description = "The CIDR block of the VPC." +} + +output "outside_subnet_ids" { + value = aws_subnet.outside.*.id + description = "The IDs of the outside subnets." +} + +output "inside_subnet_ids" { + value = aws_subnet.inside.*.id + description = "The IDs of the inside subnets." +} + +output "workload_subnet_ids" { + value = aws_subnet.workload.*.id + description = "The IDs of the workload subnets." +} + +output "local_subnet_ids" { + value = aws_subnet.local.*.id + description = "The IDs of the local subnets." +} + +output "outside_route_table_id" { + value = var.create_outside_route_table ? aws_route_table.outside[0].id : null + description = "The ID of the outside route table." +} + +output "internet_gateway_id" { + value = var.create_internet_gateway ? aws_internet_gateway.this[0].id : null + description = "The ID of the internet gateway." +} + +output "outside_security_group_id" { + value = module.aws_vpc_sg.outside_security_group_id + description = "The ID of the outside security group." +} + +output "inside_security_group_id" { + value = module.aws_vpc_sg.inside_security_group_id + description = "The ID of the inside security group." +} + +output "default_security_group_id" { + value = try(aws_default_security_group.default[0].id, null) + description = "The ID of the default security group." +} + +output "az_names" { + value = local.az_names + description = "Availability zones." +} \ No newline at end of file diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..314dc8c --- /dev/null +++ b/variables.tf @@ -0,0 +1,108 @@ + +variable "name" { + description = "The name of the VPC." + type = string + default = null +} + +variable "existing_vpc_id" { + description = "The ID of an existing VPC to use instead of creating a new one." + type = string + default = null +} + +variable "create_outside_route_table" { + description = "Whether to create an outside route table for the outside subnets." + type = bool + default = true +} + +variable "create_internet_gateway" { + description = "Whether to create an internet gateway." + type = bool + default = true +} + +variable "create_outside_security_group" { + description = "Whether to create an outside security group." + type = bool + default = true +} + +variable "create_inside_security_group" { + description = "Whether to create an inside security group." + type = bool + default = true +} + +variable "create_udp_security_group_rules" { + description = "Whether to create UDP security group rules." + type = bool + default = true +} + +variable "tags" { + description = "A map of tags to add to all resources." + type = map(string) + default = {} +} + +variable "az_names" { + description = "Availability Zone Names for Subnets." + type = list(string) + default = [] +} + +variable "local_subnets" { + description = "Local Subnet CIDR Blocks." + type = list(string) + default = [] +} + +variable "inside_subnets" { + description = "Inside Subnet CIDR Blocks." + type = list(string) + default = [] +} + +variable "outside_subnets" { + description = "Outside Subnet CIDR Blocks." + type = list(string) + default = [] +} + +variable "workload_subnets" { + description = "Workload Subnet CIDR Blocks." + type = list(string) + default = [] +} + +variable "vpc_cidr" { + description = "The Primary IPv4 block cannot be modified. All subnets prefixes in this VPC must be part of this CIDR block." + type = string + default = null +} + +variable "vpc_instance_tenancy" { + description = "A tenancy option for instances launched into the VPC." + type = string + default = "default" +} + +variable "vpc_enable_dns_hostnames" { + description = "Should be true to enable DNS hostnames in the VPC." + type = bool + default = true +} + +variable "vpc_enable_dns_support" { + description = "Should be true to enable DNS support in the VPC." + type = bool + default = true +} + +variable "vpc_enable_network_address_usage_metrics" { + description = "Determines whether network address usage metrics are enabled for the VPC." + type = bool + default = false +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..a0ec97b --- /dev/null +++ b/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=5.0" + } + } +} \ No newline at end of file