diff --git a/.circleci/config.yml b/.circleci/config.yml index 4f734b7..7afe1e3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,6 +43,9 @@ commands: environment: type: string steps: + - add_ssh_keys: + fingerprints: + - "SHA256:rPzp7kChj9Z72jls470HfO0YvieTbdUiB+y8hlxJN8c" - *attach_workspace - checkout - run: @@ -89,6 +92,9 @@ commands: environment: type: string steps: + - add_ssh_keys: + fingerprints: + - "SHA256:rPzp7kChj9Z72jls470HfO0YvieTbdUiB+y8hlxJN8c" - *attach_workspace - checkout - run: @@ -145,7 +151,8 @@ jobs: build-and-test: executor: docker-python steps: - - checkout + - checkout: + method: full - setup_remote_docker - sonarcloud/scan - run: @@ -229,6 +236,31 @@ 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: @@ -339,3 +371,69 @@ workflows: - "Serverless Framework" requires: - permit-production-release + + deploy-terraform-pre-production: + jobs: + - permit-pre-production-terraform-workflow: + type: approval + filters: + branches: + only: release + - assume-role-pre-production: + context: api-assume-role-housing-pre-production-context + requires: + - permit-pre-production-terraform-workflow + filters: + branches: + only: release + - terraform-init-and-plan-pre-production: + requires: + - assume-role-pre-production + filters: + branches: + only: release + - terraform-compliance-pre-production: + requires: + - terraform-init-and-plan-pre-production + filters: + branches: + only: release + - permit-pre-production-terraform-deployment: + type: approval + requires: + - terraform-compliance-pre-production + filters: + branches: + only: release + - terraform-apply-pre-production: + requires: + - permit-pre-production-terraform-deployment + filters: + branches: + only: release + + deploy-code-pre-production: + jobs: + - build-and-test: + context: + - api-nuget-token-context + - SonarCloud + filters: + branches: + only: release + - assume-role-pre-production: + context: api-assume-role-housing-pre-production-context + requires: + - build-and-test + filters: + branches: + only: release + - deploy-to-pre-production: + context: + - api-nuget-token-context + - "Serverless Framework" + requires: + - assume-role-pre-production + filters: + branches: + only: release diff --git a/ReferenceDataApi/ReferenceDataApi.csproj b/ReferenceDataApi/ReferenceDataApi.csproj index d8b321c..0ba7035 100644 --- a/ReferenceDataApi/ReferenceDataApi.csproj +++ b/ReferenceDataApi/ReferenceDataApi.csproj @@ -20,7 +20,7 @@ - + diff --git a/ReferenceDataApi/Startup.cs b/ReferenceDataApi/Startup.cs index 4593684..52dab05 100644 --- a/ReferenceDataApi/Startup.cs +++ b/ReferenceDataApi/Startup.cs @@ -138,6 +138,8 @@ public void ConfigureServices(IServiceCollection services) services.AddLogCallAspect(); services.ConfigureElasticSearch(Configuration); services.AddElasticSearchHealthCheck(); + // Token factory used by the logging middleware core package + // to print user email. Hidden, indirect, implicit dependency services.AddTokenFactory(); RegisterGateways(services); diff --git a/ReferenceDataApi/serverless.yml b/ReferenceDataApi/serverless.yml index 952a42c..b04cd41 100644 --- a/ReferenceDataApi/serverless.yml +++ b/ReferenceDataApi/serverless.yml @@ -100,15 +100,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' @@ -132,7 +123,7 @@ resources: - - 'arn:aws:iam:' - Ref: 'AWS::AccountId' - role/LBH_Canary_Role - RuntimeVersion: syn-nodejs-puppeteer-3.1 + RuntimeVersion: syn-nodejs-puppeteer-9.1 RunConfig: TimeoutInSeconds: 300 EnvironmentVariables: @@ -151,9 +142,10 @@ resources: DurationInSeconds: 0 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 safeguards: - title: Require authorizer safeguard: require-authorizer @@ -187,3 +179,9 @@ custom: subnetIds: - subnet-06a697d86a9b6ed01 - subnet-0beb266003a56ca82 + pre-production: + securityGroupIds: + - sg-0c6335cf631b61e07 + 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..fe32f64 --- /dev/null +++ b/terraform/pre-production/aws_ssm_parameter.tf @@ -0,0 +1,11 @@ +resource "aws_ssm_parameter" "reference_data_token" { + name = "/housing-tl/pre-production/reference-data-token" + type = "String" + value = "to_be_set_manually" + + lifecycle { + ignore_changes = [ + value, + ] + } +} diff --git a/terraform/pre-production/maint.tf b/terraform/pre-production/maint.tf new file mode 100644 index 0000000..e31c308 --- /dev/null +++ b/terraform/pre-production/maint.tf @@ -0,0 +1,81 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 3.0" + } + } +} + +provider "aws" { + region = "eu-west-2" + default_tags { + tags = { + Name = "reference-data-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" + BackupPolicy = "Dev" + Confidentiality = "Internal" + } + } +} + +data "aws_caller_identity" "current" {} + +data "aws_region" "current" {} + +locals { + esDomain = "https://${module.elasticsearch_db_pre_production.es_endpoint_url}" +} + +terraform { + backend "s3" { + bucket = "housing-pre-production-terraform-state" + encrypt = true + region = "eu-west-2" + key = "services/reference-data-api/state" + dynamodb_table = "housing-pre-production-terraform-state-lock" + } +} + +data "aws_vpc" "pre_production_vpc" { + tags = { + Name = "housing-pre-prod-pre-prod" + } +} + +data "aws_subnet_ids" "pre_production" { + vpc_id = data.aws_vpc.pre_production_vpc.id + filter { + name = "tag:Type" + values = ["private"] + } +} + +module "elasticsearch_db_pre_production" { + source = "github.com/LBHackney-IT/aws-hackney-common-terraform.git//modules/database/elasticsearch" + vpc_id = data.aws_vpc.pre_production_vpc.id + environment_name = "pre-production" + port = 443 + domain_name = "reference-data-api-es" + subnet_ids = [tolist(data.aws_subnet_ids.pre_production.ids)[0]] + project_name = "reference-data-api" + es_version = "7.8" + encrypt_at_rest = "true" + instance_type = "t3.small.elasticsearch" + instance_count = "2" + ebs_enabled = "true" + ebs_volume_size = "30" + region = data.aws_region.current.name + account_id = data.aws_caller_identity.current.account_id + create_service_role = false +} + +resource "aws_ssm_parameter" "reference_data_elasticsearch_domain" { + name = "/reference-data-api/pre-production/elasticsearch-domain" + type = "String" + value = local.esDomain +} diff --git a/terraform/pre-production/terraform-compliance/opensearch.feature b/terraform/pre-production/terraform-compliance/opensearch.feature new file mode 100644 index 0000000..ff7830f --- /dev/null +++ b/terraform/pre-production/terraform-compliance/opensearch.feature @@ -0,0 +1,25 @@ +Feature: OpenSearch is used to host the ElasticSearch clusters + In order to improve security + As engineers + We'll use ensure our OpenSearch clusters are configured correctly + + Scenario: Ensure it is deployed in a VPC + Given I have aws_elasticsearch_domain defined + Then it must contain vpc_options + + Scenario: Ensure OpenSearch clusters are encrypted at rest + Given I have aws_elasticsearch_domain defined + Then it must contain encrypt_at_rest + And its enabled property must be true + + Scenario: Ensure minimum instance count is 2 + Given I have aws_elasticsearch_domain defined + Then it must contain cluster_config + And it must contain instance_count + And its value must be greater and equal to 2 + + Scenario: Ensure instance type is small or medium + Given I have aws_elasticsearch_domain defined + Then it must contain cluster_config + And it must contain instance_type + And its value must match the "^(t3\.small\.elasticsearch|t3\.medium\.elasticsearch)" regex 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" +}