From 44ac9cbdfd0f21072e0d88f38e3008d7fd4d86c3 Mon Sep 17 00:00:00 2001 From: LBHTKarki Date: Tue, 20 May 2025 09:39:02 +0100 Subject: [PATCH 1/5] add pre-production resources and workflows --- .circleci/config.yml | 294 ++++++++++++------ NotesApi/serverless.yml | 16 +- terraform/pre-production/aws_ssm_parameter.tf | 11 + terraform/pre-production/dynamodb.tf | 38 +++ terraform/pre-production/maint.tf | 46 +++ .../terraform-compliance/dynamodb.feature | 26 ++ .../terraform-compliance/sns.feature | 8 + terraform/pre-production/variables.tf | 9 + 8 files changed, 341 insertions(+), 107 deletions(-) create mode 100644 terraform/pre-production/aws_ssm_parameter.tf create mode 100644 terraform/pre-production/dynamodb.tf create mode 100644 terraform/pre-production/maint.tf create mode 100644 terraform/pre-production/terraform-compliance/dynamodb.feature create mode 100644 terraform/pre-production/terraform-compliance/sns.feature create mode 100644 terraform/pre-production/variables.tf diff --git a/.circleci/config.yml b/.circleci/config.yml index bc71204..d5172e4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -229,134 +229,232 @@ jobs: steps: - deploy-lambda: stage: "production" + assume-role-pre-production: + executor: docker-python + steps: + - assume-role-and-persist-workspace: + aws-account: $AWS_ACCOUNT_PRE_PRODUCTION + terraform-init-and-plan-pre-production: + executor: docker-terraform + steps: + - terraform-init-then-plan: + environment: "pre-production" + terraform-compliance-pre-production: + executor: docker-terraform + steps: + - terraform-compliance: + environment: "pre-production" + terraform-apply-pre-production: + executor: docker-terraform + steps: + - terraform-apply: + environment: "pre-production" + deploy-to-pre-production: + executor: docker-dotnet + steps: + - deploy-lambda: + stage: "pre-production" workflows: - check-and-deploy-development: + # check-and-deploy-development: + # jobs: + # - check-code-formatting: + # context: api-nuget-token-context + # - build-and-test: + # context: + # - api-nuget-token-context + # - SonarCloud + # - assume-role-development: + # context: api-assume-role-housing-development-context + # requires: + # - build-and-test + # - terraform-init-and-plan-development: + # requires: + # - assume-role-development + # - terraform-compliance-development: + # requires: + # - terraform-init-and-plan-development + # - terraform-apply-development: + # requires: + # - terraform-compliance-development + # filters: + # branches: + # only: master + # - deploy-to-development: + # context: + # - api-nuget-token-context + # - "Serverless Framework" + # requires: + # - terraform-apply-development + # filters: + # branches: + # only: master + # check-and-deploy-staging-and-production: + # jobs: + # - check-code-formatting: + # context: api-nuget-token-context + # filters: + # branches: + # only: release + # - build-and-test: + # context: + # - api-nuget-token-context + # - SonarCloud + # filters: + # branches: + # only: release + # - assume-role-staging: + # context: api-assume-role-housing-staging-context + # requires: + # - build-and-test + # filters: + # branches: + # only: release + # - terraform-init-and-plan-staging: + # requires: + # - assume-role-staging + # filters: + # branches: + # only: release + # - terraform-compliance-staging: + # requires: + # - terraform-init-and-plan-staging + # filters: + # branches: + # only: release + # - terraform-apply-staging: + # requires: + # - terraform-compliance-staging + # filters: + # branches: + # only: release + # - deploy-to-staging: + # context: + # - api-nuget-token-context + # - "Serverless Framework" + # requires: + # - terraform-apply-staging + # filters: + # branches: + # only: release + # - permit-production-terraform-release: + # type: approval + # requires: + # - deploy-to-staging + # filters: + # branches: + # only: release + # - assume-role-production: + # context: api-assume-role-housing-production-context + # requires: + # - permit-production-terraform-release + # filters: + # branches: + # only: release + # - terraform-init-and-plan-production: + # requires: + # - assume-role-production + # filters: + # branches: + # only: release + # - terraform-compliance-production: + # requires: + # - terraform-init-and-plan-production + # filters: + # branches: + # only: release + # - terraform-apply-production: + # requires: + # - terraform-compliance-production + # filters: + # branches: + # only: release + # - permit-production-release: + # type: approval + # requires: + # - terraform-apply-production + # filters: + # branches: + # only: release + # - deploy-to-production: + # context: + # - api-nuget-token-context + # - "Serverless Framework" + # requires: + # - permit-production-release + # filters: + # branches: + # only: release + + deploy-terraform-pre-production: jobs: - - check-code-formatting: - context: api-nuget-token-context - - build-and-test: - context: - - api-nuget-token-context - - SonarCloud - - assume-role-development: - context: api-assume-role-housing-development-context - requires: - - build-and-test - - terraform-init-and-plan-development: - requires: - - assume-role-development - - terraform-compliance-development: - requires: - - terraform-init-and-plan-development - - terraform-apply-development: - requires: - - terraform-compliance-development - filters: - branches: - only: master - - deploy-to-development: - context: - - api-nuget-token-context - - "Serverless Framework" - requires: - - terraform-apply-development - filters: - branches: - only: master - check-and-deploy-staging-and-production: - jobs: - - check-code-formatting: - context: api-nuget-token-context - filters: - branches: - only: release - - build-and-test: - context: - - api-nuget-token-context - - SonarCloud + - permit-pre-production-terraform-workflow: + type: approval filters: branches: - only: release - - assume-role-staging: - context: api-assume-role-housing-staging-context - requires: - - build-and-test - filters: - branches: - only: release - - terraform-init-and-plan-staging: + only: ts-2045-add-pre-production-workflows + - assume-role-pre-production: + context: api-assume-role-housing-pre-production-context requires: - - assume-role-staging + - permit-pre-production-terraform-workflow filters: branches: - only: release - - terraform-compliance-staging: + only: ts-2045-add-pre-production-workflows + - terraform-init-and-plan-pre-production: requires: - - terraform-init-and-plan-staging + - assume-role-pre-production filters: branches: - only: release - - terraform-apply-staging: + only: ts-2045-add-pre-production-workflows + - terraform-compliance-pre-production: requires: - - terraform-compliance-staging + - terraform-init-and-plan-pre-production filters: branches: - only: release - - deploy-to-staging: - context: - - api-nuget-token-context - - "Serverless Framework" - requires: - - terraform-apply-staging - filters: - branches: - only: release - - permit-production-terraform-release: + only: ts-2045-add-pre-production-workflows + - permit-pre-production-terraform-deployment: type: approval requires: - - deploy-to-staging + - terraform-compliance-pre-production filters: branches: - only: release - - assume-role-production: - context: api-assume-role-housing-production-context - requires: - - permit-production-terraform-release - filters: - branches: - only: release - - terraform-init-and-plan-production: + only: ts-2045-add-pre-production-workflows + - terraform-apply-pre-production: requires: - - assume-role-production + - permit-pre-production-terraform-deployment filters: branches: - only: release - - terraform-compliance-production: - requires: - - terraform-init-and-plan-production + only: ts-2045-add-pre-production-workflows + + deploy-code-pre-production: + jobs: + - permit-pre-production-code-workflow: + type: approval filters: branches: - only: release - - terraform-apply-production: + only: ts-2045-add-pre-production-workflows + - build-and-test: requires: - - terraform-compliance-production + - permit-pre-production-code-workflow + context: + - api-nuget-token-context + - SonarCloud filters: branches: - only: release - - permit-production-release: - type: approval + only: ts-2045-add-pre-production-workflows + - assume-role-pre-production: + context: api-assume-role-housing-pre-production-context requires: - - terraform-apply-production + - build-and-test filters: branches: - only: release - - deploy-to-production: + only: ts-2045-add-pre-production-workflows + - deploy-to-pre-production: context: - - api-nuget-token-context - - "Serverless Framework" + - api-nuget-token-context + - "Serverless Framework" requires: - - permit-production-release + - assume-role-pre-production filters: branches: - only: release + only: ts-2045-add-pre-production-workflows diff --git a/NotesApi/serverless.yml b/NotesApi/serverless.yml index aaf1402..0eadcd0 100644 --- a/NotesApi/serverless.yml +++ b/NotesApi/serverless.yml @@ -132,15 +132,6 @@ resources: - Ref: 'AWS::Region' - Ref: 'AWS::AccountId' - 'log-group:/aws/lambda/*:*:*' - - Effect: "Allow" - Action: - - "s3:PutObject" - - "s3:GetObject" - Resource: - Fn::Join: - - "" - - - "arn:aws:s3:::" - - "Ref": "ServerlessDeploymentBucket" - PolicyName: lambdaInvocation PolicyDocument: Version: '2012-10-17' @@ -154,6 +145,7 @@ custom: development: arn:aws:lambda:eu-west-2:859159924354:function:api-auth-verify-token-new-development-apiauthverifytokennew staging: arn:aws:lambda:eu-west-2:715003523189:function:api-auth-verify-token-new-staging-apiauthverifytokennew production: arn:aws:lambda:eu-west-2:153306643385:function:api-auth-verify-token-new-production-apiauthverifytokennew + pre-production: arn:aws:lambda:eu-west-2:578479666894:function:api-auth-verify-token-new-pre-production-apiauthverifytokennew safeguards: - title: Require authorizer safeguard: require-authorizer @@ -184,3 +176,9 @@ custom: subnetIds: - subnet-06a697d86a9b6ed01 - subnet-0beb266003a56ca82 + pre-production: + securityGroupIds: + - Ref: LambdaSecurityGroup + subnetIds: + - subnet-08aa35159a8706faa + - subnet-0b848c5b14f841dfb diff --git a/terraform/pre-production/aws_ssm_parameter.tf b/terraform/pre-production/aws_ssm_parameter.tf new file mode 100644 index 0000000..a65dfe8 --- /dev/null +++ b/terraform/pre-production/aws_ssm_parameter.tf @@ -0,0 +1,11 @@ +resource "aws_ssm_parameter" "aspnetcore_environment" { + name = "/housing-tl/pre-production/aspnetcore-environment" + type = "String" + value = "to_be_set_manually" + + lifecycle { + ignore_changes = [ + value, + ] + } +} diff --git a/terraform/pre-production/dynamodb.tf b/terraform/pre-production/dynamodb.tf new file mode 100644 index 0000000..6f3cdaa --- /dev/null +++ b/terraform/pre-production/dynamodb.tf @@ -0,0 +1,38 @@ +resource "aws_dynamodb_table" "notesapi_dynamodb_table" { + name = "Notes" + billing_mode = "PROVISIONED" + read_capacity = 10 + write_capacity = 10 + hash_key = "targetId" + range_key = "id" + + attribute { + name = "id" + type = "S" + } + + attribute { + name = "targetId" + type = "S" + } + + attribute { + name = "createdAt" + type = "S" + } + + local_secondary_index { + name = "NotesByCreated" + range_key = "createdAt" + projection_type = "ALL" + } + + tags = merge( + local.default_tags, + { BackupPolicy = "Dev", Backup = false, Confidentiality = "Internal" } + ) + + point_in_time_recovery { + enabled = false + } +} diff --git a/terraform/pre-production/maint.tf b/terraform/pre-production/maint.tf new file mode 100644 index 0000000..1cf1dd3 --- /dev/null +++ b/terraform/pre-production/maint.tf @@ -0,0 +1,46 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 3.0" + } + } +} + +provider "aws" { + region = "eu-west-2" +} + +locals { + default_tags = { + Name = "notes-api-${var.environment_name}" + Environment = var.environment_name + terraform-managed = true + project_name = var.project_name + Application = "MTFH Housing Pre-Production" + TeamEmail = "developementteam@hackney.gov.uk" + } +} + +terraform { + backend "s3" { + bucket = "housing-pre-production-terraform-state" + encrypt = true + region = "eu-west-2" + key = "services/notes-api/state" + dynamodb_table = "housing-pre-production-terraform-state-lock" + } +} + +resource "aws_sns_topic" "notes" { + name = "notes.fifo" + fifo_topic = true + content_based_deduplication = true + kms_master_key_id = "alias/aws/sns" +} + +resource "aws_ssm_parameter" "notes_sns_arn" { + name = "/sns-topic/pre-production/notes/arn" + type = "String" + value = aws_sns_topic.notes.arn +} diff --git a/terraform/pre-production/terraform-compliance/dynamodb.feature b/terraform/pre-production/terraform-compliance/dynamodb.feature new file mode 100644 index 0000000..2a1b7ec --- /dev/null +++ b/terraform/pre-production/terraform-compliance/dynamodb.feature @@ -0,0 +1,26 @@ +Feature: DynamoDB is used as our NoSQL database service + In order to improve security + As engineers + We'll use ensure our DynamoDB tables are configured correctly + + Scenario: Ensure BackupPolicy tag is present + Given I have aws_dynamodb_table defined + Then it must contain tags + And it must contain BackupPolicy + + Scenario: Ensure point in time recovery disabled + Given I have aws_dynamodb_table defined + Then it must contain point_in_time_recovery + And its enabled property must be false + + Scenario: Ensure a maximum of 1 LSIs + Given I have aws_dynamodb_table defined + When it contains local_secondary_index + When I count them + Then I expect the result is less and equal to 1 + + Scenario: Ensure a maximum of 2 GSIs + Given I have aws_dynamodb_table defined + When it contains global_secondary_index + When I count them + Then I expect the result is less and equal to 2 \ No newline at end of file diff --git a/terraform/pre-production/terraform-compliance/sns.feature b/terraform/pre-production/terraform-compliance/sns.feature new file mode 100644 index 0000000..38278d6 --- /dev/null +++ b/terraform/pre-production/terraform-compliance/sns.feature @@ -0,0 +1,8 @@ +Feature: SNS is used as our notification service + In order to improve security + As engineers + We'll use ensure our SNS topics are configured correctly + + Scenario: Ensure encryption is enabled + Given I have aws_sns_topic defined + Then it must contain kms_master_key_id diff --git a/terraform/pre-production/variables.tf b/terraform/pre-production/variables.tf new file mode 100644 index 0000000..c92cb7b --- /dev/null +++ b/terraform/pre-production/variables.tf @@ -0,0 +1,9 @@ +variable "environment_name" { + type = string + default = "pre-prod" +} + +variable "project_name" { + type = string + default = "Housing-Pre-Production" +} From c4f3dd845de096b8a7c2ac74d9cbaf8f72f5f280 Mon Sep 17 00:00:00 2001 From: LBHTKarki Date: Tue, 20 May 2025 09:52:22 +0100 Subject: [PATCH 2/5] add pre-production vpc id --- NotesApi/serverless.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/NotesApi/serverless.yml b/NotesApi/serverless.yml index 0eadcd0..e57f0ba 100644 --- a/NotesApi/serverless.yml +++ b/NotesApi/serverless.yml @@ -157,6 +157,7 @@ custom: development: vpc-0d15f152935c8716f staging: vpc-064521a7a4109ba31 production: vpc-0ce853ddb64e8fb3c + pre-production: vpc-062a957b99c8b12e6 vpc: development: securityGroupIds: From 4834b28aab956dbb9f0bc1f7c9cb85dc83da7e41 Mon Sep 17 00:00:00 2001 From: LBHTKarki Date: Tue, 20 May 2025 10:08:14 +0100 Subject: [PATCH 3/5] remove approval from pre-prod workflow --- .circleci/config.yml | 283 +++++++++++++++++++++---------------------- 1 file changed, 138 insertions(+), 145 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d5172e4..647887b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -256,135 +256,135 @@ jobs: stage: "pre-production" workflows: - # check-and-deploy-development: - # jobs: - # - check-code-formatting: - # context: api-nuget-token-context - # - build-and-test: - # context: - # - api-nuget-token-context - # - SonarCloud - # - assume-role-development: - # context: api-assume-role-housing-development-context - # requires: - # - build-and-test - # - terraform-init-and-plan-development: - # requires: - # - assume-role-development - # - terraform-compliance-development: - # requires: - # - terraform-init-and-plan-development - # - terraform-apply-development: - # requires: - # - terraform-compliance-development - # filters: - # branches: - # only: master - # - deploy-to-development: - # context: - # - api-nuget-token-context - # - "Serverless Framework" - # requires: - # - terraform-apply-development - # filters: - # branches: - # only: master - # check-and-deploy-staging-and-production: - # jobs: - # - check-code-formatting: - # context: api-nuget-token-context - # filters: - # branches: - # only: release - # - build-and-test: - # context: - # - api-nuget-token-context - # - SonarCloud - # filters: - # branches: - # only: release - # - assume-role-staging: - # context: api-assume-role-housing-staging-context - # requires: - # - build-and-test - # filters: - # branches: - # only: release - # - terraform-init-and-plan-staging: - # requires: - # - assume-role-staging - # filters: - # branches: - # only: release - # - terraform-compliance-staging: - # requires: - # - terraform-init-and-plan-staging - # filters: - # branches: - # only: release - # - terraform-apply-staging: - # requires: - # - terraform-compliance-staging - # filters: - # branches: - # only: release - # - deploy-to-staging: - # context: - # - api-nuget-token-context - # - "Serverless Framework" - # requires: - # - terraform-apply-staging - # filters: - # branches: - # only: release - # - permit-production-terraform-release: - # type: approval - # requires: - # - deploy-to-staging - # filters: - # branches: - # only: release - # - assume-role-production: - # context: api-assume-role-housing-production-context - # requires: - # - permit-production-terraform-release - # filters: - # branches: - # only: release - # - terraform-init-and-plan-production: - # requires: - # - assume-role-production - # filters: - # branches: - # only: release - # - terraform-compliance-production: - # requires: - # - terraform-init-and-plan-production - # filters: - # branches: - # only: release - # - terraform-apply-production: - # requires: - # - terraform-compliance-production - # filters: - # branches: - # only: release - # - permit-production-release: - # type: approval - # requires: - # - terraform-apply-production - # filters: - # branches: - # only: release - # - deploy-to-production: - # context: - # - api-nuget-token-context - # - "Serverless Framework" - # requires: - # - permit-production-release - # filters: - # branches: - # only: release + check-and-deploy-development: + jobs: + - check-code-formatting: + context: api-nuget-token-context + - build-and-test: + context: + - api-nuget-token-context + - SonarCloud + - assume-role-development: + context: api-assume-role-housing-development-context + requires: + - build-and-test + - terraform-init-and-plan-development: + requires: + - assume-role-development + - terraform-compliance-development: + requires: + - terraform-init-and-plan-development + - terraform-apply-development: + requires: + - terraform-compliance-development + filters: + branches: + only: master + - deploy-to-development: + context: + - api-nuget-token-context + - "Serverless Framework" + requires: + - terraform-apply-development + filters: + branches: + only: master + check-and-deploy-staging-and-production: + jobs: + - check-code-formatting: + context: api-nuget-token-context + filters: + branches: + only: release + - build-and-test: + context: + - api-nuget-token-context + - SonarCloud + filters: + branches: + only: release + - assume-role-staging: + context: api-assume-role-housing-staging-context + requires: + - build-and-test + filters: + branches: + only: release + - terraform-init-and-plan-staging: + requires: + - assume-role-staging + filters: + branches: + only: release + - terraform-compliance-staging: + requires: + - terraform-init-and-plan-staging + filters: + branches: + only: release + - terraform-apply-staging: + requires: + - terraform-compliance-staging + filters: + branches: + only: release + - deploy-to-staging: + context: + - api-nuget-token-context + - "Serverless Framework" + requires: + - terraform-apply-staging + filters: + branches: + only: release + - permit-production-terraform-release: + type: approval + requires: + - deploy-to-staging + filters: + branches: + only: release + - assume-role-production: + context: api-assume-role-housing-production-context + requires: + - permit-production-terraform-release + filters: + branches: + only: release + - terraform-init-and-plan-production: + requires: + - assume-role-production + filters: + branches: + only: release + - terraform-compliance-production: + requires: + - terraform-init-and-plan-production + filters: + branches: + only: release + - terraform-apply-production: + requires: + - terraform-compliance-production + filters: + branches: + only: release + - permit-production-release: + type: approval + requires: + - terraform-apply-production + filters: + branches: + only: release + - deploy-to-production: + context: + - api-nuget-token-context + - "Serverless Framework" + requires: + - permit-production-release + filters: + branches: + only: release deploy-terraform-pre-production: jobs: @@ -392,63 +392,56 @@ workflows: type: approval filters: branches: - only: ts-2045-add-pre-production-workflows + only: release - assume-role-pre-production: context: api-assume-role-housing-pre-production-context requires: - permit-pre-production-terraform-workflow filters: branches: - only: ts-2045-add-pre-production-workflows + only: release - terraform-init-and-plan-pre-production: requires: - assume-role-pre-production filters: branches: - only: ts-2045-add-pre-production-workflows + only: release - terraform-compliance-pre-production: requires: - terraform-init-and-plan-pre-production filters: branches: - only: ts-2045-add-pre-production-workflows + only: release - permit-pre-production-terraform-deployment: type: approval requires: - terraform-compliance-pre-production filters: branches: - only: ts-2045-add-pre-production-workflows + only: release - terraform-apply-pre-production: requires: - permit-pre-production-terraform-deployment filters: branches: - only: ts-2045-add-pre-production-workflows + only: release deploy-code-pre-production: jobs: - - permit-pre-production-code-workflow: - type: approval - filters: - branches: - only: ts-2045-add-pre-production-workflows - build-and-test: - requires: - - permit-pre-production-code-workflow context: - api-nuget-token-context - SonarCloud filters: branches: - only: ts-2045-add-pre-production-workflows + only: release - assume-role-pre-production: context: api-assume-role-housing-pre-production-context requires: - build-and-test filters: branches: - only: ts-2045-add-pre-production-workflows + only: release - deploy-to-pre-production: context: - api-nuget-token-context @@ -457,4 +450,4 @@ workflows: - assume-role-pre-production filters: branches: - only: ts-2045-add-pre-production-workflows + only: release From 517be100f633a5756b1475d2b26ff0acb775c076 Mon Sep 17 00:00:00 2001 From: LBHTKarki Date: Fri, 20 Feb 2026 12:49:07 +0000 Subject: [PATCH 4/5] update dev authorizer --- .circleci/config.yml | 3 ++- NotesApi/serverless.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 647887b..160485a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -145,7 +145,8 @@ jobs: build-and-test: executor: docker-python steps: - - checkout + - checkout: + method: full - setup_remote_docker - sonarcloud/scan - run: diff --git a/NotesApi/serverless.yml b/NotesApi/serverless.yml index e57f0ba..090eced 100644 --- a/NotesApi/serverless.yml +++ b/NotesApi/serverless.yml @@ -142,7 +142,7 @@ resources: Resource: "*" custom: authorizerArns: - development: arn:aws:lambda:eu-west-2:859159924354:function:api-auth-verify-token-new-development-apiauthverifytokennew + development: arn:aws:lambda:eu-west-2:859159924354:function:api-gateway-lambda-authorizer staging: arn:aws:lambda:eu-west-2:715003523189:function:api-auth-verify-token-new-staging-apiauthverifytokennew production: arn:aws:lambda:eu-west-2:153306643385:function:api-auth-verify-token-new-production-apiauthverifytokennew pre-production: arn:aws:lambda:eu-west-2:578479666894:function:api-auth-verify-token-new-pre-production-apiauthverifytokennew From 4b57fd32c1b95686042e1be495f607fca6b1ef11 Mon Sep 17 00:00:00 2001 From: Liudvikas Taluntis <43747286+Duslerke@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:20:07 +0000 Subject: [PATCH 5/5] Bump JWT core to 1.87.0 for Cognito support. --- NotesApi/NotesApi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NotesApi/NotesApi.csproj b/NotesApi/NotesApi.csproj index 9cf4a66..16ea964 100644 --- a/NotesApi/NotesApi.csproj +++ b/NotesApi/NotesApi.csproj @@ -20,7 +20,7 @@ - +