diff --git a/.github/workflows/ci-cd-production.yaml b/.github/workflows/ci-cd-production.yaml
index 8d6bea8f36..ea8ba05313 100644
--- a/.github/workflows/ci-cd-production.yaml
+++ b/.github/workflows/ci-cd-production.yaml
@@ -62,7 +62,6 @@ jobs:
django_settings_module: settings.production
enable_additional_parameters: true
enable_cron_tasks: true
- enable_nat_gateway: true
enable_rds_proxy: true
environment: production
frontend_desired_count: 2
diff --git a/.github/workflows/ci-cd-staging.yaml b/.github/workflows/ci-cd-staging.yaml
index a6ad2bb667..4324d8cf97 100644
--- a/.github/workflows/ci-cd-staging.yaml
+++ b/.github/workflows/ci-cd-staging.yaml
@@ -61,7 +61,6 @@ jobs:
django_configuration: Staging
django_settings_module: settings.staging
enable_cron_tasks: false
- enable_nat_gateway: false
enable_rds_proxy: false
environment: staging
frontend_desired_count: 1
diff --git a/.github/workflows/run-ci-cd.yaml b/.github/workflows/run-ci-cd.yaml
index d4ff79b455..e57d4d5bc4 100644
--- a/.github/workflows/run-ci-cd.yaml
+++ b/.github/workflows/run-ci-cd.yaml
@@ -69,10 +69,6 @@ on:
description: Enable cron tasks
required: true
type: boolean
- enable_nat_gateway:
- description: Enable NAT gateway
- required: true
- type: boolean
enable_rds_proxy:
description: Enable RDS proxy
required: true
@@ -310,7 +306,6 @@ jobs:
django_settings_module: ${{ inputs.django_settings_module }}
enable_additional_parameters: ${{ inputs.enable_additional_parameters }}
enable_cron_tasks: ${{ inputs.enable_cron_tasks }}
- enable_nat_gateway: ${{ inputs.enable_nat_gateway }}
enable_rds_proxy: ${{ inputs.enable_rds_proxy }}
environment: ${{ inputs.environment }}
frontend_desired_count: ${{ inputs.frontend_desired_count }}
diff --git a/.github/workflows/run-deploy.yaml b/.github/workflows/run-deploy.yaml
index 5c9c7a50dd..ff4adf5721 100644
--- a/.github/workflows/run-deploy.yaml
+++ b/.github/workflows/run-deploy.yaml
@@ -65,10 +65,6 @@ on:
description: Enable cron tasks
required: true
type: boolean
- enable_nat_gateway:
- description: Enable NAT gateway
- required: true
- type: boolean
enable_rds_proxy:
description: Enable RDS proxy
required: true
@@ -217,7 +213,6 @@ jobs:
django_settings_module="${{ inputs.django_settings_module }}"
enable_additional_parameters=${{ inputs.enable_additional_parameters }}
enable_cron_tasks=${{ inputs.enable_cron_tasks }}
- enable_nat_gateway=${{ inputs.enable_nat_gateway }}
enable_rds_proxy=${{ inputs.enable_rds_proxy }}
environment="${{ inputs.environment }}"
frontend_desired_count=${{ inputs.frontend_desired_count }}
@@ -238,7 +233,6 @@ jobs:
echo "backend_service_name=$(terraform output -raw backend_service_name)"
echo "frontend_cluster_name=$(terraform output -raw frontend_cluster_name)"
echo "frontend_service_name=$(terraform output -raw frontend_service_name)"
- echo "nat_gateway_enabled=$(terraform output -raw nat_gateway_enabled)"
echo "tasks_cluster_name=$(terraform output -raw tasks_cluster_name)"
echo "tasks_security_group_id=$(terraform output -raw tasks_security_group_id)"
echo "tasks_subnet_ids=$(terraform output -json tasks_subnet_ids | jq -r 'join(",")')"
@@ -249,12 +243,11 @@ jobs:
id: migrate-task
env:
CLUSTER_NAME: ${{ steps.tf-outputs.outputs.tasks_cluster_name }}
- NAT_GATEWAY_ENABLED: ${{ steps.tf-outputs.outputs.nat_gateway_enabled }}
TASKS_SECURITY_GROUP_ID: ${{ steps.tf-outputs.outputs.tasks_security_group_id }}
TASK_DEFINITION: ${{ inputs.migrate_task_definition }}
TASKS_SUBNET_IDS: ${{ steps.tf-outputs.outputs.tasks_subnet_ids }}
run: |
- ASSIGN_PUBLIC_IP=$([ "$NAT_GATEWAY_ENABLED" = "true" ] && echo "DISABLED" || echo "ENABLED")
+ ASSIGN_PUBLIC_IP=DISABLED
TASK_ARN=$(aws ecs run-task \
--cluster "$CLUSTER_NAME" \
--task-definition "$TASK_DEFINITION" \
@@ -291,12 +284,11 @@ jobs:
- name: Run ECS index-data task
env:
CLUSTER_NAME: ${{ steps.tf-outputs.outputs.tasks_cluster_name }}
- NAT_GATEWAY_ENABLED: ${{ steps.tf-outputs.outputs.nat_gateway_enabled }}
TASK_DEFINITION: ${{ inputs.index_task_definition }}
TASKS_SECURITY_GROUP_ID: ${{ steps.tf-outputs.outputs.tasks_security_group_id }}
TASKS_SUBNET_IDS: ${{ steps.tf-outputs.outputs.tasks_subnet_ids }}
run: |
- ASSIGN_PUBLIC_IP=$([ "$NAT_GATEWAY_ENABLED" = "true" ] && echo "DISABLED" || echo "ENABLED")
+ ASSIGN_PUBLIC_IP=DISABLED
RESPONSE=$(aws ecs run-task \
--cluster "$CLUSTER_NAME" \
--task-definition "$TASK_DEFINITION" \
diff --git a/infrastructure/README.md b/infrastructure/README.md
index afb1eecbb2..fa91165675 100644
--- a/infrastructure/README.md
+++ b/infrastructure/README.md
@@ -260,8 +260,7 @@ Run the following commands to execute ECS tasks with the correct network configu
CLUSTER=$(terraform output -raw tasks_cluster_name)
SECURITY_GROUP=$(terraform output -raw tasks_security_group_id)
SUBNETS=$(terraform output -json tasks_subnet_ids | jq -r 'join(",")')
-NAT_ENABLED=$(terraform output -raw nat_gateway_enabled)
-ASSIGN_PUBLIC_IP=$([ "$NAT_ENABLED" = "true" ] && echo "DISABLED" || echo "ENABLED")
+ASSIGN_PUBLIC_IP=DISABLED
```
> [!NOTE]
@@ -313,9 +312,9 @@ aws ecs run-task \
- Environment: Cluster: `nest-staging-tasks-cluster`
- Networking:
- VPC: `nest-staging-vpc`
- - Subnets: Choose a private subnet if NAT Gateway is enabled, public otherwise (default).
+ - Subnets: Choose a private subnet.
- Security group name: select the ECS security group (e.g. `nest-staging-tasks-sg`).
- - Public IP: Turned off if NAT Gateway is enabled, Turned on otherwise (default).
+ - Public IP: Turned off.
- Click "Create"
- The task is now running... Click on the task ID to view Logs, Status, etc.
- Follow the same steps for `nest-staging-load-data` and `nest-staging-index-data`.
diff --git a/infrastructure/live/README.md b/infrastructure/live/README.md
index 9a43be941b..360862d3b6 100644
--- a/infrastructure/live/README.md
+++ b/infrastructure/live/README.md
@@ -102,7 +102,6 @@ No resources.
| [domain\_name](#input\_domain\_name) | The domain name for the site. | `string` | n/a | yes |
| [enable\_additional\_parameters](#input\_enable\_additional\_parameters) | Whether to enable additional parameters (e.g. for production). | `bool` | `false` | no |
| [enable\_cron\_tasks](#input\_enable\_cron\_tasks) | Whether to enable scheduled cron tasks. | `bool` | n/a | yes |
-| [enable\_nat\_gateway](#input\_enable\_nat\_gateway) | Whether to enable a NAT Gateway. | `bool` | `true` | no |
| [enable\_rds\_proxy](#input\_enable\_rds\_proxy) | Whether to create an RDS proxy. | `bool` | `false` | no |
| [enable\_vpc\_cloudwatch\_logs\_endpoint](#input\_enable\_vpc\_cloudwatch\_logs\_endpoint) | Whether to create CloudWatch Logs VPC endpoint. | `bool` | `false` | no |
| [enable\_vpc\_ecr\_api\_endpoint](#input\_enable\_vpc\_ecr\_api\_endpoint) | Whether to create ECR API VPC endpoint. | `bool` | `false` | no |
@@ -145,10 +144,9 @@ No resources.
| [frontend\_ecr\_repository\_url](#output\_frontend\_ecr\_repository\_url) | The URL of the frontend ECR repository. |
| [frontend\_service\_name](#output\_frontend\_service\_name) | The name of the ECS frontend service. |
| [frontend\_url](#output\_frontend\_url) | The URL to access the frontend. |
-| [nat\_gateway\_enabled](#output\_nat\_gateway\_enabled) | Whether a NAT Gateway is enabled. |
| [private\_subnet\_ids](#output\_private\_subnet\_ids) | A list of private subnet IDs. |
| [shared\_data\_bucket\_name](#output\_shared\_data\_bucket\_name) | S3 bucket for shared public data (e.g. nest.dump). |
| [tasks\_cluster\_name](#output\_tasks\_cluster\_name) | The name of the ECS tasks cluster. |
| [tasks\_security\_group\_id](#output\_tasks\_security\_group\_id) | The ID of the security group for ECS tasks. |
-| [tasks\_subnet\_ids](#output\_tasks\_subnet\_ids) | A list of public or private subnet IDs for ECS tasks. |
+| [tasks\_subnet\_ids](#output\_tasks\_subnet\_ids) | A list of private subnet IDs for ECS tasks. |
diff --git a/infrastructure/live/main.tf b/infrastructure/live/main.tf
index 74168e6196..f71ee61212 100644
--- a/infrastructure/live/main.tf
+++ b/infrastructure/live/main.tf
@@ -15,7 +15,6 @@ terraform {
}
locals {
- assign_public_ip = var.enable_nat_gateway ? false : true
common_tags = {
Environment = var.environment
ManagedBy = "Terraform"
@@ -41,7 +40,7 @@ module "alb" {
module "backend" {
source = "../modules/service"
- assign_public_ip = local.assign_public_ip
+ assign_public_ip = false
auto_scaling_cpu_target = var.auto_scaling_cpu_target
auto_scaling_scale_in_cooldown = var.auto_scaling_scale_in_cooldown
auto_scaling_scale_out_cooldown = var.auto_scaling_scale_out_cooldown
@@ -63,7 +62,7 @@ module "backend" {
project_name = var.project_name
security_group_id = module.security.backend_sg_id
service_name = "backend"
- subnet_ids = var.enable_nat_gateway ? module.networking.private_subnet_ids : module.networking.public_subnet_ids
+ subnet_ids = module.networking.private_subnet_ids
target_group_arn = module.alb.backend_target_group_arn
task_role_policy_arns = [module.storage.static_read_write_policy_arn]
use_fargate_spot = var.backend_use_fargate_spot
@@ -111,7 +110,7 @@ module "database" {
module "frontend" {
source = "../modules/service"
- assign_public_ip = local.assign_public_ip
+ assign_public_ip = false
auto_scaling_cpu_target = var.auto_scaling_cpu_target
auto_scaling_scale_in_cooldown = var.auto_scaling_scale_in_cooldown
auto_scaling_scale_out_cooldown = var.auto_scaling_scale_out_cooldown
@@ -130,7 +129,7 @@ module "frontend" {
project_name = var.project_name
security_group_id = module.security.frontend_sg_id
service_name = "frontend"
- subnet_ids = var.enable_nat_gateway ? module.networking.private_subnet_ids : module.networking.public_subnet_ids
+ subnet_ids = module.networking.private_subnet_ids
target_group_arn = module.alb.frontend_target_group_arn
use_fargate_spot = var.frontend_use_fargate_spot
}
@@ -164,7 +163,6 @@ module "networking" {
availability_zones = var.availability_zones
aws_region = var.aws_region
common_tags = local.common_tags
- enable_nat_gateway = var.enable_nat_gateway
enable_vpc_cloudwatch_logs_endpoint = var.enable_vpc_cloudwatch_logs_endpoint
enable_vpc_ecr_api_endpoint = var.enable_vpc_ecr_api_endpoint
enable_vpc_ecr_dkr_endpoint = var.enable_vpc_ecr_dkr_endpoint
@@ -233,7 +231,7 @@ module "storage" {
module "tasks" {
source = "../modules/tasks"
- assign_public_ip = local.assign_public_ip
+ assign_public_ip = false
aws_region = var.aws_region
common_tags = local.common_tags
container_parameters_arns = module.parameters.django_ssm_parameter_arns
@@ -247,6 +245,6 @@ module "tasks" {
image_tag = var.backend_image_tag
kms_key_arn = module.kms.key_arn
project_name = var.project_name
- subnet_ids = var.enable_nat_gateway ? module.networking.private_subnet_ids : module.networking.public_subnet_ids
+ subnet_ids = module.networking.private_subnet_ids
use_fargate_spot = var.tasks_use_fargate_spot
}
diff --git a/infrastructure/live/outputs.tf b/infrastructure/live/outputs.tf
index 29047c7057..ef6024dc24 100644
--- a/infrastructure/live/outputs.tf
+++ b/infrastructure/live/outputs.tf
@@ -53,11 +53,6 @@ output "frontend_url" {
value = "https://${var.domain_name}"
}
-output "nat_gateway_enabled" {
- description = "Whether a NAT Gateway is enabled."
- value = var.enable_nat_gateway
-}
-
output "private_subnet_ids" {
description = "A list of private subnet IDs."
value = module.networking.private_subnet_ids
@@ -79,6 +74,6 @@ output "tasks_security_group_id" {
}
output "tasks_subnet_ids" {
- description = "A list of public or private subnet IDs for ECS tasks."
- value = var.enable_nat_gateway ? module.networking.private_subnet_ids : module.networking.public_subnet_ids
+ description = "A list of private subnet IDs for ECS tasks."
+ value = module.networking.private_subnet_ids
}
diff --git a/infrastructure/live/terraform.production.tfvars.example b/infrastructure/live/terraform.production.tfvars.example
index 8d84d8d685..77dc2c3328 100644
--- a/infrastructure/live/terraform.production.tfvars.example
+++ b/infrastructure/live/terraform.production.tfvars.example
@@ -16,7 +16,6 @@ django_release_version = "0.0.0"
django_settings_module = "settings.production"
enable_additional_parameters = true
enable_cron_tasks = true
-enable_nat_gateway = true
enable_rds_proxy = true
environment = "production"
frontend_desired_count = 2
diff --git a/infrastructure/live/terraform.staging.tfvars.example b/infrastructure/live/terraform.staging.tfvars.example
index 3a5c1c3b91..1367b9500b 100644
--- a/infrastructure/live/terraform.staging.tfvars.example
+++ b/infrastructure/live/terraform.staging.tfvars.example
@@ -14,7 +14,6 @@ domain_name = "nest.owasp.dev"
django_configuration = "Staging"
django_settings_module = "settings.staging"
enable_cron_tasks = false
-enable_nat_gateway = false
enable_rds_proxy = false
environment = "staging"
frontend_desired_count = 1
diff --git a/infrastructure/live/variables.tf b/infrastructure/live/variables.tf
index 86181dc88e..ed7af5ff60 100644
--- a/infrastructure/live/variables.tf
+++ b/infrastructure/live/variables.tf
@@ -193,12 +193,6 @@ variable "enable_cron_tasks" {
type = bool
}
-variable "enable_nat_gateway" {
- description = "Whether to enable a NAT Gateway."
- type = bool
- default = true
-}
-
variable "enable_rds_proxy" {
description = "Whether to create an RDS proxy."
type = bool
diff --git a/infrastructure/modules/networking/README.md b/infrastructure/modules/networking/README.md
index 9c3c4a653d..9a40db0478 100644
--- a/infrastructure/modules/networking/README.md
+++ b/infrastructure/modules/networking/README.md
@@ -46,7 +46,6 @@
| [availability\_zones](#input\_availability\_zones) | A list of availability zones for the VPC. | `list(string)` | n/a | yes |
| [aws\_region](#input\_aws\_region) | The AWS region. | `string` | n/a | yes |
| [common\_tags](#input\_common\_tags) | A map of common tags to apply to all resources. | `map(string)` | `{}` | no |
-| [enable\_nat\_gateway](#input\_enable\_nat\_gateway) | Whether to enable a NAT Gateway. | `bool` | `true` | no |
| [enable\_vpc\_cloudwatch\_logs\_endpoint](#input\_enable\_vpc\_cloudwatch\_logs\_endpoint) | Whether to create CloudWatch Logs VPC endpoint. | `bool` | `false` | no |
| [enable\_vpc\_ecr\_api\_endpoint](#input\_enable\_vpc\_ecr\_api\_endpoint) | Whether to create ECR API VPC endpoint. | `bool` | `false` | no |
| [enable\_vpc\_ecr\_dkr\_endpoint](#input\_enable\_vpc\_ecr\_dkr\_endpoint) | Whether to create ECR DKR VPC endpoint. | `bool` | `false` | no |
diff --git a/infrastructure/modules/networking/main.tf b/infrastructure/modules/networking/main.tf
index 55138ffcd9..d977246eb2 100644
--- a/infrastructure/modules/networking/main.tf
+++ b/infrastructure/modules/networking/main.tf
@@ -49,7 +49,6 @@ resource "aws_internet_gateway" "main" {
}
resource "aws_eip" "nat" {
- count = var.enable_nat_gateway ? 1 : 0
depends_on = [aws_internet_gateway.main]
domain = "vpc"
tags = merge(var.common_tags, {
@@ -58,8 +57,7 @@ resource "aws_eip" "nat" {
}
resource "aws_nat_gateway" "main" {
- count = var.enable_nat_gateway ? 1 : 0
- allocation_id = aws_eip.nat[0].id
+ allocation_id = aws_eip.nat.id
depends_on = [aws_internet_gateway.main]
subnet_id = aws_subnet.public[0].id
tags = merge(var.common_tags, {
@@ -67,6 +65,16 @@ resource "aws_nat_gateway" "main" {
})
}
+moved {
+ from = aws_eip.nat[0]
+ to = aws_eip.nat
+}
+
+moved {
+ from = aws_nat_gateway.main[0]
+ to = aws_nat_gateway.main
+}
+
resource "aws_route_table" "public" {
tags = merge(var.common_tags, {
Name = "${var.project_name}-${var.environment}-public-rt"
@@ -85,12 +93,9 @@ resource "aws_route_table" "private" {
})
vpc_id = aws_vpc.main.id
- dynamic "route" {
- for_each = var.enable_nat_gateway ? [1] : []
- content {
- cidr_block = "0.0.0.0/0"
- nat_gateway_id = aws_nat_gateway.main[0].id
- }
+ route {
+ cidr_block = "0.0.0.0/0"
+ nat_gateway_id = aws_nat_gateway.main.id
}
}
diff --git a/infrastructure/modules/networking/tests/unit.tftest.hcl b/infrastructure/modules/networking/tests/unit.tftest.hcl
index 520aa57c48..333f960013 100644
--- a/infrastructure/modules/networking/tests/unit.tftest.hcl
+++ b/infrastructure/modules/networking/tests/unit.tftest.hcl
@@ -1,10 +1,17 @@
-mock_provider "aws" {}
+mock_provider "aws" {
+ override_during = plan
+
+ mock_resource "aws_nat_gateway" {
+ defaults = {
+ id = "nat-000000000000test"
+ }
+ }
+}
variables {
availability_zones = ["us-east-2a", "us-east-2b", "us-east-2c"]
aws_region = "us-east-2"
common_tags = { Environment = "test", Project = "nest" }
- enable_nat_gateway = true
enable_vpc_cloudwatch_logs_endpoint = false
enable_vpc_ecr_api_endpoint = false
enable_vpc_ecr_dkr_endpoint = false
@@ -143,28 +150,11 @@ run "test_internet_gateway_name_format" {
}
}
-run "test_nat_eip_created_when_enabled" {
- command = plan
-
- variables {
- enable_nat_gateway = true
- }
-
- assert {
- condition = length(aws_eip.nat) == 1
- error_message = "NAT EIP must be created when enable_nat_gateway is true."
- }
-}
-
run "test_nat_eip_name_format" {
command = plan
- variables {
- enable_nat_gateway = true
- }
-
assert {
- condition = aws_eip.nat[0].tags["Name"] == "${var.project_name}-${var.environment}-nat-eip"
+ condition = aws_eip.nat.tags["Name"] == "${var.project_name}-${var.environment}-nat-eip"
error_message = "NAT EIP name must follow format: {project}-{environment}-nat-eip."
}
}
@@ -172,65 +162,27 @@ run "test_nat_eip_name_format" {
run "test_nat_eip_domain_is_vpc" {
command = plan
- variables {
- enable_nat_gateway = true
- }
-
assert {
- condition = aws_eip.nat[0].domain == "vpc"
+ condition = aws_eip.nat.domain == "vpc"
error_message = "NAT EIP domain must be VPC."
}
}
-run "test_nat_eip_not_created_when_disabled" {
- command = plan
-
- variables {
- enable_nat_gateway = false
- }
-
- assert {
- condition = length(aws_eip.nat) == 0
- error_message = "NAT EIP must not be created when enable_nat_gateway is false."
- }
-}
-
-run "test_nat_gateway_created_when_enabled" {
- command = plan
-
- variables {
- enable_nat_gateway = true
- }
-
- assert {
- condition = length(aws_nat_gateway.main) == 1
- error_message = "NAT Gateway must be created when enable_nat_gateway is true."
- }
-}
-
run "test_nat_gateway_name_format" {
command = plan
- variables {
- enable_nat_gateway = true
- }
-
assert {
- condition = aws_nat_gateway.main[0].tags["Name"] == "${var.project_name}-${var.environment}-nat"
+ condition = aws_nat_gateway.main.tags["Name"] == "${var.project_name}-${var.environment}-nat"
error_message = "NAT gateway name must follow format: {project}-{environment}-nat."
}
}
-run "test_nat_gateway_not_created_when_disabled" {
+run "test_private_route_targets_nat_gateway" {
command = plan
- variables {
- enable_nat_gateway = false
- }
-
assert {
- condition = length(aws_nat_gateway.main) == 0
- error_message = "NAT Gateway must not be created when enable_nat_gateway is false."
+ condition = one([for route in aws_route_table.private.route : route if route.cidr_block == "0.0.0.0/0"]).nat_gateway_id == aws_nat_gateway.main.id
+ error_message = "Private route table must route 0.0.0.0/0 through the NAT gateway."
}
}
diff --git a/infrastructure/modules/networking/variables.tf b/infrastructure/modules/networking/variables.tf
index 7d3856585f..c5bafb45e4 100644
--- a/infrastructure/modules/networking/variables.tf
+++ b/infrastructure/modules/networking/variables.tf
@@ -14,12 +14,6 @@ variable "common_tags" {
default = {}
}
-variable "enable_nat_gateway" {
- description = "Whether to enable a NAT Gateway."
- type = bool
- default = true
-}
-
variable "enable_vpc_cloudwatch_logs_endpoint" {
description = "Whether to create CloudWatch Logs VPC endpoint."
type = bool