diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 28bfba931b..1f3cc690df 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,6 +16,8 @@ repos: files: ^infrastructure/.*\.tf$ - id: terraform_tflint files: ^infrastructure/.*\.tf$ + args: + - --args=--config=__GIT_WORKING_DIR__/infrastructure/.tflint.hcl - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.14.6 diff --git a/infrastructure/.tflint.hcl b/infrastructure/.tflint.hcl new file mode 100644 index 0000000000..2045eb8722 --- /dev/null +++ b/infrastructure/.tflint.hcl @@ -0,0 +1,45 @@ +plugin "aws" { + enabled = true + version = "0.44.0" + source = "github.com/terraform-linters/tflint-ruleset-aws" +} + +plugin "terraform" { + enabled = true + version = "0.13.0" + source = "github.com/terraform-linters/tflint-ruleset-terraform" +} + +rule "aws_resource_missing_tags" { + enabled = false +} + +rule "terraform_documented_outputs" { + enabled = true +} + +rule "terraform_documented_variables" { + enabled = true +} + +rule "terraform_module_pinned_source" { + enabled = true + style = "semver" +} + +rule "terraform_naming_convention" { + enabled = true + format = "snake_case" +} + +rule "terraform_required_providers" { + enabled = true +} + +rule "terraform_required_version" { + enabled = true +} + +rule "terraform_typed_variables" { + enabled = true +} diff --git a/infrastructure/README.md b/infrastructure/README.md index 20f0ce6545..7707f4d4b6 100644 --- a/infrastructure/README.md +++ b/infrastructure/README.md @@ -17,73 +17,87 @@ Follow these steps to set up the infrastructure: 1. **Setup Backend (one-time setup)**: -- Navigate to the backend directory: - ```bash - cd infrastructure/backend/ - ``` + - Navigate to the backend directory: -**Note:** Optionally change the region: set `aws_region` in a `.tfvars` file. + ```bash + cd infrastructure/backend/ + ``` -- Initialize Terraform if needed: - ```bash - terraform init - ``` + > [!NOTE] + > Optionally change the region: set `aws_region` in a `.tfvars` file. -- Apply the changes to create the backend resources: - ```bash - terraform apply - ``` + - Initialize Terraform if needed: + + ```bash + terraform init + ``` + + - Apply the changes to create the backend resources: + + ```bash + terraform apply + ``` -**Note:** Copy the state bucket name from the output. + > [!NOTE] + > Copy the state bucket name from the output. -**Note:** It is recommended to not destroy the backend resources unless absolutely necessary. + > [!NOTE] + > It is recommended to not destroy the backend resources unless absolutely necessary. 2. **Setup Main Infrastructure (staging)**: -- Navigate to the main infrastructure directory. If you are in `infrastructure/backend`, you can use: - ```bash - cd ../staging/ - ``` + - Navigate to the main infrastructure directory. If you are in `infrastructure/backend`, you can use: -- Create a local variables file: - ```bash - touch terraform.tfvars - ``` + ```bash + cd ../staging/ + ``` -- Copy the contents from the example file: - ```bash - cat terraform.tfvars.example > terraform.tfvars - ``` + - Create a local variables file: -- Create a local backend configuration file: - ```bash - touch terraform.tfbackend - ``` + ```bash + touch terraform.tfvars + ``` -- Copy the contents from the example file: - ```bash - cat terraform.tfbackend.example > terraform.tfbackend - ``` + - Copy the contents from the example file: -*Note:* Update the state bucket name in `terraform.tfbackend` with the name of the state bucket created in the previous step. + ```bash + cat terraform.tfvars.example > terraform.tfvars + ``` -*Note:* Update defaults (e.g. `region`) as needed. + - Create a local backend configuration file: -- Initialize Terraform with the backend configuration: - ```bash - terraform init -backend-config=terraform.tfbackend - ``` + ```bash + touch terraform.tfbackend + ``` -- Apply the changes to create the main infrastructure using the command: - ```bash - terraform apply - ``` + - Copy the contents from the example file: -3. **Populate Secrets** + ```bash + cat terraform.tfbackend.example > terraform.tfbackend + ``` - - Visit the AWS Console > Systems Manager > Parameter Store. - - Populate all `DJANGO_*` secrets that have `to-be-set-in-aws-console` value. + > [!NOTE] + > Update the state bucket name in `terraform.tfbackend` with the name of the state bucket created in the previous step. + > [!NOTE] + > Update defaults (e.g. `region`) as needed. + + - Initialize Terraform with the backend configuration: + + ```bash + terraform init -backend-config=terraform.tfbackend + ``` + + - Apply the changes to create the main infrastructure using the command: + + ```bash + terraform apply + ``` + +3. **Populate Secrets** + + - Visit the AWS Console > Systems Manager > Parameter Store. + - Populate all `DJANGO_*` secrets that have `to-be-set-in-aws-console` value. ## Setting up Zappa @@ -91,111 +105,121 @@ The Django backend deployment is managed by Zappa. This includes the API Gateway 1. **Change Directory**: - - Change the directory to `backend/` using the following command: + - Change the directory to `backend/` using the following command: - ```bash - cd ../../backend/ - ``` + ```bash + cd ../../backend/ + ``` - *Note*: The following steps assume the current working directory is `backend/` + > [!NOTE] + > The following steps assume the current working directory is `backend/` 2. **Setup Dependencies**: - - This step may differ for different operating systems. - - The goal is to install dependencies listed in `pyproject.toml`. - - Steps for Linux: + - This step may differ for different operating systems. + - The goal is to install dependencies listed in `pyproject.toml`. + - Steps for Linux: - ```bash - poetry install && eval $(poetry env activate) - ``` + ```bash + poetry install && eval $(poetry env activate) + ``` 3. **Create Zappa Settings File**: -- Create a local Zappa settings file in the `backend` directory: + - Create a local Zappa settings file in the `backend` directory: - ```bash - touch zappa_settings.json - ``` + ```bash + touch zappa_settings.json + ``` -- Copy the contents from the template file into your new local environment file: + - Copy the contents from the template file into your new local environment file: - ```bash - cat zappa_settings.example.json > zappa_settings.json - ``` + ```bash + cat zappa_settings.example.json > zappa_settings.json + ``` 4. **Populate Settings File**: -- Replace all `${...}` variables in `zappa_settings.json` with appropriate output variables. + - Replace all `${...}` variables in `zappa_settings.json` with appropriate output variables. 5. **Deploy**: - - **Note**: Make sure to populate all `DJANGO_*` secrets that are set as `to-be-set-in-aws-console` - in the Parameter Store. The deployment might fail with no logs if secrets such as - `DJANGO_SLACK_BOT_TOKEN` are invalid. + > [!NOTE] + > Make sure to populate all `DJANGO_*` secrets that are set as `to-be-set-in-aws-console` in the Parameter Store. The deployment might fail with no logs if secrets such as `DJANGO_SLACK_BOT_TOKEN` are invalid. - ```bash - zappa deploy staging - ``` - - **Note**: If the deployment is successful but returns a `5xx` error, resolve the issues - and use `zappa undeploy staging` & `zappa deploy staging`. The command `zappa update staging` may not work. + ```bash + zappa deploy staging + ``` -Once deployed, use the URL provided by Zappa to test the API. + > [!NOTE] + > If the deployment is successful but returns a `5xx` error, resolve the issues and use `zappa undeploy staging` & `zappa deploy staging`. The command `zappa update staging` may not work. + + Once deployed, use the URL provided by Zappa to test the API. ## Setup Database Migrate and load data into the new database. 1. **Setup ECR Image**: - - Login to the Elastic Container Registry using the following command: - *Note*: replace `us-east-2` with configured region and `000000000000` with AWS Account ID. + - Login to the Elastic Container Registry using the following command: + + > [!NOTE] + > Replace `us-east-2` with configured region and `000000000000` with AWS Account ID. - *Warning*: Configure a credential helper instead of using following command to login. + > [!WARNING] + > Configure a credential helper instead of using following command to login. - ```bash - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin 000000000000.dkr.ecr.us-east-2.amazonaws.com - ``` + ```bash + aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin 000000000000.dkr.ecr.us-east-2.amazonaws.com + ``` + + - Build the backend image using the following command: + + ```bash + docker build -t owasp-nest-staging-backend:latest -f docker/Dockerfile . + ``` - - Build the backend image using the following command: + - Tag the image: - ```bash - docker build -t owasp-nest-staging-backend:latest -f docker/Dockerfile . - ``` + > [!NOTE] + > Replace `us-east-2` with configured region and `000000000000` with AWS Account ID. - - Tag the image: - *Note*: replace `us-east-2` with configured region and `000000000000` with AWS Account ID. + ```bash + docker tag owasp-nest-staging-backend:latest 000000000000.dkr.ecr.us-east-2.amazonaws.com/owasp-nest-staging-backend:latest + ``` - ```bash - docker tag owasp-nest-staging-backend:latest 000000000000.dkr.ecr.us-east-2.amazonaws.com/owasp-nest-staging-backend:latest - ``` + - Push the image: - - Push the image: - *Note*: replace `us-east-2` with configured region and `000000000000` with AWS Account ID. + > [!NOTE] + > Replace `us-east-2` with configured region and `000000000000` with AWS Account ID. - ```bash - docker push 000000000000.dkr.ecr.us-east-2.amazonaws.com/owasp-nest-staging-backend:latest - ``` + ```bash + docker push 000000000000.dkr.ecr.us-east-2.amazonaws.com/owasp-nest-staging-backend:latest + ``` 2. **Upload Fixture to S3**: - - Upload the fixture present in `backend/data` to `nest-fixtures` bucket using the following command: - ```bash - aws s3 cp data/nest.json.gz s3://owasp-nest-fixtures-/ - ``` + - Upload the fixture present in `backend/data` to `nest-fixtures` bucket using the following command: + + ```bash + aws s3 cp data/nest.json.gz s3://owasp-nest-fixtures-/ + ``` 3. **Run ECS Tasks**: - - Head over to Elastic Container Service in the AWS Console. - - Click on `owasp-nest-staging-migrate` in `Task Definitions` section. - - Select the task definition revision. - - Click Deploy > Run Task. - - Use the following configuration: - - Networking: - - VPC: owasp-nest-staging-vpc - - Subnets: subnets will be auto-selected due to VPC selection. - - Security group name: select the ECS security group (e.g. `owasp-nest-staging-ecs-sg`). - - Click "Create" - - The task is now running... Click on the task ID to view Logs, Status, etc. - - Follow the same steps for `owasp-nest-staging-load-data` and `owasp-nest-staging-index-data`. + + - Head over to Elastic Container Service in the AWS Console. + - Click on `owasp-nest-staging-migrate` in `Task Definitions` section. + - Select the task definition revision. + - Click Deploy > Run Task. + - Use the following configuration: + - Networking: + - VPC: owasp-nest-staging-vpc + - Subnets: subnets will be auto-selected due to VPC selection. + - Security group name: select the ECS security group (e.g. `owasp-nest-staging-ecs-sg`). + - Click "Create" + - The task is now running... Click on the task ID to view Logs, Status, etc. + - Follow the same steps for `owasp-nest-staging-load-data` and `owasp-nest-staging-index-data`. ## Cleaning Up @@ -207,7 +231,9 @@ Migrate and load data into the new database. - Ensure all buckets and ECR repositories are empty. -**Note:** Some resources have `prevent_destroy` set to `true`. Please set it to `false` before destruction. +> [!NOTE] +> Some resources have `prevent_destroy` set to `true`. Please set it to `false` before destruction. + - To destroy Terraform infrastructure: ```bash diff --git a/infrastructure/backend/main.tf b/infrastructure/backend/main.tf index b748cf0b64..43bbb7f7cc 100644 --- a/infrastructure/backend/main.tf +++ b/infrastructure/backend/main.tf @@ -12,6 +12,14 @@ terraform { } } +locals { + common_tags = { + Environment = "backend" + ManagedBy = "Terraform" + Project = var.project_name + } +} + data "aws_iam_policy_document" "logs" { statement { actions = ["s3:PutObject"] @@ -58,9 +66,9 @@ resource "aws_dynamodb_table" "state_lock" { name = "${var.project_name}-terraform-state-lock" billing_mode = "PAY_PER_REQUEST" hash_key = "LockID" - tags = { + tags = merge(local.common_tags, { Name = "${var.project_name}-terraform-state-lock" - } + }) attribute { name = "LockID" @@ -80,9 +88,9 @@ resource "aws_s3_bucket" "logs" { # NOSONAR lifecycle { prevent_destroy = true } - tags = { + tags = merge(local.common_tags, { Name = "${var.project_name}-terraform-state-logs" - } + }) } resource "aws_s3_bucket" "state" { # NOSONAR @@ -92,9 +100,9 @@ resource "aws_s3_bucket" "state" { # NOSONAR lifecycle { prevent_destroy = true } - tags = { + tags = merge(local.common_tags, { Name = "${var.project_name}-terraform-state" - } + }) } resource "aws_s3_bucket_lifecycle_configuration" "state" { diff --git a/infrastructure/backend/variables.tf b/infrastructure/backend/variables.tf index 43be2145a5..72789673c3 100644 --- a/infrastructure/backend/variables.tf +++ b/infrastructure/backend/variables.tf @@ -1,5 +1,5 @@ variable "abort_incomplete_multipart_upload_days" { - description = "Specifies the number of days after which an incomplete multipart upload is aborted." + description = "The number of days after which an incomplete multipart upload is aborted." type = number default = 7 } diff --git a/infrastructure/modules/cache/.terraform.lock.hcl b/infrastructure/modules/cache/.terraform.lock.hcl deleted file mode 100644 index e15fbddce1..0000000000 --- a/infrastructure/modules/cache/.terraform.lock.hcl +++ /dev/null @@ -1,45 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "6.17.0" - constraints = "~> 6.0" - hashes = [ - "h1:65zxvr7oxROr5hqTWQtoS5HsGOBwUko7douoc9Azptc=", - "zh:157063d66cd4b5fc650f20f56127e19c9da5d135f4231f9ca0c19a1c0bf6e29d", - "zh:2050dc03304b42204e6c58bbb1a2afd4feeac7db55d7c06be77c6b1e2ab46a0f", - "zh:2a7f7751eef636ca064700cc4574b9b54a2596d9e2e86b91c45127410d9724c6", - "zh:335fd7bb44bebfc4dd1db1c013947e1dde2518c6f2d846aac13b7314414ce461", - "zh:545c248d2eb601a7b45a34313096cae0a5201ccf31e7fd99428357ef800051e0", - "zh:57d19883a6367c245e885856a1c5395c4c743c20feff631ea4ec7b5e16826281", - "zh:66d4f080b8c268d65e8c4758ed57234e5a19deff6073ffc3753b9a4cc177b54e", - "zh:6ad50de35970f15e1ed41d39742290c1be80600b7df3a9fbb4c02f353b9586cf", - "zh:7af42fa531e4dcb3ddb09f71ca988e90626abbf56a45981c2a6c01d0b364a51b", - "zh:9a6a535a879314a9137ec9d3e858b7c490a962050845cf62620ba2bf4ae916a8", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:ca213e0262c8f686fcd40e3fc84d67b8eea1596de988c13d4a8ecd4522ede669", - "zh:cc4132f682e9bf17c0649928ad92af4da07ffe7bccfe615d955225cdcf9e7f09", - "zh:dfe6de43496d2e2b6dff131fef6ada1e15f1fbba3d47235c751564d22003d05e", - "zh:e37d035fa02693a3d47fe636076cce50b6579b6adc0a36a7cf0456a2331c99ec", - ] -} - -provider "registry.terraform.io/hashicorp/random" { - version = "3.7.2" - constraints = "~> 3.0" - hashes = [ - "h1:356j/3XnXEKr9nyicLUufzoF4Yr6hRy481KIxRVpK0c=", - "zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f", - "zh:1527fb07d9fea400d70e9e6eb4a2b918d5060d604749b6f1c361518e7da546dc", - "zh:1e86bcd7ebec85ba336b423ba1db046aeaa3c0e5f921039b3f1a6fc2f978feab", - "zh:24536dec8bde66753f4b4030b8f3ef43c196d69cccbea1c382d01b222478c7a3", - "zh:29f1786486759fad9b0ce4fdfbbfece9343ad47cd50119045075e05afe49d212", - "zh:4d701e978c2dd8604ba1ce962b047607701e65c078cb22e97171513e9e57491f", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7b8434212eef0f8c83f5a90c6d76feaf850f6502b61b53c329e85b3b281cba34", - "zh:ac8a23c212258b7976e1621275e3af7099e7e4a3d4478cf8d5d2a27f3bc3e967", - "zh:b516ca74431f3df4c6cf90ddcdb4042c626e026317a33c53f0b445a3d93b720d", - "zh:dc76e4326aec2490c1600d6871a95e78f9050f9ce427c71707ea412a2f2f1a62", - "zh:eac7b63e86c749c7d48f527671c7aee5b4e26c10be6ad7232d6860167f99dbb0", - ] -} diff --git a/infrastructure/modules/cache/main.tf b/infrastructure/modules/cache/main.tf index d9d96c334f..2b69012077 100644 --- a/infrastructure/modules/cache/main.tf +++ b/infrastructure/modules/cache/main.tf @@ -1,14 +1,14 @@ terraform { - required_version = ">= 1.0" + required_version = "1.14.0" required_providers { aws = { source = "hashicorp/aws" - version = "~> 6.0" + version = "6.22.0" } random = { source = "hashicorp/random" - version = "~> 3.0" + version = "3.7.2" } } } @@ -82,3 +82,11 @@ resource "aws_elasticache_replication_group" "main" { Name = "${var.project_name}-${var.environment}-redis" }) } + +resource "aws_ssm_parameter" "django_redis_password" { + description = "The password of Redis cache (Required by Django)." + name = "/${var.project_name}/${var.environment}/DJANGO_REDIS_PASSWORD" + tags = var.common_tags + type = "SecureString" + value = local.redis_auth_token +} diff --git a/infrastructure/modules/cache/outputs.tf b/infrastructure/modules/cache/outputs.tf index f1582444ff..5c95bfaff5 100644 --- a/infrastructure/modules/cache/outputs.tf +++ b/infrastructure/modules/cache/outputs.tf @@ -1,10 +1,9 @@ -output "redis_auth_token" { - description = "The auth token for Redis" - value = random_password.redis_auth_token[0].result - sensitive = true +output "redis_password_arn" { + description = "The SSM Parameter ARN of password of Redis." + value = aws_ssm_parameter.django_redis_password.arn } output "redis_primary_endpoint" { - description = "The primary endpoint of the Redis replication group" + description = "The primary endpoint of the Redis replication group." value = aws_elasticache_replication_group.main.primary_endpoint_address } diff --git a/infrastructure/modules/cache/variables.tf b/infrastructure/modules/cache/variables.tf index ebf3f897bb..fe13005897 100644 --- a/infrastructure/modules/cache/variables.tf +++ b/infrastructure/modules/cache/variables.tf @@ -1,5 +1,5 @@ variable "auto_minor_version_upgrade" { - description = "Determines whether minor engine upgrades will be applied automatically." + description = "Whether minor engine upgrades will be applied automatically." type = bool default = true } @@ -11,7 +11,7 @@ variable "common_tags" { } variable "environment" { - description = "The environment (e.g., staging, production)" + description = "The environment (e.g., staging, production)." type = string } @@ -28,32 +28,32 @@ variable "maintenance_window" { } variable "project_name" { - description = "The name of the project" + description = "The name of the project." type = string } variable "redis_engine_version" { - description = "The version of the Redis engine" + description = "The version of the Redis engine." type = string } variable "redis_node_type" { - description = "The node type for the Redis cache" + description = "The node type for the Redis cache." type = string } variable "redis_num_cache_nodes" { - description = "The number of cache nodes in the Redis cluster" + description = "The number of cache nodes in the Redis cluster." type = number } variable "redis_port" { - description = "The port for the Redis cache" + description = "The port for the Redis cache." type = number } variable "security_group_ids" { - description = "A list of security group IDs to associate with the Redis cache" + description = "A list of security group IDs to associate with the Redis cache." type = list(string) } @@ -70,6 +70,6 @@ variable "snapshot_window" { } variable "subnet_ids" { - description = "A list of subnet IDs for the cache subnet group" + description = "A list of subnet IDs for the cache subnet group." type = list(string) } diff --git a/infrastructure/modules/database/.terraform.lock.hcl b/infrastructure/modules/database/.terraform.lock.hcl deleted file mode 100644 index e15fbddce1..0000000000 --- a/infrastructure/modules/database/.terraform.lock.hcl +++ /dev/null @@ -1,45 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "6.17.0" - constraints = "~> 6.0" - hashes = [ - "h1:65zxvr7oxROr5hqTWQtoS5HsGOBwUko7douoc9Azptc=", - "zh:157063d66cd4b5fc650f20f56127e19c9da5d135f4231f9ca0c19a1c0bf6e29d", - "zh:2050dc03304b42204e6c58bbb1a2afd4feeac7db55d7c06be77c6b1e2ab46a0f", - "zh:2a7f7751eef636ca064700cc4574b9b54a2596d9e2e86b91c45127410d9724c6", - "zh:335fd7bb44bebfc4dd1db1c013947e1dde2518c6f2d846aac13b7314414ce461", - "zh:545c248d2eb601a7b45a34313096cae0a5201ccf31e7fd99428357ef800051e0", - "zh:57d19883a6367c245e885856a1c5395c4c743c20feff631ea4ec7b5e16826281", - "zh:66d4f080b8c268d65e8c4758ed57234e5a19deff6073ffc3753b9a4cc177b54e", - "zh:6ad50de35970f15e1ed41d39742290c1be80600b7df3a9fbb4c02f353b9586cf", - "zh:7af42fa531e4dcb3ddb09f71ca988e90626abbf56a45981c2a6c01d0b364a51b", - "zh:9a6a535a879314a9137ec9d3e858b7c490a962050845cf62620ba2bf4ae916a8", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:ca213e0262c8f686fcd40e3fc84d67b8eea1596de988c13d4a8ecd4522ede669", - "zh:cc4132f682e9bf17c0649928ad92af4da07ffe7bccfe615d955225cdcf9e7f09", - "zh:dfe6de43496d2e2b6dff131fef6ada1e15f1fbba3d47235c751564d22003d05e", - "zh:e37d035fa02693a3d47fe636076cce50b6579b6adc0a36a7cf0456a2331c99ec", - ] -} - -provider "registry.terraform.io/hashicorp/random" { - version = "3.7.2" - constraints = "~> 3.0" - hashes = [ - "h1:356j/3XnXEKr9nyicLUufzoF4Yr6hRy481KIxRVpK0c=", - "zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f", - "zh:1527fb07d9fea400d70e9e6eb4a2b918d5060d604749b6f1c361518e7da546dc", - "zh:1e86bcd7ebec85ba336b423ba1db046aeaa3c0e5f921039b3f1a6fc2f978feab", - "zh:24536dec8bde66753f4b4030b8f3ef43c196d69cccbea1c382d01b222478c7a3", - "zh:29f1786486759fad9b0ce4fdfbbfece9343ad47cd50119045075e05afe49d212", - "zh:4d701e978c2dd8604ba1ce962b047607701e65c078cb22e97171513e9e57491f", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7b8434212eef0f8c83f5a90c6d76feaf850f6502b61b53c329e85b3b281cba34", - "zh:ac8a23c212258b7976e1621275e3af7099e7e4a3d4478cf8d5d2a27f3bc3e967", - "zh:b516ca74431f3df4c6cf90ddcdb4042c626e026317a33c53f0b445a3d93b720d", - "zh:dc76e4326aec2490c1600d6871a95e78f9050f9ce427c71707ea412a2f2f1a62", - "zh:eac7b63e86c749c7d48f527671c7aee5b4e26c10be6ad7232d6860167f99dbb0", - ] -} diff --git a/infrastructure/modules/database/main.tf b/infrastructure/modules/database/main.tf index e0fe59271b..338fcecd6b 100644 --- a/infrastructure/modules/database/main.tf +++ b/infrastructure/modules/database/main.tf @@ -1,14 +1,14 @@ terraform { - required_version = ">= 1.0" + required_version = "1.14.0" required_providers { aws = { source = "hashicorp/aws" - version = "~> 6.0" + version = "6.22.0" } random = { source = "hashicorp/random" - version = "~> 3.0" + version = "3.7.2" } } } @@ -61,7 +61,7 @@ resource "aws_db_instance" "main" { } resource "aws_secretsmanager_secret" "db_credentials" { - description = "Stores the credentials for the RDS database." + description = "Stores the credentials for the RDS database" name = "${var.project_name}-${var.environment}-db-credentials" recovery_window_in_days = var.secret_recovery_window_in_days tags = merge(var.common_tags, { @@ -77,6 +77,14 @@ resource "aws_secretsmanager_secret_version" "db_credentials" { }) } +resource "aws_ssm_parameter" "django_db_password" { + description = "Database password generated by Terraform (Required by Django)." + name = "/${var.project_name}/${var.environment}/DJANGO_DB_PASSWORD" + tags = var.common_tags + type = "SecureString" + value = local.db_password +} + resource "aws_iam_role" "rds_proxy" { count = var.create_rds_proxy ? 1 : 0 diff --git a/infrastructure/modules/database/outputs.tf b/infrastructure/modules/database/outputs.tf index 94960bf951..67aea9ba7c 100644 --- a/infrastructure/modules/database/outputs.tf +++ b/infrastructure/modules/database/outputs.tf @@ -1,10 +1,9 @@ -output "db_password" { - description = "The password for the RDS database" - value = local.db_password - sensitive = true +output "db_password_arn" { + description = "The SSM Parameter ARN of password of the RDS database." + value = aws_ssm_parameter.django_db_password.arn } output "db_proxy_endpoint" { - description = "The endpoint of the RDS proxy" + description = "The endpoint of the RDS proxy." value = var.create_rds_proxy ? aws_db_proxy.main[0].endpoint : aws_db_instance.main.address } diff --git a/infrastructure/modules/database/variables.tf b/infrastructure/modules/database/variables.tf index bfe5c98f77..d57e7f61ff 100644 --- a/infrastructure/modules/database/variables.tf +++ b/infrastructure/modules/database/variables.tf @@ -5,18 +5,18 @@ variable "common_tags" { } variable "create_rds_proxy" { - description = "Whether to create an RDS proxy" + description = "Whether to create an RDS proxy." type = bool default = false } variable "db_allocated_storage" { - description = "The allocated storage for the RDS database in GB" + description = "The allocated storage for the RDS database in GB." type = number } variable "db_backup_retention_period" { - description = "The number of days to retain backups for" + description = "The number of days to retain backups for." type = number default = 7 } @@ -28,7 +28,7 @@ variable "db_backup_window" { } variable "db_copy_tags_to_snapshot" { - description = "Specifies whether to copy all instance tags to snapshots." + description = "Whether to copy all instance tags to snapshots." type = bool default = true } @@ -46,12 +46,12 @@ variable "db_enabled_cloudwatch_logs_exports" { } variable "db_engine_version" { - description = "The version of the PostgreSQL engine" + description = "The version of the PostgreSQL engine." type = string } variable "db_instance_class" { - description = "The instance class for the RDS database" + description = "The instance class for the RDS database." type = string } @@ -62,51 +62,51 @@ variable "db_maintenance_window" { } variable "db_name" { - description = "The name of the RDS database" + description = "The name of the RDS database." type = string } variable "db_password" { - description = "The password for the RDS database" + description = "The password for the RDS database." type = string sensitive = true default = null } variable "db_skip_final_snapshot" { - description = "Determines whether a final DB snapshot is created before the DB instance is deleted." + description = "Whether a final DB snapshot is created before the DB instance is deleted." type = bool default = false } variable "db_storage_type" { - description = "The storage type for the RDS database" + description = "The storage type for the RDS database." type = string default = "gp3" } variable "db_subnet_ids" { - description = "A list of subnet IDs for the DB subnet group" + description = "A list of subnet IDs for the DB subnet group." type = list(string) } variable "db_user" { - description = "The username for the RDS database" + description = "The username for the RDS database." type = string } variable "environment" { - description = "The environment (e.g., staging, production)" + description = "The environment (e.g., staging, production)." type = string } variable "project_name" { - description = "The name of the project" + description = "The name of the project." type = string } variable "proxy_security_group_ids" { - description = "A list of security group IDs to associate with the RDS proxy" + description = "A list of security group IDs to associate with the RDS proxy." type = list(string) } @@ -117,6 +117,6 @@ variable "secret_recovery_window_in_days" { } variable "security_group_ids" { - description = "A list of security group IDs to associate with the RDS database" + description = "A list of security group IDs to associate with the RDS database." type = list(string) } diff --git a/infrastructure/modules/ecs/.terraform.lock.hcl b/infrastructure/modules/ecs/.terraform.lock.hcl deleted file mode 100644 index 2efdd35b34..0000000000 --- a/infrastructure/modules/ecs/.terraform.lock.hcl +++ /dev/null @@ -1,25 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "6.17.0" - constraints = "~> 6.0" - hashes = [ - "h1:65zxvr7oxROr5hqTWQtoS5HsGOBwUko7douoc9Azptc=", - "zh:157063d66cd4b5fc650f20f56127e19c9da5d135f4231f9ca0c19a1c0bf6e29d", - "zh:2050dc03304b42204e6c58bbb1a2afd4feeac7db55d7c06be77c6b1e2ab46a0f", - "zh:2a7f7751eef636ca064700cc4574b9b54a2596d9e2e86b91c45127410d9724c6", - "zh:335fd7bb44bebfc4dd1db1c013947e1dde2518c6f2d846aac13b7314414ce461", - "zh:545c248d2eb601a7b45a34313096cae0a5201ccf31e7fd99428357ef800051e0", - "zh:57d19883a6367c245e885856a1c5395c4c743c20feff631ea4ec7b5e16826281", - "zh:66d4f080b8c268d65e8c4758ed57234e5a19deff6073ffc3753b9a4cc177b54e", - "zh:6ad50de35970f15e1ed41d39742290c1be80600b7df3a9fbb4c02f353b9586cf", - "zh:7af42fa531e4dcb3ddb09f71ca988e90626abbf56a45981c2a6c01d0b364a51b", - "zh:9a6a535a879314a9137ec9d3e858b7c490a962050845cf62620ba2bf4ae916a8", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:ca213e0262c8f686fcd40e3fc84d67b8eea1596de988c13d4a8ecd4522ede669", - "zh:cc4132f682e9bf17c0649928ad92af4da07ffe7bccfe615d955225cdcf9e7f09", - "zh:dfe6de43496d2e2b6dff131fef6ada1e15f1fbba3d47235c751564d22003d05e", - "zh:e37d035fa02693a3d47fe636076cce50b6579b6adc0a36a7cf0456a2331c99ec", - ] -} diff --git a/infrastructure/modules/ecs/main.tf b/infrastructure/modules/ecs/main.tf index add84fdb61..f896366f7e 100644 --- a/infrastructure/modules/ecs/main.tf +++ b/infrastructure/modules/ecs/main.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = "1.14.0" required_providers { aws = { source = "hashicorp/aws" - version = "~> 6.0" + version = "6.22.0" } } } @@ -80,6 +80,7 @@ resource "aws_iam_policy" "ecs_tasks_execution_role_ssm_policy" { } ] }) + tags = var.common_tags } resource "aws_iam_policy" "ecs_tasks_execution_policy" { @@ -115,6 +116,7 @@ resource "aws_iam_policy" "ecs_tasks_execution_policy" { } ] }) + tags = var.common_tags } resource "aws_iam_role_policy_attachment" "ecs_tasks_execution_policy_attachment" { @@ -195,6 +197,7 @@ resource "aws_iam_policy" "event_bridge_ecs_policy" { } ] }) + tags = var.common_tags } resource "aws_iam_role_policy_attachment" "event_bridge_policy_attachment" { diff --git a/infrastructure/modules/ecs/modules/task/.terraform.lock.hcl b/infrastructure/modules/ecs/modules/task/.terraform.lock.hcl deleted file mode 100644 index 2efdd35b34..0000000000 --- a/infrastructure/modules/ecs/modules/task/.terraform.lock.hcl +++ /dev/null @@ -1,25 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "6.17.0" - constraints = "~> 6.0" - hashes = [ - "h1:65zxvr7oxROr5hqTWQtoS5HsGOBwUko7douoc9Azptc=", - "zh:157063d66cd4b5fc650f20f56127e19c9da5d135f4231f9ca0c19a1c0bf6e29d", - "zh:2050dc03304b42204e6c58bbb1a2afd4feeac7db55d7c06be77c6b1e2ab46a0f", - "zh:2a7f7751eef636ca064700cc4574b9b54a2596d9e2e86b91c45127410d9724c6", - "zh:335fd7bb44bebfc4dd1db1c013947e1dde2518c6f2d846aac13b7314414ce461", - "zh:545c248d2eb601a7b45a34313096cae0a5201ccf31e7fd99428357ef800051e0", - "zh:57d19883a6367c245e885856a1c5395c4c743c20feff631ea4ec7b5e16826281", - "zh:66d4f080b8c268d65e8c4758ed57234e5a19deff6073ffc3753b9a4cc177b54e", - "zh:6ad50de35970f15e1ed41d39742290c1be80600b7df3a9fbb4c02f353b9586cf", - "zh:7af42fa531e4dcb3ddb09f71ca988e90626abbf56a45981c2a6c01d0b364a51b", - "zh:9a6a535a879314a9137ec9d3e858b7c490a962050845cf62620ba2bf4ae916a8", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:ca213e0262c8f686fcd40e3fc84d67b8eea1596de988c13d4a8ecd4522ede669", - "zh:cc4132f682e9bf17c0649928ad92af4da07ffe7bccfe615d955225cdcf9e7f09", - "zh:dfe6de43496d2e2b6dff131fef6ada1e15f1fbba3d47235c751564d22003d05e", - "zh:e37d035fa02693a3d47fe636076cce50b6579b6adc0a36a7cf0456a2331c99ec", - ] -} diff --git a/infrastructure/modules/ecs/modules/task/main.tf b/infrastructure/modules/ecs/modules/task/main.tf index fa7aa9c450..6f71792290 100644 --- a/infrastructure/modules/ecs/modules/task/main.tf +++ b/infrastructure/modules/ecs/modules/task/main.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = "1.14.0" required_providers { aws = { source = "hashicorp/aws" - version = "~> 6.0" + version = "6.22.0" } } } diff --git a/infrastructure/modules/ecs/modules/task/outputs.tf b/infrastructure/modules/ecs/modules/task/outputs.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/infrastructure/modules/ecs/outputs.tf b/infrastructure/modules/ecs/outputs.tf index acb7cd7fdc..849a9b5e52 100644 --- a/infrastructure/modules/ecs/outputs.tf +++ b/infrastructure/modules/ecs/outputs.tf @@ -1,9 +1,9 @@ output "ecs_cluster_arn" { - description = "The ARN of the ECS cluster" + description = "The ARN of the ECS cluster." value = aws_ecs_cluster.main.arn } output "ecr_repository_url" { - description = "The URL of the ECR repository" + description = "The URL of the ECR repository." value = aws_ecr_repository.main.repository_url } diff --git a/infrastructure/modules/ecs/variables.tf b/infrastructure/modules/ecs/variables.tf index 0ca06160e3..12530eb1b8 100644 --- a/infrastructure/modules/ecs/variables.tf +++ b/infrastructure/modules/ecs/variables.tf @@ -1,5 +1,5 @@ variable "aws_region" { - description = "The AWS region" + description = "The AWS region." type = string } @@ -16,109 +16,109 @@ variable "container_parameters_arns" { } variable "ecs_sg_id" { - description = "The ID of the security group for the ECS tasks" + description = "The ID of the security group for the ECS tasks." type = string } variable "environment" { - description = "The environment (e.g., staging, production)" + description = "The environment (e.g., staging, production)." type = string } variable "fixtures_read_only_policy_arn" { - description = "The ARN of the fixtures read-only IAM policy" + description = "The ARN of the fixtures read-only IAM policy." type = string } variable "fixtures_bucket_name" { - description = "The name of the S3 bucket for fixtures" + description = "The name of the S3 bucket for fixtures." type = string } variable "image_tag" { - description = "The Docker image tag to use for ECS tasks" + description = "The Docker image tag to use for ECS tasks." type = string default = "latest" } variable "index_data_task_cpu" { - description = "The CPU for the index-data task" + description = "The CPU for the index-data task." type = string default = "256" } variable "index_data_task_memory" { - description = "The memory for the index-data task" + description = "The memory for the index-data task." type = string default = "2048" } variable "load_data_task_cpu" { - description = "The CPU for the load-data task" + description = "The CPU for the load-data task." type = string default = "512" } variable "load_data_task_memory" { - description = "The memory for the load-data task" + description = "The memory for the load-data task." type = string default = "4096" } variable "migrate_task_cpu" { - description = "The CPU for the migrate task" + description = "The CPU for the migrate task." type = string default = "256" } variable "migrate_task_memory" { - description = "The memory for the migrate task" + description = "The memory for the migrate task." type = string default = "1024" } variable "private_subnet_ids" { - description = "A list of private subnet IDs" + description = "A list of private subnet IDs." type = list(string) } variable "project_name" { - description = "The name of the project" + description = "The name of the project." type = string } variable "sync_data_task_cpu" { - description = "The CPU for the sync-data task" + description = "The CPU for the sync-data task." type = string default = "256" } variable "sync_data_task_memory" { - description = "The memory for the sync-data task" + description = "The memory for the sync-data task." type = string default = "1024" } variable "update_project_health_metrics_task_cpu" { - description = "The CPU for the update-project-health-metrics task" + description = "The CPU for the update-project-health-metrics task." type = string default = "256" } variable "update_project_health_metrics_task_memory" { - description = "The memory for the update-project-health-metrics task" + description = "The memory for the update-project-health-metrics task." type = string default = "1024" } variable "update_project_health_scores_task_cpu" { - description = "The CPU for the update-project-health-scores task" + description = "The CPU for the update-project-health-scores task." type = string default = "256" } variable "update_project_health_scores_task_memory" { - description = "The memory for the update-project-health-scores task" + description = "The memory for the update-project-health-scores task." type = string default = "1024" } diff --git a/infrastructure/modules/networking/modules/nacl/outputs.tf b/infrastructure/modules/networking/modules/nacl/outputs.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/infrastructure/modules/networking/modules/nacl/variables.tf b/infrastructure/modules/networking/modules/nacl/variables.tf index de606def10..8709cb2376 100644 --- a/infrastructure/modules/networking/modules/nacl/variables.tf +++ b/infrastructure/modules/networking/modules/nacl/variables.tf @@ -1,34 +1,34 @@ variable "common_tags" { - description = "Common tags to apply to all resources" + description = "A map of common tags to apply to all resources." type = map(string) } variable "environment" { - description = "Environment name" + description = "The environment (e.g., staging, production)." type = string } variable "private_subnet_ids" { - description = "List of private subnet IDs" + description = "A list of private subnet IDs." type = list(string) } variable "project_name" { - description = "Project name" + description = "The name of the project." type = string } variable "public_subnet_ids" { - description = "List of public subnet IDs" + description = "A list of public subnet IDs." type = list(string) } variable "vpc_cidr" { - description = "VPC CIDR block" + description = "The CIDR block for the VPC." type = string } variable "vpc_id" { - description = "VPC ID" + description = "The ID of the VPC." type = string } diff --git a/infrastructure/modules/networking/modules/vpc-endpoint/outputs.tf b/infrastructure/modules/networking/modules/vpc-endpoint/outputs.tf index c33d9b1626..fc9d266fc5 100644 --- a/infrastructure/modules/networking/modules/vpc-endpoint/outputs.tf +++ b/infrastructure/modules/networking/modules/vpc-endpoint/outputs.tf @@ -1,4 +1,4 @@ output "security_group_id" { - description = "Security group ID for VPC endpoints" + description = "Security group ID for VPC endpoints." value = aws_security_group.vpc_endpoints.id } diff --git a/infrastructure/modules/networking/modules/vpc-endpoint/variables.tf b/infrastructure/modules/networking/modules/vpc-endpoint/variables.tf index 22607624f6..3c567b18c0 100644 --- a/infrastructure/modules/networking/modules/vpc-endpoint/variables.tf +++ b/infrastructure/modules/networking/modules/vpc-endpoint/variables.tf @@ -1,44 +1,44 @@ variable "aws_region" { - description = "AWS region" + description = "The AWS region." type = string } variable "common_tags" { - description = "Common tags to apply to all resources" + description = "A map of common tags to apply to all resources." type = map(string) } variable "environment" { - description = "Environment name" + description = "The environment (e.g., staging, production)." type = string } variable "private_route_table_id" { - description = "Private route table ID" + description = "The ID of the private route table." type = string } variable "private_subnet_ids" { - description = "List of private subnet IDs" + description = "A list of private subnet IDs." type = list(string) } variable "project_name" { - description = "Project name" + description = "The name of the project." type = string } variable "public_route_table_id" { - description = "Public route table ID" + description = "The ID of the public route table." type = string } variable "vpc_cidr" { - description = "VPC CIDR block" + description = "The CIDR block for the VPC." type = string } variable "vpc_id" { - description = "VPC ID" + description = "The ID of the VPC." type = string } diff --git a/infrastructure/modules/networking/outputs.tf b/infrastructure/modules/networking/outputs.tf index f748588f70..30d22bef66 100644 --- a/infrastructure/modules/networking/outputs.tf +++ b/infrastructure/modules/networking/outputs.tf @@ -1,19 +1,19 @@ output "vpc_id" { - description = "The ID of the VPC" + description = "The ID of the VPC." value = aws_vpc.main.id } output "public_subnet_ids" { - description = "A list of public subnet IDs" + description = "A list of public subnet IDs." value = aws_subnet.public[*].id } output "private_subnet_ids" { - description = "A list of private subnet IDs" + description = "A list of private subnet IDs." value = aws_subnet.private[*].id } output "vpc_endpoint_security_group_id" { - description = "Security group ID for VPC endpoints" + description = "Security group ID for VPC endpoints." value = module.vpc_endpoint.security_group_id } diff --git a/infrastructure/modules/networking/variables.tf b/infrastructure/modules/networking/variables.tf index 06dae08bc8..30c74cb251 100644 --- a/infrastructure/modules/networking/variables.tf +++ b/infrastructure/modules/networking/variables.tf @@ -1,10 +1,10 @@ variable "aws_region" { - description = "The AWS region" + description = "The AWS region." type = string } variable "availability_zones" { - description = "A list of availability zones for the VPC" + description = "A list of availability zones for the VPC." type = list(string) } @@ -15,7 +15,7 @@ variable "common_tags" { } variable "environment" { - description = "The environment (e.g., staging, production)" + description = "The environment (e.g., staging, production)." type = string } @@ -26,21 +26,21 @@ variable "log_retention_in_days" { } variable "private_subnet_cidrs" { - description = "A list of CIDR blocks for the private subnets" + description = "A list of CIDR blocks for the private subnets." type = list(string) } variable "project_name" { - description = "The name of the project" + description = "The name of the project." type = string } variable "public_subnet_cidrs" { - description = "A list of CIDR blocks for the public subnets" + description = "A list of CIDR blocks for the public subnets." type = list(string) } variable "vpc_cidr" { - description = "The CIDR block for the VPC" + description = "The CIDR block for the VPC." type = string } diff --git a/infrastructure/modules/parameters/main.tf b/infrastructure/modules/parameters/main.tf index 9be0cd04dc..a741e19572 100644 --- a/infrastructure/modules/parameters/main.tf +++ b/infrastructure/modules/parameters/main.tf @@ -1,14 +1,14 @@ terraform { - required_version = ">= 1.0" + required_version = "1.14.0" required_providers { aws = { source = "hashicorp/aws" - version = "~> 6.0" + version = "6.22.0" } random = { source = "hashicorp/random" - version = "~> 3.5" + version = "3.7.2" } } } @@ -77,14 +77,6 @@ resource "aws_ssm_parameter" "django_db_name" { value = var.db_name } -resource "aws_ssm_parameter" "django_db_password" { - description = "Database password generated by Terraform." - name = "/${var.project_name}/${var.environment}/DJANGO_DB_PASSWORD" - tags = var.common_tags - type = "SecureString" - value = var.db_password -} - resource "aws_ssm_parameter" "django_db_port" { description = "The port of the database." name = "/${var.project_name}/${var.environment}/DJANGO_DB_PORT" @@ -121,14 +113,6 @@ resource "aws_ssm_parameter" "django_redis_host" { value = var.redis_host } -resource "aws_ssm_parameter" "django_redis_password" { - description = "The password of Redis cache." - name = "/${var.project_name}/${var.environment}/DJANGO_REDIS_PASSWORD" - tags = var.common_tags - type = "SecureString" - value = var.redis_password -} - resource "aws_ssm_parameter" "django_secret_key" { description = "Django Secret Key generated by Terraform." name = "/${var.project_name}/${var.environment}/DJANGO_SECRET_KEY" diff --git a/infrastructure/modules/parameters/outputs.tf b/infrastructure/modules/parameters/outputs.tf index 1333a95a5b..5f45f8d2eb 100644 --- a/infrastructure/modules/parameters/outputs.tf +++ b/infrastructure/modules/parameters/outputs.tf @@ -1,5 +1,5 @@ -output "ssm_parameter_arns" { - description = "Map of environment variable names to the ARNs of all SSM parameters." +output "django_ssm_parameter_arns" { + description = "Map of environment variable names to the ARNs of all SSM parameters (Required by Django)." value = { "DJANGO_ALGOLIA_APPLICATION_ID" = aws_ssm_parameter.django_algolia_application_id.arn "DJANGO_ALGOLIA_WRITE_API_KEY" = aws_ssm_parameter.django_algolia_write_api_key.arn @@ -7,12 +7,12 @@ output "ssm_parameter_arns" { "DJANGO_CONFIGURATION" = aws_ssm_parameter.django_configuration.arn "DJANGO_DB_HOST" = aws_ssm_parameter.django_db_host.arn "DJANGO_DB_NAME" = aws_ssm_parameter.django_db_name.arn - "DJANGO_DB_PASSWORD" = aws_ssm_parameter.django_db_password.arn + "DJANGO_DB_PASSWORD" = var.db_password_arn "DJANGO_DB_PORT" = aws_ssm_parameter.django_db_port.arn "DJANGO_DB_USER" = aws_ssm_parameter.django_db_user.arn "DJANGO_OPEN_AI_SECRET_KEY" = aws_ssm_parameter.django_open_ai_secret_key.arn "DJANGO_REDIS_HOST" = aws_ssm_parameter.django_redis_host.arn - "DJANGO_REDIS_PASSWORD" = aws_ssm_parameter.django_redis_password.arn + "DJANGO_REDIS_PASSWORD" = var.redis_password_arn "DJANGO_SECRET_KEY" = aws_ssm_parameter.django_secret_key.arn "DJANGO_SENTRY_DSN" = aws_ssm_parameter.django_sentry_dsn.arn "DJANGO_SETTINGS_MODULE" = aws_ssm_parameter.django_settings_module.arn diff --git a/infrastructure/modules/parameters/variables.tf b/infrastructure/modules/parameters/variables.tf index e27a6cb176..6d76403d11 100644 --- a/infrastructure/modules/parameters/variables.tf +++ b/infrastructure/modules/parameters/variables.tf @@ -26,8 +26,8 @@ variable "db_name" { type = string } -variable "db_password" { - description = "The password of the database." +variable "db_password_arn" { + description = "The SSM Parameter ARN of password of the database." type = string sensitive = true } @@ -57,8 +57,8 @@ variable "redis_host" { type = string } -variable "redis_password" { - description = "The password of the Redis cache." +variable "redis_password_arn" { + description = "The SSM Parameter ARN of password of the Redis cache." type = string sensitive = true } diff --git a/infrastructure/modules/security/main.tf b/infrastructure/modules/security/main.tf index 62b43ead05..52481d2f36 100644 --- a/infrastructure/modules/security/main.tf +++ b/infrastructure/modules/security/main.tf @@ -16,14 +16,6 @@ resource "aws_security_group" "ecs" { Name = "${var.project_name}-${var.environment}-ecs-sg" }) vpc_id = var.vpc_id - - egress { - cidr_blocks = var.default_egress_cidr_blocks - description = "Allow all outbound traffic" - from_port = 0 - protocol = "-1" - to_port = 0 - } } resource "aws_security_group" "lambda" { @@ -33,14 +25,6 @@ resource "aws_security_group" "lambda" { Name = "${var.project_name}-${var.environment}-lambda-sg" }) vpc_id = var.vpc_id - - egress { - cidr_blocks = var.default_egress_cidr_blocks - description = "Allow all outbound traffic" - from_port = 0 - protocol = "-1" - to_port = 0 - } } resource "aws_security_group" "rds" { @@ -50,14 +34,6 @@ resource "aws_security_group" "rds" { Name = "${var.project_name}-${var.environment}-rds-sg" }) vpc_id = var.vpc_id - - egress { - cidr_blocks = var.default_egress_cidr_blocks - description = "Allow all outbound traffic" - from_port = 0 - protocol = "-1" - to_port = 0 - } } resource "aws_security_group" "rds_proxy" { @@ -68,14 +44,6 @@ resource "aws_security_group" "rds_proxy" { Name = "${var.project_name}-${var.environment}-rds-proxy-sg" }) vpc_id = var.vpc_id - - egress { - cidr_blocks = var.default_egress_cidr_blocks - description = "Allow all outbound traffic" - from_port = 0 - protocol = "-1" - to_port = 0 - } } resource "aws_security_group" "redis" { @@ -85,22 +53,16 @@ resource "aws_security_group" "redis" { Name = "${var.project_name}-${var.environment}-redis-sg" }) vpc_id = var.vpc_id +} - egress { - cidr_blocks = var.default_egress_cidr_blocks - description = "Allow all outbound traffic" - from_port = 0 - protocol = "-1" - to_port = 0 - } - - ingress { - description = "Redis from Lambda" - from_port = var.redis_port - protocol = "tcp" - security_groups = [aws_security_group.lambda.id] - to_port = var.redis_port - } +resource "aws_security_group_rule" "ecs_egress_all" { + cidr_blocks = var.default_egress_cidr_blocks + description = "Allow all outbound traffic" + from_port = 0 + protocol = "-1" + security_group_id = aws_security_group.ecs.id + to_port = 0 + type = "egress" } resource "aws_security_group_rule" "ecs_to_vpc_endpoints" { @@ -113,6 +75,16 @@ resource "aws_security_group_rule" "ecs_to_vpc_endpoints" { type = "egress" } +resource "aws_security_group_rule" "lambda_egress_all" { + cidr_blocks = var.default_egress_cidr_blocks + description = "Allow all outbound traffic" + from_port = 0 + protocol = "-1" + security_group_id = aws_security_group.lambda.id + to_port = 0 + type = "egress" +} + resource "aws_security_group_rule" "lambda_to_vpc_endpoints" { description = "Allow HTTPS to VPC endpoints" from_port = 443 @@ -147,35 +119,46 @@ resource "aws_security_group_rule" "rds_from_lambda" { resource "aws_security_group_rule" "rds_from_proxy" { count = var.create_rds_proxy ? 1 : 0 - type = "ingress" description = "PostgreSQL from RDS Proxy" from_port = var.db_port - to_port = var.db_port protocol = "tcp" security_group_id = aws_security_group.rds.id source_security_group_id = aws_security_group.rds_proxy[0].id + to_port = var.db_port + type = "ingress" +} + +resource "aws_security_group_rule" "rds_proxy_to_rds" { + count = var.create_rds_proxy ? 1 : 0 + description = "Allow RDS Proxy to reach RDS database" + from_port = var.db_port + protocol = "tcp" + security_group_id = aws_security_group.rds_proxy[0].id + source_security_group_id = aws_security_group.rds.id + to_port = var.db_port + type = "egress" } resource "aws_security_group_rule" "rds_proxy_from_ecs" { count = var.create_rds_proxy ? 1 : 0 - type = "ingress" description = "PostgreSQL from ECS" from_port = var.db_port - to_port = var.db_port protocol = "tcp" security_group_id = aws_security_group.rds_proxy[0].id source_security_group_id = aws_security_group.ecs.id + to_port = var.db_port + type = "ingress" } resource "aws_security_group_rule" "rds_proxy_from_lambda" { count = var.create_rds_proxy ? 1 : 0 - type = "ingress" description = "PostgreSQL from Lambda" from_port = var.db_port - to_port = var.db_port protocol = "tcp" security_group_id = aws_security_group.rds_proxy[0].id source_security_group_id = aws_security_group.lambda.id + to_port = var.db_port + type = "ingress" } resource "aws_security_group_rule" "redis_from_ecs" { @@ -187,3 +170,13 @@ resource "aws_security_group_rule" "redis_from_ecs" { to_port = var.redis_port type = "ingress" } + +resource "aws_security_group_rule" "redis_from_lambda" { + description = "Redis from Lambda" + from_port = var.redis_port + protocol = "tcp" + security_group_id = aws_security_group.redis.id + source_security_group_id = aws_security_group.lambda.id + to_port = var.redis_port + type = "ingress" +} diff --git a/infrastructure/modules/security/outputs.tf b/infrastructure/modules/security/outputs.tf index fecfb5176b..4c6ba15afe 100644 --- a/infrastructure/modules/security/outputs.tf +++ b/infrastructure/modules/security/outputs.tf @@ -1,24 +1,24 @@ output "ecs_sg_id" { - description = "The ID of the ECS security group" + description = "The ID of the ECS security group." value = aws_security_group.ecs.id } output "lambda_sg_id" { - description = "The ID of the Lambda security group" + description = "The ID of the Lambda security group." value = aws_security_group.lambda.id } output "rds_proxy_sg_id" { - description = "The ID of the RDS proxy security group" + description = "The ID of the RDS proxy security group." value = var.create_rds_proxy ? aws_security_group.rds_proxy[0].id : null } output "rds_sg_id" { - description = "The ID of the RDS security group" + description = "The ID of the RDS security group." value = aws_security_group.rds.id } output "redis_sg_id" { - description = "The ID of the Redis security group" + description = "The ID of the Redis security group." value = aws_security_group.redis.id } diff --git a/infrastructure/modules/security/variables.tf b/infrastructure/modules/security/variables.tf index f889d43a37..725b7aa4f4 100644 --- a/infrastructure/modules/security/variables.tf +++ b/infrastructure/modules/security/variables.tf @@ -5,13 +5,13 @@ variable "common_tags" { } variable "create_rds_proxy" { - description = "Whether to create an RDS proxy" + description = "Whether to create an RDS proxy." type = bool default = false } variable "db_port" { - description = "The port for the RDS database" + description = "The port for the RDS database." type = number } @@ -22,26 +22,26 @@ variable "default_egress_cidr_blocks" { } variable "environment" { - description = "The environment (e.g., staging, production)" + description = "The environment (e.g., staging, production)." type = string } variable "project_name" { - description = "The name of the project" + description = "The name of the project." type = string } variable "redis_port" { - description = "The port for the Redis cache" + description = "The port for the Redis cache." type = number } variable "vpc_endpoint_sg_id" { - description = "Security group ID for VPC endpoints" + description = "Security group ID for VPC endpoints." type = string } variable "vpc_id" { - description = "The ID of the VPC" + description = "The ID of the VPC." type = string } diff --git a/infrastructure/modules/storage/.terraform.lock.hcl b/infrastructure/modules/storage/.terraform.lock.hcl deleted file mode 100644 index e15fbddce1..0000000000 --- a/infrastructure/modules/storage/.terraform.lock.hcl +++ /dev/null @@ -1,45 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "6.17.0" - constraints = "~> 6.0" - hashes = [ - "h1:65zxvr7oxROr5hqTWQtoS5HsGOBwUko7douoc9Azptc=", - "zh:157063d66cd4b5fc650f20f56127e19c9da5d135f4231f9ca0c19a1c0bf6e29d", - "zh:2050dc03304b42204e6c58bbb1a2afd4feeac7db55d7c06be77c6b1e2ab46a0f", - "zh:2a7f7751eef636ca064700cc4574b9b54a2596d9e2e86b91c45127410d9724c6", - "zh:335fd7bb44bebfc4dd1db1c013947e1dde2518c6f2d846aac13b7314414ce461", - "zh:545c248d2eb601a7b45a34313096cae0a5201ccf31e7fd99428357ef800051e0", - "zh:57d19883a6367c245e885856a1c5395c4c743c20feff631ea4ec7b5e16826281", - "zh:66d4f080b8c268d65e8c4758ed57234e5a19deff6073ffc3753b9a4cc177b54e", - "zh:6ad50de35970f15e1ed41d39742290c1be80600b7df3a9fbb4c02f353b9586cf", - "zh:7af42fa531e4dcb3ddb09f71ca988e90626abbf56a45981c2a6c01d0b364a51b", - "zh:9a6a535a879314a9137ec9d3e858b7c490a962050845cf62620ba2bf4ae916a8", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:ca213e0262c8f686fcd40e3fc84d67b8eea1596de988c13d4a8ecd4522ede669", - "zh:cc4132f682e9bf17c0649928ad92af4da07ffe7bccfe615d955225cdcf9e7f09", - "zh:dfe6de43496d2e2b6dff131fef6ada1e15f1fbba3d47235c751564d22003d05e", - "zh:e37d035fa02693a3d47fe636076cce50b6579b6adc0a36a7cf0456a2331c99ec", - ] -} - -provider "registry.terraform.io/hashicorp/random" { - version = "3.7.2" - constraints = "~> 3.0" - hashes = [ - "h1:356j/3XnXEKr9nyicLUufzoF4Yr6hRy481KIxRVpK0c=", - "zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f", - "zh:1527fb07d9fea400d70e9e6eb4a2b918d5060d604749b6f1c361518e7da546dc", - "zh:1e86bcd7ebec85ba336b423ba1db046aeaa3c0e5f921039b3f1a6fc2f978feab", - "zh:24536dec8bde66753f4b4030b8f3ef43c196d69cccbea1c382d01b222478c7a3", - "zh:29f1786486759fad9b0ce4fdfbbfece9343ad47cd50119045075e05afe49d212", - "zh:4d701e978c2dd8604ba1ce962b047607701e65c078cb22e97171513e9e57491f", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7b8434212eef0f8c83f5a90c6d76feaf850f6502b61b53c329e85b3b281cba34", - "zh:ac8a23c212258b7976e1621275e3af7099e7e4a3d4478cf8d5d2a27f3bc3e967", - "zh:b516ca74431f3df4c6cf90ddcdb4042c626e026317a33c53f0b445a3d93b720d", - "zh:dc76e4326aec2490c1600d6871a95e78f9050f9ce427c71707ea412a2f2f1a62", - "zh:eac7b63e86c749c7d48f527671c7aee5b4e26c10be6ad7232d6860167f99dbb0", - ] -} diff --git a/infrastructure/modules/storage/main.tf b/infrastructure/modules/storage/main.tf index a32b648a20..99e9335e80 100644 --- a/infrastructure/modules/storage/main.tf +++ b/infrastructure/modules/storage/main.tf @@ -50,4 +50,5 @@ resource "aws_iam_policy" "fixtures_read_only" { name = "${var.project_name}-${var.environment}-fixtures-read-only" description = "Allows read-only access to the fixtures S3 bucket" policy = data.aws_iam_policy_document.fixtures_read_only.json + tags = var.common_tags } diff --git a/infrastructure/modules/storage/modules/s3-bucket/outputs.tf b/infrastructure/modules/storage/modules/s3-bucket/outputs.tf index 909151341c..870dea567a 100644 --- a/infrastructure/modules/storage/modules/s3-bucket/outputs.tf +++ b/infrastructure/modules/storage/modules/s3-bucket/outputs.tf @@ -1,9 +1,9 @@ output "arn" { - description = "The ARN of the S3 bucket" + description = "The ARN of the S3 bucket." value = aws_s3_bucket.this.arn } output "bucket" { - description = "The S3 bucket resource" + description = "The S3 bucket resource." value = aws_s3_bucket.this } diff --git a/infrastructure/modules/storage/modules/s3-bucket/variables.tf b/infrastructure/modules/storage/modules/s3-bucket/variables.tf index 919b8c38e1..83f847b78f 100644 --- a/infrastructure/modules/storage/modules/s3-bucket/variables.tf +++ b/infrastructure/modules/storage/modules/s3-bucket/variables.tf @@ -5,7 +5,7 @@ variable "abort_incomplete_multipart_upload_days" { } variable "bucket_name" { - description = "The name of the bucket" + description = "The name of the bucket." type = string } diff --git a/infrastructure/modules/storage/outputs.tf b/infrastructure/modules/storage/outputs.tf index 0273553a89..a771d3ccfb 100644 --- a/infrastructure/modules/storage/outputs.tf +++ b/infrastructure/modules/storage/outputs.tf @@ -1,24 +1,24 @@ output "fixtures_read_only_policy_arn" { - description = "The ARN of the fixtures read-only IAM policy" + description = "The ARN of the fixtures read-only IAM policy." value = aws_iam_policy.fixtures_read_only.arn } output "fixtures_s3_bucket_arn" { - description = "The ARN of the S3 bucket for fixtures" + description = "The ARN of the S3 bucket for fixtures." value = module.fixtures_bucket.arn } output "fixtures_s3_bucket_name" { - description = "The name of the S3 bucket for fixtures" + description = "The name of the S3 bucket for fixtures." value = module.fixtures_bucket.bucket.id } output "zappa_s3_bucket" { - description = "The name of the S3 bucket for Zappa deployments" + description = "The name of the S3 bucket for Zappa deployments." value = module.zappa_bucket.bucket } output "zappa_s3_bucket_arn" { - description = "The ARN of the S3 bucket for Zappa deployments" + description = "The ARN of the S3 bucket for Zappa deployments." value = module.zappa_bucket.arn } diff --git a/infrastructure/modules/storage/variables.tf b/infrastructure/modules/storage/variables.tf index 936ac060e2..525ac2fde5 100644 --- a/infrastructure/modules/storage/variables.tf +++ b/infrastructure/modules/storage/variables.tf @@ -5,21 +5,21 @@ variable "common_tags" { } variable "environment" { - description = "The environment (e.g., staging, production)" + description = "The environment (e.g., staging, production)." type = string } variable "fixtures_bucket_name" { - description = "The name of the S3 bucket for fixtures" + description = "The name of the S3 bucket for fixtures." type = string } variable "project_name" { - description = "The name of the project" + description = "The name of the project." type = string } variable "zappa_bucket_name" { - description = "The name of the S3 bucket for Zappa deployments" + description = "The name of the S3 bucket for Zappa deployments." type = string } diff --git a/infrastructure/staging/.terraform.lock.hcl b/infrastructure/staging/.terraform.lock.hcl index bcea98837a..22df00b9db 100644 --- a/infrastructure/staging/.terraform.lock.hcl +++ b/infrastructure/staging/.terraform.lock.hcl @@ -3,7 +3,7 @@ provider "registry.terraform.io/hashicorp/aws" { version = "6.22.0" - constraints = "~> 6.0, 6.22.0" + constraints = "6.22.0" hashes = [ "h1:TV1UZ7DzioV1EUY/lMS+eIInU379DA1Q2QwnEGGZMks=", "zh:0ed7ceb13bade9076021a14f995d07346d3063f4a419a904d5804d76e372bbda", @@ -26,7 +26,7 @@ provider "registry.terraform.io/hashicorp/aws" { provider "registry.terraform.io/hashicorp/random" { version = "3.7.2" - constraints = "~> 3.0, ~> 3.5" + constraints = "3.7.2" hashes = [ "h1:356j/3XnXEKr9nyicLUufzoF4Yr6hRy481KIxRVpK0c=", "zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f", diff --git a/infrastructure/staging/main.tf b/infrastructure/staging/main.tf index 2ee8d30101..0b1f1488a2 100644 --- a/infrastructure/staging/main.tf +++ b/infrastructure/staging/main.tf @@ -58,7 +58,7 @@ module "ecs" { aws_region = var.aws_region common_tags = local.common_tags - container_parameters_arns = module.parameters.ssm_parameter_arns + container_parameters_arns = module.parameters.django_ssm_parameter_arns ecs_sg_id = module.security.ecs_sg_id environment = var.environment fixtures_read_only_policy_arn = module.storage.fixtures_read_only_policy_arn @@ -83,16 +83,16 @@ module "networking" { module "parameters" { source = "../modules/parameters" - common_tags = local.common_tags - db_host = module.database.db_proxy_endpoint - db_name = var.db_name - db_password = module.database.db_password - db_port = var.db_port - db_user = var.db_user - environment = var.environment - project_name = var.project_name - redis_host = module.cache.redis_primary_endpoint - redis_password = module.cache.redis_auth_token + common_tags = local.common_tags + db_host = module.database.db_proxy_endpoint + db_name = var.db_name + db_password_arn = module.database.db_password_arn + db_port = var.db_port + db_user = var.db_user + environment = var.environment + project_name = var.project_name + redis_host = module.cache.redis_primary_endpoint + redis_password_arn = module.cache.redis_password_arn } module "security" { diff --git a/infrastructure/staging/outputs.tf b/infrastructure/staging/outputs.tf index f140538a31..ddc9ff3517 100644 --- a/infrastructure/staging/outputs.tf +++ b/infrastructure/staging/outputs.tf @@ -1,19 +1,19 @@ output "private_subnet_ids" { - description = "A list of private subnet IDs" + description = "A list of private subnet IDs." value = module.networking.private_subnet_ids } output "lambda_security_group_id" { - description = "The ID of the security group for the Lambda function" + description = "The ID of the security group for the Lambda function." value = module.security.lambda_sg_id } output "ecr_repository_url" { - description = "The URL of the ECR repository" + description = "The URL of the ECR repository." value = module.ecs.ecr_repository_url } output "zappa_s3_bucket" { - description = "The name of the S3 bucket for Zappa deployments" + description = "The name of the S3 bucket for Zappa deployments." value = module.storage.zappa_s3_bucket.bucket } diff --git a/infrastructure/staging/variables.tf b/infrastructure/staging/variables.tf index b2024ab56e..188abbc319 100644 --- a/infrastructure/staging/variables.tf +++ b/infrastructure/staging/variables.tf @@ -5,25 +5,25 @@ variable "aws_region" { } variable "availability_zones" { - description = "A list of availability zones for the VPC" + description = "A list of availability zones for the VPC." type = list(string) default = ["us-east-2a", "us-east-2b", "us-east-2c"] } variable "create_rds_proxy" { - description = "Whether to create an RDS proxy" + description = "Whether to create an RDS proxy." type = bool default = true } variable "db_allocated_storage" { - description = "The allocated storage for the RDS database in GB" + description = "The allocated storage for the RDS database in GB." type = number default = 20 } variable "db_backup_retention_period" { - description = "The number of days to retain backups for" + description = "The number of days to retain backups for." type = number default = 7 } @@ -35,50 +35,60 @@ variable "db_deletion_protection" { } variable "db_engine_version" { - description = "The version of the PostgreSQL engine" + description = "The version of the PostgreSQL engine." type = string default = "16.10" } variable "db_instance_class" { - description = "The instance class for the RDS database" + description = "The instance class for the RDS database." type = string default = "db.t3.micro" + + validation { + condition = can(regex("^db\\.", var.db_instance_class)) + error_message = "DB instance class must start with 'db.' (e.g., db.t3.micro, db.r5.large)." + } } variable "db_name" { - description = "The name of the RDS database" + description = "The name of the RDS database." type = string default = "owasp_nest" } variable "db_password" { - description = "The password for the RDS database" + description = "The password for the RDS database." type = string sensitive = true default = null } variable "db_port" { - description = "The port for the RDS database" + description = "The port for the RDS database." type = number default = 5432 + + validation { + condition = var.db_port > 0 && var.db_port < 65536 + error_message = "Port must be between 1 and 65535." + } } variable "db_storage_type" { - description = "The storage type for the RDS database" + description = "The storage type for the RDS database." type = string default = "gp3" } variable "db_user" { - description = "The username for the RDS database" + description = "The username for the RDS database." type = string default = "owasp_nest_db_user" } variable "environment" { - description = "The environment (e.g., staging, production)" + description = "The environment (e.g., staging, production)." type = string default = "staging" validation { @@ -88,51 +98,75 @@ variable "environment" { } variable "fixtures_bucket_name" { - description = "The name of the S3 bucket for fixtures" + description = "The name of the S3 bucket for fixtures." type = string default = "owasp-nest-fixtures" } variable "private_subnet_cidrs" { - description = "A list of CIDR blocks for the private subnets" + description = "A list of CIDR blocks for the private subnets." type = list(string) default = ["10.0.11.0/24", "10.0.12.0/24", "10.0.13.0/24"] + + validation { + condition = alltrue([ + for cidr in var.private_subnet_cidrs : can(cidrhost(cidr, 0)) + ]) + error_message = "All private subnet CIDRs must be valid IPv4 CIDR blocks." + } } variable "project_name" { - description = "The name of the project" + description = "The name of the project." type = string default = "nest" } variable "public_subnet_cidrs" { - description = "A list of CIDR blocks for the public subnets" + description = "A list of CIDR blocks for the public subnets." type = list(string) default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] + + validation { + condition = alltrue([ + for cidr in var.public_subnet_cidrs : can(cidrhost(cidr, 0)) + ]) + error_message = "All public subnet CIDRs must be valid IPv4 CIDR blocks." + } } variable "redis_engine_version" { - description = "The version of the Redis engine" + description = "The version of the Redis engine." type = string default = "7.0" } variable "redis_node_type" { - description = "The node type for the Redis cache" + description = "The node type for the Redis cache." type = string default = "cache.t3.micro" + + validation { + condition = can(regex("^cache\\.", var.redis_node_type)) + error_message = "Redis node type must start with 'cache.' (e.g., cache.t3.micro, cache.r5.large)." + } } variable "redis_num_cache_nodes" { - description = "The number of cache nodes in the Redis cluster" + description = "The number of cache nodes in the Redis cluster." type = number default = 1 } variable "redis_port" { - description = "The port for the Redis cache" + description = "The port for the Redis cache." type = number default = 6379 + + validation { + condition = var.redis_port > 0 && var.redis_port < 65536 + error_message = "Port must be between 1 and 65535." + } } variable "secret_recovery_window_in_days" { @@ -142,13 +176,18 @@ variable "secret_recovery_window_in_days" { } variable "vpc_cidr" { - description = "The CIDR block for the VPC" + description = "The CIDR block for the VPC." type = string default = "10.0.0.0/16" + + validation { + condition = can(cidrhost(var.vpc_cidr, 0)) + error_message = "VPC CIDR must be a valid IPv4 CIDR block (e.g., 10.0.0.0/16)." + } } variable "zappa_bucket_name" { - description = "The name of the S3 bucket for Zappa deployments" + description = "The name of the S3 bucket for Zappa deployments." type = string default = "owasp-nest-zappa-deployments" }