diff --git a/modules/terraform-aws-proxy/.terraform-docs.yaml b/modules/terraform-aws-proxy/.terraform-docs.yaml
new file mode 100644
index 0000000..0936036
--- /dev/null
+++ b/modules/terraform-aws-proxy/.terraform-docs.yaml
@@ -0,0 +1,21 @@
+formatter: markdown
+header-from: doc_fragments/header.md
+settings:
+ anchor: true
+ color: true
+ default: true
+ escape: true
+ html: true
+ indent: 2
+ required: true
+ sensitive: true
+ type: true
+
+
+sort:
+ enabled: true
+ by: required
+
+output:
+ file: README.md
+ mode: replace
\ No newline at end of file
diff --git a/modules/terraform-aws-proxy/README.md b/modules/terraform-aws-proxy/README.md
new file mode 100644
index 0000000..33e17aa
--- /dev/null
+++ b/modules/terraform-aws-proxy/README.md
@@ -0,0 +1,88 @@
+
+# Terraform Module for AWS Transit Gateway
+
+This module contains resource files and example variable definition files to create and configure and EC2 Auto-Scaling Group to create a highly available Squid Proxy service. A Network Load Balancer is also created to forward traffic to the proxy instances. This module can be used to assist in deploying Cloudera Data Platform (CDP) Public Cloud in a fully private networking configuration where the CDP Environment uses a proxy configuration via the Network Load Balancer.
+
+## Usage
+
+The [examples](./examples) directory has example of using this module:
+
+* `ex01-minimal_inputs` demonstrates how this module can be used to create Squid proxy instances and NLB in a networking VPC. The [terraform-aws-vpc](../../../terraform-aws-vpc/README.md) module is also used as part of this example.
+
+The sample `terraform.tfvars.sample` describes the required inputs for the example.
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | > 1.3.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | ~> 4.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_autoscaling_attachment.proxy_asg_tg_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_attachment) | resource |
+| [aws_autoscaling_group.proxy_asg](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_group) | resource |
+| [aws_launch_template.proxy_lt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template) | resource |
+| [aws_lb.proxy_lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource |
+| [aws_lb_listener.proxy_lb_listener](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource |
+| [aws_lb_target_group.proxy_tg](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group) | resource |
+| [aws_route.vpc_tgw_route](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
+| [aws_security_group.proxy_sg](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
+| [aws_security_group_rule.proxy_egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
+| [aws_security_group_rule.proxy_ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
+| [aws_security_group_rule.proxy_lb_ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
+| [aws_ami.proxy_default_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
+| [aws_network_interface.proxy_lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/network_interface) | data source |
+| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
+| [aws_route_table.proxy_rt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route_table) | data source |
+| [aws_vpc.proxy_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [lb\_subnet\_ids](#input\_lb\_subnet\_ids) | The IDs of the subnet for the Network Load Balancer | `list(any)` | n/a | yes |
+| [network\_load\_balancer\_name](#input\_network\_load\_balancer\_name) | Name of Network Load Balancer for the Proxy. | `string` | n/a | yes |
+| [proxy\_autoscaling\_group\_name](#input\_proxy\_autoscaling\_group\_name) | Name of Autoscaling Group for the Proxy VMs. | `string` | n/a | yes |
+| [proxy\_aws\_keypair\_name](#input\_proxy\_aws\_keypair\_name) | SSH Keypair name for the proxy VM | `string` | n/a | yes |
+| [proxy\_launch\_template\_name](#input\_proxy\_launch\_template\_name) | Name of Launch Template for the Proxy VMs. | `string` | n/a | yes |
+| [proxy\_subnet\_ids](#input\_proxy\_subnet\_ids) | The IDs of the subnet where the proxy VMs will run | `list(any)` | n/a | yes |
+| [target\_group\_proxy\_name](#input\_target\_group\_proxy\_name) | Name of Target Group for the Proxy. | `string` | n/a | yes |
+| [vpc\_id](#input\_vpc\_id) | VPC ID for where the proxy VM will run | `string` | n/a | yes |
+| [autoscaling\_group\_scaling](#input\_autoscaling\_group\_scaling) | Minimum, maximum and desired size of EC2 instance in the Auto Scaling Group. |
object({
min_size = number
max_size = number
desired_capacity = number
})
| {
"desired_capacity": 3,
"max_size": 6,
"min_size": 3
}
| no |
+| [aws\_region](#input\_aws\_region) | AWS region, used in Proxy Whitelist configuration files. If not provided will perform lookup of aws\_region data source. | `string` | `null` | no |
+| [cdp\_region](#input\_cdp\_region) | CDP Control Plane region, used in Proxy Whitelist configuration files. | `string` | `"us-west-1"` | no |
+| [create\_proxy\_sg](#input\_create\_proxy\_sg) | Flag to specify if the Security Group for the proxy should be created. | `bool` | `true` | no |
+| [egress\_rules](#input\_egress\_rules) | List of egress rules to create. Used only if create\_proxy\_sg is true | list(object({
cidrs = list(string)
from_port = number
to_port = optional(number)
protocol = string
}))
| [
{
"cidrs": [
"0.0.0.0/0"
],
"from_port": 0,
"protocol": "all",
"to_port": 0
}
]
| no |
+| [enable\_proxy\_public\_ip](#input\_enable\_proxy\_public\_ip) | Assign a public IP address to the Proxy VM | `bool` | `true` | no |
+| [env\_tags](#input\_env\_tags) | Tags applied to provisioned resources | `map(any)` | `{}` | no |
+| [ingress\_rules](#input\_ingress\_rules) | List of ingress rules to create. Used only if create\_proxy\_sg is true | list(object({
cidrs = list(string)
from_port = number
to_port = optional(number)
protocol = string
}))
| `[]` | no |
+| [proxy\_aws\_ami](#input\_proxy\_aws\_ami) | The AWS AMI to use for the proxy VM | `string` | `null` | no |
+| [proxy\_aws\_instance\_type](#input\_proxy\_aws\_instance\_type) | The EC2 instance type to use for the proxy VM | `string` | `"t3.medium"` | no |
+| [proxy\_launch\_template\_user\_data\_file](#input\_proxy\_launch\_template\_user\_data\_file) | Location of the AWS Launch Template user data script. If not specified the files/user-data-proxy.sh.tpl file accompanying the module is used. | `string` | `null` | no |
+| [proxy\_port](#input\_proxy\_port) | Port number which the proxy and NLB listens | `number` | `3129` | no |
+| [proxy\_security\_group\_id](#input\_proxy\_security\_group\_id) | ID for existing Security Group to be used for the proxy VM. Required when create\_proxy\_sg is false | `string` | `null` | no |
+| [proxy\_security\_group\_name](#input\_proxy\_security\_group\_name) | Name of Proxy Security Group for CDP environment. Used only if create\_proxy\_sg is true. | `string` | `null` | no |
+| [proxy\_whitelist\_file](#input\_proxy\_whitelist\_file) | Location of the Proxy Whitelist file. If not specified the files/squid-http-whitelist.txt.tpl file accompanying the module is used. | `string` | `null` | no |
+| [route\_tables\_to\_update](#input\_route\_tables\_to\_update) | List of any route tables to update to point to the Network interface of the Proxy VM | list(object({
route_tables = list(string)
destination_cidr_block = string
}))
| `[]` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [proxy\_lb\_arn](#output\_proxy\_lb\_arn) | ARN of the Proxy Load Balancer |
+| [proxy\_lb\_dns\_name](#output\_proxy\_lb\_dns\_name) | DNS Name of the Proxy Load Balancer |
+| [proxy\_port](#output\_proxy\_port) | Port where Proxy is running |
+
\ No newline at end of file
diff --git a/modules/terraform-aws-proxy/data.tf b/modules/terraform-aws-proxy/data.tf
new file mode 100644
index 0000000..8fde7ba
--- /dev/null
+++ b/modules/terraform-aws-proxy/data.tf
@@ -0,0 +1,61 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+# Find AWS region
+data "aws_region" "current" {}
+
+# Find AMI for default proxy VMs
+data "aws_ami" "proxy_default_ami" {
+
+ most_recent = true
+
+ filter {
+ name = "name"
+ values = ["al2023-ami-2023*-x86_64"]
+ }
+
+ owners = ["amazon"]
+}
+
+# Find details of the VPC
+data "aws_vpc" "proxy_vpc" {
+ id = var.vpc_id
+}
+
+# Find the network interface for the load balancer
+data "aws_network_interface" "proxy_lb" {
+
+ for_each = { for k, v in var.lb_subnet_ids : k => v }
+
+ filter {
+ name = "description"
+ values = ["ELB ${aws_lb.proxy_lb.arn_suffix}"]
+ }
+
+ filter {
+ name = "subnet-id"
+ values = [each.value]
+ }
+}
+
+# Find route table details
+data "aws_route_table" "proxy_rt" {
+
+ for_each = {
+ for k, v in local.route_tables_to_update : k => v
+ }
+
+ route_table_id = each.value.route_table
+
+}
\ No newline at end of file
diff --git a/modules/terraform-aws-proxy/defaults.tf b/modules/terraform-aws-proxy/defaults.tf
new file mode 100644
index 0000000..98521c7
--- /dev/null
+++ b/modules/terraform-aws-proxy/defaults.tf
@@ -0,0 +1,71 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+locals {
+
+ # AWS region (derived from provider lookup unless overridden)
+ aws_region = coalesce(var.aws_region, data.aws_region.current.name)
+
+ # Security Groups
+ proxy_security_group_id = (var.create_proxy_sg ?
+ aws_security_group.proxy_sg[0].id : var.proxy_security_group_id)
+
+ # Proxy VM
+ proxy_aws_ami = coalesce(var.proxy_aws_ami, data.aws_ami.proxy_default_ami.id)
+
+ # User data for Proxy VM (for squid proxy)
+ proxy_launch_template_user_data_file = coalesce(var.proxy_launch_template_user_data_file, "${path.module}/files/squid-user-data.sh.tpl")
+
+ # Squid whitelist file
+ proxy_whitelist_file = coalesce(var.proxy_whitelist_file, "${path.module}/files/squid-whitelist.txt.tpl")
+
+ # Local variables to determine route table to Internal NLB eni mapping
+ route_tables_to_update = flatten([
+ for route in var.route_tables_to_update :
+ [
+ for rt in route.route_tables :
+ {
+ route_table = rt
+ destination_cidr_block = route.destination_cidr_block
+ }
+ ]
+ ])
+
+ lb_eni_details = [
+ for eni in data.aws_network_interface.proxy_lb :
+ {
+ eni_id = eni.id
+ az = eni.availability_zone
+ subnet_id = eni.subnet_id
+ }
+ ]
+
+ # TODO: Explore better rt to eni mapping with the below
+ # route_table_details = [
+ # for rt in data.aws_route_table.proxy_rt :
+ # {
+ # rt_id = rt.id
+ # subnet_ids = rt.associations[*].subnet_id
+ # }
+ # ]
+
+ route_table_to_lb_eni_assoc = {
+ for k, v in data.aws_route_table.proxy_rt : v.id => {
+ # TODO: eni of same subnet assoc if possible otherwise the first eni_id in lb_eni_details
+ eni = local.lb_eni_details[0].eni_id
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/modules/terraform-aws-proxy/doc_fragments/header.md b/modules/terraform-aws-proxy/doc_fragments/header.md
new file mode 100644
index 0000000..205750f
--- /dev/null
+++ b/modules/terraform-aws-proxy/doc_fragments/header.md
@@ -0,0 +1,11 @@
+# Terraform Module for AWS Transit Gateway
+
+This module contains resource files and example variable definition files to create and configure and EC2 Auto-Scaling Group to create a highly available Squid Proxy service. A Network Load Balancer is also created to forward traffic to the proxy instances. This module can be used to assist in deploying Cloudera Data Platform (CDP) Public Cloud in a fully private networking configuration where the CDP Environment uses a proxy configuration via the Network Load Balancer.
+
+## Usage
+
+The [examples](./examples) directory has example of using this module:
+
+* `ex01-minimal_inputs` demonstrates how this module can be used to create Squid proxy instances and NLB in a networking VPC. The [terraform-aws-vpc](../../../terraform-aws-vpc/README.md) module is also used as part of this example.
+
+The sample `terraform.tfvars.sample` describes the required inputs for the example.
diff --git a/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/main.tf b/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/main.tf
new file mode 100644
index 0000000..838f407
--- /dev/null
+++ b/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/main.tf
@@ -0,0 +1,72 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+provider "aws" {
+ profile = var.aws_profile
+ region = var.aws_region
+}
+
+module "ex01_network_vpc" {
+ source = "../../../terraform-aws-vpc"
+
+ cdp_vpc = false
+ vpc_name = "${var.name_prefix}-network-vpc"
+ vpc_cidr = "10.11.0.0/16"
+ enable_nat_gateway = false
+
+ private_cidr_range = var.network_vpc_private_cidr_range
+ public_cidr_range = var.network_vpc_public_cidr_range
+
+}
+
+module "ex01_proxy" {
+ source = "../.."
+
+ vpc_id = module.ex01_network_vpc.vpc_id
+
+ proxy_security_group_name = "${var.name_prefix}-sg"
+ proxy_aws_keypair_name = var.aws_key_pair
+
+ proxy_launch_template_name = "${var.name_prefix}-lt"
+ proxy_autoscaling_group_name = "${var.name_prefix}-asg"
+ proxy_subnet_ids = module.ex01_network_vpc.public_subnets
+
+ network_load_balancer_name = "${var.name_prefix}-lb"
+ target_group_proxy_name = "${var.name_prefix}-tg"
+ lb_subnet_ids = module.ex01_network_vpc.private_subnets
+
+ ingress_rules = [
+ {
+ cidrs = module.ex01_network_vpc.vpc_cidr_blocks
+ from_port = 0
+ to_port = 65535
+ protocol = "tcp"
+ },
+ {
+ cidrs = var.ingress_extra_cidrs
+ from_port = 22
+ # to_port =
+ protocol = "tcp"
+ }
+ ]
+
+ route_tables_to_update = [
+ # Route all Internet traffic in Networking VPC to the proxy instance(s)
+ {
+ route_tables = module.ex01_network_vpc.private_route_tables
+ destination_cidr_block = "0.0.0.0/0"
+ }
+ ]
+
+}
diff --git a/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/terraform.tfvars.sample b/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/terraform.tfvars.sample
new file mode 100644
index 0000000..2e76630
--- /dev/null
+++ b/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/terraform.tfvars.sample
@@ -0,0 +1,23 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+# ------- Global Settings -------
+name_prefix = ""
+
+# ------- Cloud Settings -------
+aws_region = "" # Change this to specify Cloud Provider region, e.g. eu-west-1
+aws_key_pair = "" # Change this with the name of a pre-existing AWS keypair, e.g. my-keypair
+
+# ------- Proxy settings -------
+ingress_extra_cidrs = ["", ""] # Any additional CIDRs the Proxy Security Groups for SSH access
diff --git a/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/variables.tf b/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/variables.tf
new file mode 100644
index 0000000..94c333e
--- /dev/null
+++ b/modules/terraform-aws-proxy/examples/ex01-minimal_inputs/variables.tf
@@ -0,0 +1,84 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+# ------- Global settings -------
+variable "aws_profile" {
+ type = string
+ description = "Profile for AWS cloud credentials"
+
+ # Profile is default unless explicitly specified
+ default = "default"
+}
+
+variable "aws_region" {
+ type = string
+ description = "Region which Cloud resources will be created"
+}
+
+variable "env_tags" {
+ type = map(any)
+ description = "Tags applied to provised resources"
+
+ default = null
+}
+
+variable "name_prefix" {
+ type = string
+ description = "Shorthand name to use when naming resources."
+}
+
+# ------- VPC settings -------
+variable "cdp_vpc_private_cidr_range" {
+ type = number
+ description = "Size of each private subnet for CDP VPC."
+
+ default = 19
+}
+
+variable "cdp_vpc_public_cidr_range" {
+ type = number
+ description = "Size of each public subnet for CDP VPC."
+
+ default = 24
+}
+
+variable "network_vpc_private_cidr_range" {
+ type = number
+ description = "Size of each private subnet for Network VPC."
+
+ default = 19
+}
+
+variable "network_vpc_public_cidr_range" {
+ type = number
+ description = "Size of each public subnet for Network VPC."
+
+ default = 24
+}
+
+# ------- Proxy settings -------
+variable "ingress_extra_cidrs" {
+ type = list(string)
+ description = "List of extra ingress rules to create."
+
+ default = []
+}
+
+
+variable "aws_key_pair" {
+ type = string
+
+ description = "Name of the Public SSH key for the CDP environment"
+
+}
\ No newline at end of file
diff --git a/modules/terraform-aws-proxy/files/squid-user-data.sh.tpl b/modules/terraform-aws-proxy/files/squid-user-data.sh.tpl
new file mode 100644
index 0000000..e3e22fe
--- /dev/null
+++ b/modules/terraform-aws-proxy/files/squid-user-data.sh.tpl
@@ -0,0 +1,145 @@
+#!/bin/bash
+
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+#####################################################
+# User Data Bash script to setup suid proxy on a
+# Amazon Linux 2 EC2 instance.
+#####################################################
+
+# Install
+yum update -y
+yum install -y squid
+
+# Create Squid whitelist file
+echo "${whitelist_txt}" > /etc/squid/whitelist.txt
+
+# Generate self-signed cert
+mkdir -p /etc/squid/ssl
+openssl req \
+ -x509 -new -sha256 -nodes \
+ -newkey rsa:2048 -days 365 \
+ -keyout /etc/squid/ssl/private.key \
+ -out /etc/squid/ssl/cert.pem \
+ -subj "/C=XX/ST=XX/L=squid/O=squid/CN=squid"
+
+
+# Create Squid configuration file
+cat > /etc/squid/squid.conf << EOF
+# Working Config File for non-transparent proxy
+# Recommended minimum configuration:
+#
+# Example rule allowing access from your local networks.
+# Adapt to list your (internal) IP networks from where browsing
+# should be allowed
+acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
+acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
+acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
+acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
+acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
+acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
+acl localnet src fc00::/7 # RFC 4193 local private network range
+acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
+acl SSL_ports port 443
+acl Safe_ports port 80 # http
+acl Safe_ports port 21 # ftp
+acl Safe_ports port 443 # https
+acl Safe_ports port 70 # gopher
+acl Safe_ports port 210 # wais
+acl Safe_ports port 1025-65535 # unregistered ports
+acl Safe_ports port 280 # http-mgmt
+acl Safe_ports port 488 # gss-http
+acl Safe_ports port 591 # filemaker
+acl Safe_ports port 777 # multiling http
+
+# ACL for the whitelist
+acl http-whitelist dstdomain "/etc/squid/whitelist.txt"
+
+# Deny access to URLs not in the whitelist
+http_access allow http-whitelist
+
+http_port ${proxy_port} cert=/etc/squid/ssl/cert.pem key=/etc/squid/ssl/private.key
+https_port ${proxy_port} cert=/etc/squid/ssl/cert.pem key=/etc/squid/ssl/private.key
+ssl_bump bump all
+sslcrtd_program /usr/lib/squid/ssl_crtd -s /var/lib/ssl_db -M 4MB
+sslcrtd_children 8 startup=1 idle=1
+
+# Deny access to all other URLs
+http_access deny all
+
+# Recommended minimum Access Permission configuration:
+# Deny requests to certain unsafe ports
+http_access deny !Safe_ports
+
+
+# Deny CONNECT to other than secure SSL ports
+http_access deny CONNECT !SSL_ports
+
+
+# Only allow cachemgr access from localhost
+http_access allow localhost manager
+http_access deny manager
+
+
+# This default configuration only allows localhost requests because a more
+# permissive Squid installation could introduce new attack vectors into the
+# network by proxying external TCP connections to unprotected services.
+
+
+http_access allow localhost
+
+
+# The two deny rules below are unnecessary in this default configuration
+# because they are followed by a "deny all" rule. However, they may become
+# critically important when you start allowing external requests below them.
+# Protect web applications running on the same server as Squid. They often
+# assume that only local users can access them at "localhost" ports.
+http_access deny to_localhost
+# Protect cloud servers that provide local users with sensitive info about
+# their server via certain well-known link-local (a.k.a. APIPA) addresses.
+http_access deny to_linklocal
+
+#
+# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
+#
+#http_access allow whitelist_url
+# For example, to allow access from your local networks, you may uncomment the
+# following rule (and/or add rules that match your definition of "local"):
+# http_access allow localnet
+# And finally deny all other access to this proxy
+#http_access deny all
+
+
+http_access allow all
+# Squid normally listens to port 3128
+# Squid normally listens to port 3128
+http_port 3128
+# Uncomment and adjust the following to add a disk cache directory.
+#cache_dir ufs /var/spool/squid 100 16 256
+# Leave coredumps in the first cache dir
+coredump_dir /var/spool/squid
+#
+# Add any of your own refresh_pattern entries above these.
+#
+refresh_pattern ^ftp: 1440 20% 10080
+refresh_pattern ^gopher: 1440 0% 1440
+refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
+refresh_pattern . 0 20% 4320
+EOF
+
+
+# Start and enable squid
+systemctl enable squid
+systemctl start squid
\ No newline at end of file
diff --git a/modules/terraform-aws-proxy/files/squid-whitelist.txt.tpl b/modules/terraform-aws-proxy/files/squid-whitelist.txt.tpl
new file mode 100644
index 0000000..26056fa
--- /dev/null
+++ b/modules/terraform-aws-proxy/files/squid-whitelist.txt.tpl
@@ -0,0 +1,123 @@
+# Cloudera CCMv2 for Persistent Control Plane connection
+%{if cdp_region == "us-west-1" ~}
+# ..US-based Control Plane
+.v2.us-west-1.ccm.cdp.cloudera.com
+%{ endif ~}
+
+%{if cdp_region == "eu-1" ~}
+# ..EU-based Control Plane
+.v2.ccm.eu-1.cdp.cloudera.com
+%{ endif ~}
+
+%{if cdp_region == "ap-1" ~}
+# ..AP-based Control Plane
+.v2.ccm.ap-1.cdp.cloudera.com
+%{ endif ~}
+
+# Cloudera Databus for Telemetry, billing and metering data
+%{if cdp_region == "us-west-1" ~}
+# ..US-based Control Plane
+dbusapi.us-west-1.sigma.altus.cloudera.com
+cloudera-dbus-prod.s3.amazonaws.com
+%{ endif ~}
+
+%{if cdp_region == "eu-1" ~}
+# ..EU-based Control Plane
+api.eu-1.cdp.cloudera.com
+mow-prod-eu-central-1-sigmadbus-dbus.s3.eu-central-1.amazonaws.com # NOTE - this is a subdomain of the CDP AWS bucket with flow definitions for CDF below
+mow-prod-eu-central-1-sigmadbus-dbus.s3.amazonaws.com
+%{ endif ~}
+
+%{if cdp_region == "ap-1" ~}
+# ..AP-based Control Plane
+api.ap-1.cdp.cloudera.com
+# mow-prod-ap-southeast-2-sigmadbus-dbus.s3.ap-southeast-2.amazonaws.com # NOTE - this is a subdomain of the CDP AWS bucket with flow definitions for CDF below
+mow-prod-ap-southeast-2-sigmadbus-dbus.s3.amazonaws.com
+%{ endif ~}
+
+# Cloudera Manager parcels for Software distribution
+archive.cloudera.com
+
+# Control Plane API
+api.${cdp_region}.cdp.cloudera.com
+
+# Cloudera RPMs for workload agents
+cloudera-service-delivery-cache.s3.amazonaws.com
+
+# Docker Images for CDE, CDF, CML and CDW
+container.repository.cloudera.com
+docker.repository.cloudera.com
+
+container.repo.cloudera.com
+
+%{if cdp_region == "us-west-1" ~}
+# ..US-based Control Plane
+prod-us-west-2-starport-layer-bucket.s3.us-west-2.amazonaws.com
+prod-eu-west-1-starport-layer-bucket.s3.eu-west-1.amazonaws.com # NOTE - found that this domain was required for us control plane and eu aws region
+prod-us-west-2-starport-layer-bucket.s3.amazonaws.com
+s3-r-w.us-west-2.amazonaws.com
+.execute-api.us-west-2.amazonaws.com
+cloudera-dbus-prod.s3.us-west-2.amazonaws.com # NOTE - found that this domain was required for CDE
+%{ endif ~}
+
+%{if cdp_region == "eu-1" ~}
+# ..EU-based Control Plane
+prod-eu-west-1-starport-layer-bucket.s3.eu-west-1.amazonaws.com
+prod-eu-west-1-starport-layer-bucket.s3.amazonaws.com
+s3-r-w.eu-west-1.amazonaws.com
+.execute-api.eu-west-1.amazonaws.com
+%{ endif ~}
+
+%{if cdp_region == "ap-1" ~}
+# ..AP-based Control Plane
+prod-ap-southeast-1-starport-layer-bucket.s3.ap-southeast-1.amazonaws.com
+prod-ap-southeast-1-starport-layer-bucket.s3.amazonaws.com
+s3-r-w.ap-southeast-1.amazonaws.com
+.execute-api.ap-southeast-1.amazonaws.com
+%{ endif ~}
+
+# CDP AWS bucket with flow definitions for CDF
+%{if cdp_region == "us-west-1" ~}
+# ..US-based Control Plane
+.s3.us-west-1.amazonaws.com
+%{ endif ~}
+
+%{if cdp_region == "eu-1" ~}
+# ..EU-based Control Plane
+# .s3.eu-central-1.amazonaws.com # More specific CDF bucket is used instead
+cldr-mow-prod-eu-central-1-dfx-flow-artifacts.s3.eu-central-1.amazonaws.com
+%{ endif ~}
+
+%{if cdp_region == "ap-1" ~}
+# ..AP-based Control Plane
+.s3.ap-southeast-2.amazonaws.com
+%{ endif ~}
+
+# Public Signing Key Retrieval for CDE and CDF
+console.${cdp_region}.cdp.cloudera.com
+
+%{if cdp_region == "us-west-1" ~}
+# ..Additional for US-based Control Plane
+consoleauth.altus.cloudera.com
+%{ endif ~}
+
+# SQL Stream Builder PostgreSQL driver install
+pypi.org
+
+# AMPs for CML incl Learning Hub
+raw.githubusercontent.com
+github.com
+
+# AWS-specific endpoints
+.eks.${aws_region}.amazonaws.com
+.autoscaling.${aws_region}.amazonaws.com
+.cloudformation.${aws_region}.amazonaws.com
+
+# Additional endpoints for CDE deployment
+cloudera.com
+www.cloudera.com
+truststore.pki.rds.amazonaws.com
+
+# Additional endpoints for CDW deployment
+amazonlinux-2-repos-${aws_region}.s3.dualstack.${aws_region}.amazonaws.com
+iamapi.${cdp_region}.altus.cloudera.com
diff --git a/modules/terraform-aws-proxy/main.tf b/modules/terraform-aws-proxy/main.tf
new file mode 100644
index 0000000..ea67d91
--- /dev/null
+++ b/modules/terraform-aws-proxy/main.tf
@@ -0,0 +1,187 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+# ------- Networking - Security Group and Security Group rules -------
+# Security Group for proxy
+resource "aws_security_group" "proxy_sg" {
+
+ count = var.create_proxy_sg ? 1 : 0
+
+ vpc_id = var.vpc_id
+ name = var.proxy_security_group_name
+ description = var.proxy_security_group_name
+ tags = merge(var.env_tags, { Name = var.proxy_security_group_name })
+}
+
+# Create ingress SG rule
+resource "aws_security_group_rule" "proxy_ingress" {
+
+ for_each = { for k, v in var.ingress_rules : k => v
+ if var.create_proxy_sg
+ }
+
+ security_group_id = aws_security_group.proxy_sg[0].id
+ type = "ingress"
+ description = "Ingress rules for ${var.proxy_security_group_name} Proxy Security Group"
+
+ cidr_blocks = each.value.cidrs
+ from_port = each.value.from_port
+ to_port = coalesce(each.value.to_port, each.value.from_port)
+ protocol = each.value.protocol
+
+}
+
+# Access from NLB to Proxy VMs within the VPC
+resource "aws_security_group_rule" "proxy_lb_ingress" {
+
+ count = var.create_proxy_sg ? 1 : 0
+
+ security_group_id = aws_security_group.proxy_sg[0].id
+ type = "ingress"
+ description = "Allow traffic from NLB to Proxy VMs in ${var.proxy_security_group_name} Proxy Security Group"
+
+ cidr_blocks = data.aws_vpc.proxy_vpc.cidr_block_associations[*].cidr_block
+ from_port = var.proxy_port
+ to_port = var.proxy_port
+ protocol = "TCP"
+}
+
+# Create egress SG rule
+resource "aws_security_group_rule" "proxy_egress" {
+
+ for_each = { for k, v in var.egress_rules : k => v
+ if var.create_proxy_sg
+ }
+
+ security_group_id = aws_security_group.proxy_sg[0].id
+ type = "egress"
+ description = "Egress rules for ${var.proxy_security_group_name} Proxy Security Group"
+
+ cidr_blocks = each.value.cidrs #tfsec:ignore:aws-ec2-no-public-egress-sgr #tfsec:ignore:aws-vpc-no-public-egress-sgr
+ from_port = each.value.from_port
+ to_port = coalesce(each.value.to_port, each.value.from_port)
+ protocol = each.value.protocol
+
+}
+
+# ------- Proxy launch template and Auto-Scaling Groups -------
+resource "aws_launch_template" "proxy_lt" {
+
+ name = var.proxy_launch_template_name
+
+ image_id = local.proxy_aws_ami
+ instance_type = var.proxy_aws_instance_type
+ key_name = var.proxy_aws_keypair_name
+
+ user_data = base64encode(templatefile(local.proxy_launch_template_user_data_file, {
+ proxy_port = var.proxy_port
+ whitelist_txt = templatefile(local.proxy_whitelist_file, {
+ aws_region = local.aws_region
+ cdp_region = var.cdp_region })
+ }))
+
+ network_interfaces {
+ associate_public_ip_address = var.enable_proxy_public_ip
+ security_groups = [local.proxy_security_group_id]
+ }
+
+ metadata_options {
+ http_tokens = "required"
+ }
+
+ tags = var.env_tags
+
+}
+
+resource "aws_autoscaling_group" "proxy_asg" {
+ name = var.proxy_autoscaling_group_name
+ min_size = var.autoscaling_group_scaling.min_size
+ max_size = var.autoscaling_group_scaling.max_size
+ desired_capacity = var.autoscaling_group_scaling.desired_capacity
+
+ target_group_arns = [aws_lb_target_group.proxy_tg.arn]
+
+ vpc_zone_identifier = var.proxy_subnet_ids
+
+ launch_template {
+ id = aws_launch_template.proxy_lt.id
+ version = "$Latest"
+ }
+
+ dynamic "tag" {
+ for_each = merge(var.env_tags, { Name = "${var.proxy_autoscaling_group_name}-proxy" })
+ content {
+ key = tag.key
+ value = tag.value
+ propagate_at_launch = true
+ }
+ }
+
+}
+
+# ------- Internal Network Load Balancer -------
+
+resource "aws_lb" "proxy_lb" {
+ name = var.network_load_balancer_name
+ internal = true
+ load_balancer_type = "network"
+ subnets = var.lb_subnet_ids
+
+ tags = var.env_tags
+}
+
+resource "aws_lb_listener" "proxy_lb_listener" {
+ load_balancer_arn = aws_lb.proxy_lb.arn
+ port = var.proxy_port
+ protocol = "TCP"
+
+ default_action {
+ type = "forward"
+ target_group_arn = aws_lb_target_group.proxy_tg.arn
+ }
+
+ tags = var.env_tags
+}
+
+# Target groups are essentially the end point of the LB
+resource "aws_lb_target_group" "proxy_tg" {
+ name = var.target_group_proxy_name
+ target_type = "instance"
+ port = var.proxy_port
+ protocol = "TCP"
+ vpc_id = var.vpc_id
+
+ # TODO: Review health checks on the TG
+
+ tags = var.env_tags
+}
+
+# Now we have a target group we need to assign something to it. This is done through target group attachments
+resource "aws_autoscaling_attachment" "proxy_asg_tg_attach" {
+ autoscaling_group_name = aws_autoscaling_group.proxy_asg.id
+ lb_target_group_arn = aws_lb_target_group.proxy_tg.arn
+}
+
+
+# ------- Route Table update -------
+# Update the route tables to point to eni of NLB
+resource "aws_route" "vpc_tgw_route" {
+ for_each = {
+ for k, v in local.route_tables_to_update : k => v
+ }
+
+ route_table_id = each.value.route_table
+ destination_cidr_block = each.value.destination_cidr_block
+ network_interface_id = local.route_table_to_lb_eni_assoc[each.value.route_table].eni
+}
diff --git a/modules/terraform-aws-proxy/outputs.tf b/modules/terraform-aws-proxy/outputs.tf
new file mode 100644
index 0000000..9df92b9
--- /dev/null
+++ b/modules/terraform-aws-proxy/outputs.tf
@@ -0,0 +1,46 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+# DNS name of the NLB
+output "proxy_lb_dns_name" {
+ value = aws_lb.proxy_lb.dns_name
+
+ description = "DNS Name of the Proxy Load Balancer"
+}
+
+output "proxy_lb_arn" {
+ value = aws_lb.proxy_lb.arn
+
+ description = "ARN of the Proxy Load Balancer"
+}
+
+# Proxy port
+output "proxy_port" {
+ value = var.proxy_port
+
+ description = "Port where Proxy is running"
+}
\ No newline at end of file
diff --git a/modules/terraform-aws-proxy/provider.tf b/modules/terraform-aws-proxy/provider.tf
new file mode 100644
index 0000000..d45eadd
--- /dev/null
+++ b/modules/terraform-aws-proxy/provider.tf
@@ -0,0 +1,24 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+
+ required_version = "> 1.3.0"
+}
diff --git a/modules/terraform-aws-proxy/variables.tf b/modules/terraform-aws-proxy/variables.tf
new file mode 100644
index 0000000..cd489f0
--- /dev/null
+++ b/modules/terraform-aws-proxy/variables.tf
@@ -0,0 +1,217 @@
+# Copyright 2023 Cloudera, Inc. All Rights Reserved.
+#
+# 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.
+
+# ------- Global settings -------
+variable "env_tags" {
+ type = map(any)
+ description = "Tags applied to provisioned resources"
+
+ default = {}
+}
+
+variable "vpc_id" {
+ type = string
+ description = "VPC ID for where the proxy VM will run"
+
+}
+
+variable "cdp_region" {
+ type = string
+ description = "CDP Control Plane region, used in Proxy Whitelist configuration files."
+
+ default = "us-west-1"
+}
+
+variable "aws_region" {
+ type = string
+ description = "AWS region, used in Proxy Whitelist configuration files. If not provided will perform lookup of aws_region data source."
+
+ default = null
+}
+
+# ------- Proxy SG -------
+variable "create_proxy_sg" {
+ type = bool
+
+ description = "Flag to specify if the Security Group for the proxy should be created."
+
+ default = true
+}
+
+variable "proxy_security_group_name" {
+ type = string
+
+ description = "Name of Proxy Security Group for CDP environment. Used only if create_proxy_sg is true."
+
+ default = null
+}
+
+variable "proxy_security_group_id" {
+ type = string
+
+ description = "ID for existing Security Group to be used for the proxy VM. Required when create_proxy_sg is false"
+
+ default = null
+}
+
+variable "ingress_rules" {
+ description = "List of ingress rules to create. Used only if create_proxy_sg is true"
+ type = list(object({
+ cidrs = list(string)
+ from_port = number
+ to_port = optional(number)
+ protocol = string
+ }))
+ default = []
+}
+
+variable "egress_rules" {
+ description = "List of egress rules to create. Used only if create_proxy_sg is true"
+ type = list(object({
+ cidrs = list(string)
+ from_port = number
+ to_port = optional(number)
+ protocol = string
+ }))
+ default = [{
+ cidrs = ["0.0.0.0/0"]
+ from_port = 0
+ to_port = 0
+ protocol = "all"
+ }]
+}
+
+# ------- Proxy Settings -------
+variable "proxy_port" {
+ type = number
+ description = "Port number which the proxy and NLB listens"
+
+ default = 3129
+}
+
+variable "proxy_launch_template_name" {
+ type = string
+
+ description = "Name of Launch Template for the Proxy VMs."
+
+}
+
+variable "enable_proxy_public_ip" {
+ type = bool
+
+ description = "Assign a public IP address to the Proxy VM"
+
+ default = true
+}
+
+variable "proxy_aws_ami" {
+ type = string
+ description = "The AWS AMI to use for the proxy VM"
+
+ default = null
+}
+
+variable "proxy_aws_instance_type" {
+ type = string
+ description = "The EC2 instance type to use for the proxy VM"
+
+ default = "t3.medium"
+
+}
+
+variable "proxy_aws_keypair_name" {
+ type = string
+
+ description = "SSH Keypair name for the proxy VM"
+
+}
+
+variable "proxy_launch_template_user_data_file" {
+ type = string
+
+ description = "Location of the AWS Launch Template user data script. If not specified the files/user-data-proxy.sh.tpl file accompanying the module is used."
+
+ default = null
+}
+
+variable "proxy_whitelist_file" {
+ type = string
+
+ description = "Location of the Proxy Whitelist file. If not specified the files/squid-http-whitelist.txt.tpl file accompanying the module is used."
+
+ default = null
+}
+
+variable "proxy_autoscaling_group_name" {
+ type = string
+
+ description = "Name of Autoscaling Group for the Proxy VMs."
+
+}
+
+variable "autoscaling_group_scaling" {
+ type = object({
+ min_size = number
+ max_size = number
+ desired_capacity = number
+ })
+
+ description = "Minimum, maximum and desired size of EC2 instance in the Auto Scaling Group."
+
+ default = {
+ min_size = 3
+ max_size = 6
+ desired_capacity = 3
+ }
+}
+
+variable "proxy_subnet_ids" {
+ type = list(any)
+
+ description = "The IDs of the subnet where the proxy VMs will run"
+
+}
+
+# ------- Internal Network Load Balancer -------
+variable "network_load_balancer_name" {
+ type = string
+
+ description = "Name of Network Load Balancer for the Proxy."
+
+}
+
+variable "lb_subnet_ids" {
+ type = list(any)
+
+ description = "The IDs of the subnet for the Network Load Balancer"
+
+}
+
+variable "target_group_proxy_name" {
+ type = string
+
+ description = "Name of Target Group for the Proxy."
+
+}
+
+# ------- Route table updates -------
+variable "route_tables_to_update" {
+ description = "List of any route tables to update to point to the Network interface of the Proxy VM"
+ type = list(object({
+ route_tables = list(string)
+ destination_cidr_block = string
+ }))
+
+ default = []
+}
\ No newline at end of file