diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2e7647b7f54..d4f13112aed 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,6 +10,7 @@ /terraform/environments/cica-copilot @ministryofjustice/cica-copilot-llm-maintainers @ministryofjustice/modernisation-platform /terraform/environments/cooker @ministryofjustice/modernisation-platform @ministryofjustice/modernisation-platform /terraform/environments/corporate-staff-rostering @ministryofjustice/csr-application-support @ministryofjustice/studio-webops @ministryofjustice/modernisation-platform +/terraform/environments/cortex-xsiam @ministryofjustice/mip-devops @ministryofjustice/modernisation-platform /terraform/environments/dacp @ministryofjustice/dts-legacy @ministryofjustice/modernisation-platform /terraform/environments/data-and-insights-wepi @ministryofjustice/data-and-insights-hub @ministryofjustice/modernisation-platform /terraform/environments/data-platform-apps-and-tools @ministryofjustice/data-platform-apps-and-tools @ministryofjustice/modernisation-platform diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index 0385ebf1260..742234df28f 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -78,7 +78,7 @@ jobs: fetch-depth: 0 - name: Run Checkov action id: checkov - uses: bridgecrewio/checkov-action@0dc29cc1e9248c45929de6394c1c2026602de647 # v12.2655.0 + uses: bridgecrewio/checkov-action@4fc35972a43e0622149fadb328d3a5123bfca03e # v12.2671.0 with: directory: ./ framework: terraform diff --git a/.github/workflows/cortex-xsiam.yml b/.github/workflows/cortex-xsiam.yml new file mode 100644 index 00000000000..7b380c8745e --- /dev/null +++ b/.github/workflows/cortex-xsiam.yml @@ -0,0 +1,66 @@ +--- +name: cortex-xsiam +on: + push: + branches: + - main + paths: + - 'terraform/environments/cortex-xsiam/**' + - '.github/workflows/cortex-xsiam.yml' + + pull_request: + branches: + - main + types: [opened, edited, reopened, synchronize] + paths: + - 'terraform/environments/cortex-xsiam/**' + - '.github/workflows/cortex-xsiam.yml' + + workflow_dispatch: + inputs: + action: + description: 'Set either [deploy|destroy].' + default: 'deploy' + required: true + type: string + options: + - deploy + - destroy + +permissions: + id-token: write # This is required for requesting the JWT + contents: read # This is required for actions/checkout + +jobs: + strategy: + uses: ./.github/workflows/reusable_terraform_strategy.yml + if: inputs.action != 'destroy' + with: + application: "${{ github.workflow }}" + + terraform: + needs: strategy + if: inputs.action != 'destroy' + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.strategy.outputs.matrix) }} + uses: ./.github/workflows/reusable_terraform_plan_apply.yml + with: + application: "${{ github.workflow }}" + environment: "${{ matrix.target }}" + action: "${{ matrix.action }}" + secrets: + modernisation_platform_environments: "${{ secrets.MODERNISATION_PLATFORM_ENVIRONMENTS }}" + pipeline_github_token: "${{ secrets.MODERNISATION_PLATFORM_CI_USER_ENVIRONMENTS_REPO_PAT }}" + + destroy-development: + if: inputs.action == 'destroy' + uses: ./.github/workflows/reusable_terraform_plan_apply.yml + with: + application: "${{ github.workflow }}" + environment: "development" + action: "plan_apply" + plan_apply_tfargs: "-destroy" + secrets: + modernisation_platform_environments: "${{ secrets.MODERNISATION_PLATFORM_ENVIRONMENTS }}" + pipeline_github_token: "${{ secrets.MODERNISATION_PLATFORM_CI_USER_ENVIRONMENTS_REPO_PAT }}" diff --git a/.github/workflows/generate-dependabot-file.yml b/.github/workflows/generate-dependabot-file.yml index aae615211f8..1e821ead17c 100644 --- a/.github/workflows/generate-dependabot-file.yml +++ b/.github/workflows/generate-dependabot-file.yml @@ -34,7 +34,7 @@ jobs: env: SECRET: ${{ secrets.GITHUB_TOKEN }} - name: Slack failure notification - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 with: payload: | {"blocks":[{"type": "section","text": {"type": "mrkdwn","text": ":no_entry: Failed GitHub Action:"}},{"type": "section","fields":[{"type": "mrkdwn","text": "*Workflow:*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>"},{"type": "mrkdwn","text": "*Job:*\n${{ github.job }}"},{"type": "mrkdwn","text": "*Repo:*\n${{ github.repository }}"}]}]} diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3d8a474d4c5..4843e88b488 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: name: SARIF file path: results.sarif diff --git a/terraform/environments/corporate-staff-rostering/ec2_common.tf b/terraform/environments/corporate-staff-rostering/ec2_common.tf index 8579f991c3c..a533c211efb 100644 --- a/terraform/environments/corporate-staff-rostering/ec2_common.tf +++ b/terraform/environments/corporate-staff-rostering/ec2_common.tf @@ -1,111 +1,52 @@ -resource "aws_ssm_document" "windows_domain_join" { - name = "windows-domain-join" - document_type = "Command" - document_format = "YAML" - content = file("./ssm-documents/windows-domain-join.yaml") - - tags = merge( - local.tags, - { - Name = "windows-domain-join" - }, - ) -} - -resource "aws_ssm_document" "cloud_watch_agent" { - name = "windows-cloudwatch-agent-config" - document_type = "Command" - document_format = "YAML" - content = file("./ssm-documents/windows-cloudwatch-agent-config.yaml") - - tags = merge( - local.tags, - { - Name = "windows-cloudwatch-agent-config" - }, - ) +locals { + # this local is used in locals.tf + ssm_doc_cloudwatch_log_groups = { + for key, value in local.ssm_docs : + "/aws/ssm/${try(value.name, key)}" => { + retention_in_days = 30 + } + } + ssm_docs = { + windows-domain-join = { + content = file("./ssm-documents/windows-domain-join.yaml") + } + windows-cloudwatch-agent-config = { + content = file("./ssm-documents/windows-cloudwatch-agent-config.yaml") + } + ami-build-command = { + content = file("./ssm-documents/ami-build-command.yaml") + } + ami-build-automation = { + document_type = "Automation" + content = file("./ssm-documents/ami-build-automation.yaml") + } + leave-windows-domain = { + content = file("./ssm-documents/leave-windows-domain.yaml") + } + remove-local-users-windows = { + content = file("./ssm-documents/remove-local-users-windows.yaml") + } + network-testing-tools = { + content = file("./ssm-documents/network-testing-tools.yaml") + } + # windows-psreadline-fix = { + # content = file("./ssm-documents/windows-psreadline-fix.yaml") + # } + } } -resource "aws_ssm_document" "ami_build_command" { - name = "ami-build-command" - document_type = "Command" - document_format = "YAML" - content = file("./ssm-documents/ami-build-command.yaml") - - tags = merge( - local.tags, - { - Name = "ami-build-command" - }, - ) -} +resource "aws_ssm_document" "ssm_documents" { + for_each = local.ssm_docs -resource "aws_ssm_document" "ami_build_automation" { - name = "ami-build-automation" - document_type = "Automation" - document_format = "YAML" - content = file("./ssm-documents/ami-build-automation.yaml") + name = try(each.value.name, each.key) + document_type = try(each.value.document_type, "Command") + document_format = try(each.value.format, "YAML") + content = try(each.value.content) tags = merge( local.tags, { - Name = "ami-build-automation" + Name = try(each.value.name, each.key) }, ) } - -resource "aws_ssm_document" "leave_windows_domain" { - name = "leave-windows-domain" - document_type = "Command" - document_format = "YAML" - content = file("./ssm-documents/leave-windows-domain.yaml") - - tags = merge( - local.tags, - { - Name = "leave-windows-domain" - }, - ) -} - -resource "aws_ssm_document" "remove_local_users_windows" { - name = "remove-local-users-windows" - document_type = "Command" - document_format = "YAML" - content = file("./ssm-documents/remove-local-users-windows.yaml") - - tags = merge( - local.tags, - { - Name = "remove-local-users-windows" - }, - ) -} - -resource "aws_ssm_document" "network-testing-tools" { - name = "network-testing-tools" - document_type = "Command" - document_format = "YAML" - content = file("./ssm-documents/network-testing-tools.yaml") - - tags = merge( - local.tags, - { - Name = "network-testing-tools" - }, - ) -} - -# resource "aws_ssm_document" "windows-psreadline-fix" { -# name = "windows-psreadline-fix" -# document_type = "Command" -# document_format = "YAML" -# content = file("./ssm-documents/windows-psreadline-fix.yaml") - -# tags = merge( -# local.tags, -# { -# Name = "windows-psreadline-fix" -# }, -# ) -# } diff --git a/terraform/environments/corporate-staff-rostering/iam.tf b/terraform/environments/corporate-staff-rostering/iam.tf index 64afd9d3044..628fca18719 100644 --- a/terraform/environments/corporate-staff-rostering/iam.tf +++ b/terraform/environments/corporate-staff-rostering/iam.tf @@ -43,3 +43,37 @@ resource "aws_iam_user_policy_attachment" "mgn_attach_policy_app_migrationfull_a user = aws_iam_user.mgn_user.name policy_arn = "arn:aws:iam::aws:policy/AWSApplicationMigrationFullAccess" } + +# AD clean up lambda IAM resources + +data "aws_iam_policy_document" "lambda_assume_role_policy" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "lambda-ad-role" { + count = local.environment == "test" ? 1 : 0 # temporary + name = "LambdaFunctionADObjectCleanUp" + tags = local.tags + + assume_role_policy = data.aws_iam_policy_document.lambda_assume_role_policy.json +} + +resource "aws_iam_role_policy_attachment" "lambda-vpc-attachment" { + count = local.environment == "test" ? 1 : 0 # temporary + role = aws_iam_role.lambda-ad-role[count.index].name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" +} + +resource "aws_iam_role_policy_attachment" "lambda_secrets_manager" { + count = local.environment == "test" ? 1 : 0 # temporary + role = aws_iam_role.lambda-ad-role[count.index].name + policy_arn = "arn:aws:iam::aws:policy/SecretsManagerReadWrite" +} diff --git a/terraform/environments/corporate-staff-rostering/lambda.tf b/terraform/environments/corporate-staff-rostering/lambda.tf new file mode 100644 index 00000000000..31c11b57408 --- /dev/null +++ b/terraform/environments/corporate-staff-rostering/lambda.tf @@ -0,0 +1,40 @@ +locals { + lambda_ad_object_cleanup = { + function_name = "AD-Object-Clean-Up" + } +} + +module "ad-clean-up-lambda" { + source = "github.com/ministryofjustice/modernisation-platform-terraform-lambda-function" # ref for V3.1 + count = local.environment == "test" ? 1 : 0 # temporary # temporary whilst on-going work + + + application_name = local.lambda_ad_object_cleanup.function_name + function_name = local.lambda_ad_object_cleanup.function_name + description = "Lambda to remove corresponding computer object from Active Directory upon server termination" + package_type = "Zip" + filename = data.archive_file.ad-cleanup-lambda.output_path + source_code_hash = data.archive_file.ad-cleanup-lambda.output_base64sha256 + handler = "lambda_function.lambda_handler" + runtime = "python3.8" + + create_role = false + lambda_role = aws_iam_role.lambda-ad-role[count.index].arn + + vpc_subnet_ids = tolist(data.aws_subnets.shared-private.ids) + vpc_security_group_ids = [module.baseline.security_groups["domain"].id] + + tags = merge( + local.tags, + { + Name = "ad-object-clean-up-lambda" + }, + ) +} + +data "archive_file" "ad-cleanup-lambda" { + type = "zip" + source_dir = "lambda/ad-clean-up" + output_path = "lambda/ad-clean-up/ad-clean-up-lambda-payload-test.zip" +} + diff --git a/terraform/environments/corporate-staff-rostering/lambda/ad-clean-up/lambda_function.py b/terraform/environments/corporate-staff-rostering/lambda/ad-clean-up/lambda_function.py new file mode 100644 index 00000000000..7aacc512236 --- /dev/null +++ b/terraform/environments/corporate-staff-rostering/lambda/ad-clean-up/lambda_function.py @@ -0,0 +1,106 @@ +import json +import boto3 +from ldap3 import Server, Connection, SUBTREE + +# checks for objects within active directory +def check_ad_for_object(hostname, domain_fqdn, domain_name, search_base): + + # create a secrets manager connection + secrets_manager = boto3.client('secretsmanager') + + # extract the secret value from hmpps-domain-services-test / hmpps-domain-services-prod + secret_name = f"/microsoft/AD/{domain_fqdn}/shared-passwords" + response = secrets_manager.get_secret_value(SecretId=secret_name) + secret_data = response['SecretString'] + + # parse the JSON format secret data + secret_json = json.loads(secret_data) + ad_password = secret_json.get('svc_join_domain') + + # domain connection details + domain_controller = Server(f'{domain_fqdn}:389') + ad_username = rf'{domain_name}\aws-lambda' + + with Connection(Server, user=ad_username, password=ad_password, auto_bind=True) as conn: + ad_search = search_base + search_filter = f'(sAMAccountName={hostname})' + # subtree for recursive search through defined OU + search_result = conn.search(ad_search, search_filter, SUBTREE) + print(search_result) + + if conn.entries: + # Get the distinguished name (DN) of the found object + object_dn = conn.entries[0].entry_dn + print(object_dn) + print(f"The object {object_dn} is present in Active Directory and will be deleted...") + # conn.delete(object_dn) # action removed during testing + return 0 # success status + else: + print(f"The terminated server object {hostname} was not found in Active Directory - no further action taken.") + return 1 # object not found status + +# function to iterate through instance tags +def get_tag_value(tags, key): + for tag in tags: + if tag['Key'] == key: + return tag['Value'] + return None + +# function to determine test or prod domain values to be used +def determine_domain(environment_tag): + domain_info = {} + if "development" in environment_tag.split('-') or "test" in environment_tag.split('-'): + domain_info['domain_type'] = "dev/test" + domain_info['domain_name'] = "azure" + domain_info['domain_fqdn'] = "azure.noms.root" + domain_info['search_base'] = "ou=Managed-Windows-Servers,ou=Computers,dc=azure,dc=noms,dc=root" + # domain_info['account'] = "hmpps-domain-services-test" + elif "preproduction" in environment_tag.split('-') or "production" in environment_tag.split('-'): + domain_info['domain_type'] = "preprod/prod" + domain_info['domain_name'] = "hmpp" + domain_info['domain_fqdn'] = "azure.hmpp.root" + domain_info['search_base'] = "ou=MEMBER_SERVERS,dc=azure,dc=hmpp,dc=root" + # domain_info['account'] = "hmpps-domain-services-production" + else: + print("Unexpected environment-name tag. Aborting lambda function...") + return None + return domain_info + +# function to search active directory if an instance is stopped, final iteration will be state terminated +def lambda_handler(event, context): + + if event['detail']['state'] == 'stopped': # to be updated to terminated + instance_id = event['detail']['instance-id'] + + # creates an ec2 connection for terminated instance + ec2 = boto3.client('ec2') + response = ec2.describe_instances(InstanceIds=[instance_id]) + # return the tags associated with the terminated instance + tags = response['Reservations'][0]['Instances'][0]['Tags'] + # terminated instance server-name value, same as hostname + resource_name = 'server-name' + + # obtain the hostame for the terminated server + hostname = get_tag_value(tags, resource_name) + print(f"Server hostname is: {hostname}") + + # obtain terminated instance environment-name value + resource_environment = 'environment-name' + environment_tag = get_tag_value(tags, resource_environment) + + # determine appropriate domain variables + domain = determine_domain(environment_tag) + print("Domain address: {}".format(domain['domain_type'])) + + # pass hostname and domain variables into AD oject deletion function + if hostname is not None and domain is not None: + check_ad_for_object(hostname, domain['domain_fqdn'], domain['domain_name'], domain['search_base']) + print(f"The Active Directory object {hostname} has been deleted.") + else: + print(f"The '{resource_name}' tag was not found for the terminated instance.") + + # 200 http response lambda run successful + return { + 'statusCode': 200, + 'body': 'Active Directory clean up complete. Computer object {resource_name} has been removed.' + } diff --git a/terraform/environments/corporate-staff-rostering/lambda/ad-clean-up/requirements.txt b/terraform/environments/corporate-staff-rostering/lambda/ad-clean-up/requirements.txt new file mode 100644 index 00000000000..7ed6256f455 --- /dev/null +++ b/terraform/environments/corporate-staff-rostering/lambda/ad-clean-up/requirements.txt @@ -0,0 +1,4 @@ +pyasn1~=0.5 +ldap3~=2.9 +boto3 +json \ No newline at end of file diff --git a/terraform/environments/corporate-staff-rostering/locals.tf b/terraform/environments/corporate-staff-rostering/locals.tf index 6951494fe61..72ccf1a84fb 100644 --- a/terraform/environments/corporate-staff-rostering/locals.tf +++ b/terraform/environments/corporate-staff-rostering/locals.tf @@ -36,14 +36,14 @@ locals { } baseline_acm_certificates = {} - baseline_cloudwatch_log_groups = { - cwagent-windows-application = { - retention_in_days = 30 - } - "/aws/ssm/windows-cloudwatch-agent-config" = { - retention_in_days = 30 + baseline_cloudwatch_log_groups = merge( + local.ssm_doc_cloudwatch_log_groups, + { + cwagent-windows-application = { + retention_in_days = 30 + } } - } + ) baseline_cloudwatch_log_metric_filters = {} baseline_ec2_autoscaling_groups = {} baseline_ec2_instances = {} diff --git a/terraform/environments/corporate-staff-rostering/locals_defaults.tf b/terraform/environments/corporate-staff-rostering/locals_defaults.tf index 4fb18a53af2..7ea7c85969f 100644 --- a/terraform/environments/corporate-staff-rostering/locals_defaults.tf +++ b/terraform/environments/corporate-staff-rostering/locals_defaults.tf @@ -1,10 +1,11 @@ locals { ec2_cloudwatch_metric_alarms = { - linux = merge( + database = merge( module.baseline_presets.cloudwatch_metric_alarms.ec2, module.baseline_presets.cloudwatch_metric_alarms.ec2_cwagent_linux, - module.baseline_presets.cloudwatch_metric_alarms.ec2_instance_or_cwagent_stopped_linux + module.baseline_presets.cloudwatch_metric_alarms.ec2_instance_or_cwagent_stopped_linux, + module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].ec2_instance_cwagent_collectd_oracle_db_backup ) windows = merge( module.baseline_presets.cloudwatch_metric_alarms.ec2, @@ -48,7 +49,7 @@ locals { disable_api_stop = false vpc_security_group_ids = ["database"] }) - cloudwatch_metric_alarms = local.ec2_cloudwatch_metric_alarms.linux + cloudwatch_metric_alarms = local.ec2_cloudwatch_metric_alarms.database ebs_volumes = { "/dev/sdb" = { label = "app" } # /u01 "/dev/sdc" = { label = "app" } # /u02 diff --git a/terraform/environments/corporate-staff-rostering/locals_preproduction.tf b/terraform/environments/corporate-staff-rostering/locals_preproduction.tf index 8d9ac0c45e1..d95ae827075 100644 --- a/terraform/environments/corporate-staff-rostering/locals_preproduction.tf +++ b/terraform/environments/corporate-staff-rostering/locals_preproduction.tf @@ -739,14 +739,12 @@ locals { } } http-7781 = { - alarm_target_group_names = [ "pp-csr-w-12-7781" ] # this alarm will deliberately fail, will be removed later - port = 7781 - protocol = "TCP" + port = 7781 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pp-csr-w-12-7781" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb } } } @@ -1221,44 +1219,44 @@ locals { } } http-7770 = { - alarm_target_group_names = [ "pp-csr-w-34-7770" ] - port = 7770 - protocol = "TCP" + alarm_target_group_names = ["pp-csr-w-34-7770"] + port = 7770 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pp-csr-w-34-7770" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7771 = { - alarm_target_group_names = [ "pp-csr-w-34-7771" ] - port = 7771 - protocol = "TCP" + alarm_target_group_names = ["pp-csr-w-34-7771"] + port = 7771 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pp-csr-w-34-7771" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7780 = { - alarm_target_group_names = [ "pp-csr-w-34-7780" ] - port = 7780 - protocol = "TCP" + alarm_target_group_names = ["pp-csr-w-34-7780"] + port = 7780 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pp-csr-w-34-7780" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7781 = { - alarm_target_group_names = [ "pp-csr-w-34-7781" ] - port = 7781 - protocol = "TCP" + alarm_target_group_names = ["pp-csr-w-34-7781"] + port = 7781 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pp-csr-w-34-7781" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } } } diff --git a/terraform/environments/corporate-staff-rostering/locals_production.tf b/terraform/environments/corporate-staff-rostering/locals_production.tf index 23fde67922e..2f9c11cce33 100644 --- a/terraform/environments/corporate-staff-rostering/locals_production.tf +++ b/terraform/environments/corporate-staff-rostering/locals_production.tf @@ -618,44 +618,44 @@ locals { } } http-7770 = { - alarm_target_group_names = [ "pd-csr-w-12-7770" ] - port = 7770 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-12-7770"] + port = 7770 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-12-7770" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7771 = { - alarm_target_group_names = [ "pd-csr-w-12-7771" ] - port = 7771 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-12-7771"] + port = 7771 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-12-7771" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7780 = { - alarm_target_group_names = [ "pd-csr-w-12-7780" ] - port = 7780 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-12-7780"] + port = 7780 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-12-7780" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7781 = { - alarm_target_group_names = [ "pd-csr-w-12-7781" ] - port = 7781 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-12-7781"] + port = 7781 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-12-7781" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } } } @@ -794,44 +794,44 @@ locals { } } http-7770 = { - alarm_target_group_names = [ "pd-csr-w-34-7770" ] - port = 7770 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-34-7770"] + port = 7770 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-34-7770" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7771 = { - alarm_target_group_names = [ "pd-csr-w-34-7771" ] - port = 7771 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-34-7771"] + port = 7771 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-34-7771" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7780 = { - alarm_target_group_names = [ "pd-csr-w-34-7780" ] - port = 7780 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-34-7780"] + port = 7780 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-34-7780" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7781 = { - alarm_target_group_names = [ "pd-csr-w-34-7781" ] - port = 7781 - protocol = "TCP" + alarm_target_group_names = ["pd-csr-w-34-7781"] + port = 7781 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-34-7781" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } } } @@ -971,43 +971,43 @@ locals { } http-7770 = { alarm_target_group_names = ["pd-csr-w-56-7770"] - port = 7770 - protocol = "TCP" + port = 7770 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-56-7770" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7771 = { alarm_target_group_names = ["pd-csr-w-56-7771"] - port = 7771 - protocol = "TCP" + port = 7771 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-56-7771" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7780 = { alarm_target_group_names = ["pd-csr-w-56-7780"] - port = 7780 - protocol = "TCP" + port = 7780 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-56-7780" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } http-7781 = { alarm_target_group_names = ["pd-csr-w-56-7781"] - port = 7781 - protocol = "TCP" + port = 7781 + protocol = "TCP" default_action = { type = "forward" target_group_name = "pd-csr-w-56-7781" } - cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].lb + cloudwatch_metric_alarms = module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["csr_pagerduty"].network_lb } } } diff --git a/terraform/environments/cortex-xsiam/README.md b/terraform/environments/cortex-xsiam/README.md new file mode 100644 index 00000000000..9aa2658704c --- /dev/null +++ b/terraform/environments/cortex-xsiam/README.md @@ -0,0 +1,76 @@ +# Service Runbook + + + +_If you have any questions surrounding this page please post in the `#team-name` channel._ + +## Mandatory Information + +### **Last review date:** + + + +### **Description:** + + + +### **Service URLs:** + + + +### **Incident response hours:** + + + +### **Incident contact details:** + + + +### **Service team contact:** + + + +### **Hosting environment:** + +Modernisation Platform + + + +## Optional + +### **Other URLs:** + + + +### **Expected speed and frequency of releases:** + + + +### **Automatic alerts:** + + + +### **Impact of an outage:** + + + +### **Out of hours response types:** + + + +### **Consumers of this service:** + + + +### **Services consumed by this:** + + + +### **Restrictions on access:** + + + +### **How to resolve specific issues:** + + diff --git a/terraform/environments/cortex-xsiam/application_variables.json b/terraform/environments/cortex-xsiam/application_variables.json new file mode 100644 index 00000000000..6b52bfe9b30 --- /dev/null +++ b/terraform/environments/cortex-xsiam/application_variables.json @@ -0,0 +1,16 @@ +{ + "accounts": { + "development": { + "example_var": "dev-data" + }, + "test": { + "example_var": "test-data" + }, + "preproduction": { + "example_var": "preproduction-data" + }, + "production": { + "example_var": "production-data" + } + } +} diff --git a/terraform/environments/cortex-xsiam/data.tf b/terraform/environments/cortex-xsiam/data.tf new file mode 100644 index 00000000000..96a2521d17e --- /dev/null +++ b/terraform/environments/cortex-xsiam/data.tf @@ -0,0 +1 @@ +#### This file can be used to store data specific to the member account #### diff --git a/terraform/environments/cortex-xsiam/locals.tf b/terraform/environments/cortex-xsiam/locals.tf new file mode 100644 index 00000000000..a7454414911 --- /dev/null +++ b/terraform/environments/cortex-xsiam/locals.tf @@ -0,0 +1 @@ +#### This file can be used to store locals specific to the member account #### diff --git a/terraform/environments/cortex-xsiam/networking.auto.tfvars.json b/terraform/environments/cortex-xsiam/networking.auto.tfvars.json new file mode 100644 index 00000000000..6116c45e3d8 --- /dev/null +++ b/terraform/environments/cortex-xsiam/networking.auto.tfvars.json @@ -0,0 +1,9 @@ +{ + "networking": [ + { + "business-unit": "hq", + "set": "general", + "application": "cortex-xsiam" + } + ] +} diff --git a/terraform/environments/cortex-xsiam/platform_backend.tf b/terraform/environments/cortex-xsiam/platform_backend.tf new file mode 100644 index 00000000000..7b9ceacce21 --- /dev/null +++ b/terraform/environments/cortex-xsiam/platform_backend.tf @@ -0,0 +1,14 @@ +# Backend +terraform { + # `backend` blocks do not support variables, so the following are hard-coded here: + # - S3 bucket name, which is created in modernisation-platform-account/s3.tf + backend "s3" { + acl = "bucket-owner-full-control" + bucket = "modernisation-platform-terraform-state" + dynamodb_table = "modernisation-platform-terraform-state-lock" + encrypt = true + key = "terraform.tfstate" + region = "eu-west-2" + workspace_key_prefix = "environments/members/cortex-xsiam" # This will store the object as environments/members/cortex-xsiam/${workspace}/terraform.tfstate + } +} diff --git a/terraform/environments/cortex-xsiam/platform_base_variables.tf b/terraform/environments/cortex-xsiam/platform_base_variables.tf new file mode 100644 index 00000000000..e5713ed9493 --- /dev/null +++ b/terraform/environments/cortex-xsiam/platform_base_variables.tf @@ -0,0 +1,11 @@ +variable "networking" { + + type = list(any) + +} + +variable "collaborator_access" { + type = string + default = "developer" + description = "Collaborators must specify which access level they are using, eg set an environment variable of export TF_VAR_collaborator_access=migration" +} diff --git a/terraform/environments/cortex-xsiam/platform_data.tf b/terraform/environments/cortex-xsiam/platform_data.tf new file mode 100644 index 00000000000..9844360a8cd --- /dev/null +++ b/terraform/environments/cortex-xsiam/platform_data.tf @@ -0,0 +1,173 @@ +# Current account data +data "aws_region" "current" {} + +data "aws_caller_identity" "current" {} + +# VPC and subnet data +data "aws_vpc" "shared" { + tags = { + "Name" = "${var.networking[0].business-unit}-${local.environment}" + } +} + +data "aws_subnets" "shared-data" { + filter { + name = "vpc-id" + values = [data.aws_vpc.shared.id] + } + tags = { + Name = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-data*" + } +} + +data "aws_subnets" "shared-private" { + filter { + name = "vpc-id" + values = [data.aws_vpc.shared.id] + } + tags = { + Name = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-private*" + } +} + +data "aws_subnets" "shared-public" { + filter { + name = "vpc-id" + values = [data.aws_vpc.shared.id] + } + tags = { + Name = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-public*" + } +} + +data "aws_subnet" "data_subnets_a" { + vpc_id = data.aws_vpc.shared.id + tags = { + "Name" = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-data-${data.aws_region.current.name}a" + } +} + +data "aws_subnet" "data_subnets_b" { + vpc_id = data.aws_vpc.shared.id + tags = { + "Name" = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-data-${data.aws_region.current.name}b" + } +} + +data "aws_subnet" "data_subnets_c" { + vpc_id = data.aws_vpc.shared.id + tags = { + "Name" = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-data-${data.aws_region.current.name}c" + } +} + +data "aws_subnet" "private_subnets_a" { + vpc_id = data.aws_vpc.shared.id + tags = { + "Name" = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-private-${data.aws_region.current.name}a" + } +} + +data "aws_subnet" "private_subnets_b" { + vpc_id = data.aws_vpc.shared.id + tags = { + "Name" = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-private-${data.aws_region.current.name}b" + } +} + +data "aws_subnet" "private_subnets_c" { + vpc_id = data.aws_vpc.shared.id + tags = { + "Name" = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-private-${data.aws_region.current.name}c" + } +} + +data "aws_subnet" "public_subnets_a" { + vpc_id = data.aws_vpc.shared.id + tags = { + Name = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-public-${data.aws_region.current.name}a" + } +} + +data "aws_subnet" "public_subnets_b" { + vpc_id = data.aws_vpc.shared.id + tags = { + Name = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-public-${data.aws_region.current.name}b" + } +} + +data "aws_subnet" "public_subnets_c" { + vpc_id = data.aws_vpc.shared.id + tags = { + Name = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}-public-${data.aws_region.current.name}c" + } +} + +# Route53 DNS data +data "aws_route53_zone" "external" { + provider = aws.core-vpc + + name = "${var.networking[0].business-unit}-${local.environment}.modernisation-platform.service.justice.gov.uk." + private_zone = false +} + +data "aws_route53_zone" "inner" { + provider = aws.core-vpc + + name = "${var.networking[0].business-unit}-${local.environment}.modernisation-platform.internal." + private_zone = true +} + +data "aws_route53_zone" "network-services" { + provider = aws.core-network-services + + name = "modernisation-platform.service.justice.gov.uk." + private_zone = false +} + +# Shared KMS keys (per business unit) +data "aws_kms_key" "general_shared" { + key_id = "arn:aws:kms:eu-west-2:${local.environment_management.account_ids["core-shared-services-production"]}:alias/general-${var.networking[0].business-unit}" +} + +data "aws_kms_key" "ebs_shared" { + key_id = "arn:aws:kms:eu-west-2:${local.environment_management.account_ids["core-shared-services-production"]}:alias/ebs-${var.networking[0].business-unit}" +} + +data "aws_kms_key" "rds_shared" { + key_id = "arn:aws:kms:eu-west-2:${local.environment_management.account_ids["core-shared-services-production"]}:alias/rds-${var.networking[0].business-unit}" +} + +# State for core-network-services resource information +data "terraform_remote_state" "core_network_services" { + backend = "s3" + config = { + acl = "bucket-owner-full-control" + bucket = "modernisation-platform-terraform-state" + key = "environments/accounts/core-network-services/core-network-services-production/terraform.tfstate" + region = "eu-west-2" + encrypt = "true" + } +} + +data "aws_organizations_organization" "root_account" {} + +# Retrieve information about the modernisation platform account +data "aws_caller_identity" "modernisation_platform" { + provider = aws.modernisation-platform +} + +# caller account information to instantiate aws.oidc provider +data "aws_caller_identity" "original_session" { + provider = aws.original-session +} + +data "aws_iam_session_context" "whoami" { + provider = aws.original-session + arn = data.aws_caller_identity.original_session.arn +} + +# Get the environments file from the main repository +data "http" "environments_file" { + url = "https://raw.githubusercontent.com/ministryofjustice/modernisation-platform/main/environments/${local.application_name}.json" +} diff --git a/terraform/environments/cortex-xsiam/platform_locals.tf b/terraform/environments/cortex-xsiam/platform_locals.tf new file mode 100644 index 00000000000..6b5f6e9fbc6 --- /dev/null +++ b/terraform/environments/cortex-xsiam/platform_locals.tf @@ -0,0 +1,38 @@ +locals { + + application_name = "cortex-xsiam" + + environment_management = jsondecode(data.aws_secretsmanager_secret_version.environment_management.secret_string) + + # Stores modernisation platform account id for setting up the modernisation-platform provider + modernisation_platform_account_id = data.aws_ssm_parameter.modernisation_platform_account_id.value + + # This takes the name of the Terraform workspace (e.g. core-vpc-production), strips out the application name (e.g. core-vpc), and checks if + # the string leftover is `-production`, if it isn't (e.g. core-vpc-non-production => -non-production) then it sets the var to false. + is-production = substr(terraform.workspace, length(local.application_name), length(terraform.workspace)) == "-production" + is-preproduction = substr(terraform.workspace, length(local.application_name), length(terraform.workspace)) == "-preproduction" + is-test = substr(terraform.workspace, length(local.application_name), length(terraform.workspace)) == "-test" + is-development = substr(terraform.workspace, length(local.application_name), length(terraform.workspace)) == "-development" + + # Merge tags from the environment json file with additional ones + tags = merge( + jsondecode(data.http.environments_file.response_body).tags, + { "is-production" = local.is-production }, + { "environment-name" = terraform.workspace }, + { "source-code" = "https://github.com/ministryofjustice/modernisation-platform-environments" } + ) + + environment = trimprefix(terraform.workspace, "${var.networking[0].application}-") + vpc_name = var.networking[0].business-unit + subnet_set = var.networking[0].set + vpc_all = "${local.vpc_name}-${local.environment}" + subnet_set_name = "${var.networking[0].business-unit}-${local.environment}-${var.networking[0].set}" + + is_live = [substr(terraform.workspace, length(local.application_name), length(terraform.workspace)) == "-production" || substr(terraform.workspace, length(local.application_name), length(terraform.workspace)) == "-preproduction" ? "live" : "non-live"] + provider_name = "core-vpc-${local.environment}" + + # environment specfic variables + # example usage: + # example_data = local.application_data.accounts[local.environment].example_var + application_data = fileexists("./application_variables.json") ? jsondecode(file("./application_variables.json")) : null +} diff --git a/terraform/environments/cortex-xsiam/platform_providers.tf b/terraform/environments/cortex-xsiam/platform_providers.tf new file mode 100644 index 00000000000..ac450a6ba4d --- /dev/null +++ b/terraform/environments/cortex-xsiam/platform_providers.tf @@ -0,0 +1,49 @@ +# AWS provider for the original session which you connect with +provider "aws" { + alias = "original-session" + region = "eu-west-2" +} + +# AWS provider for the workspace you're working in (every resource will default to using this, unless otherwise specified) +provider "aws" { + region = "eu-west-2" + assume_role { + role_arn = !can(regex("githubactionsrolesession|AdministratorAccess|user", data.aws_caller_identity.original_session.arn)) ? null : can(regex("user", data.aws_caller_identity.original_session.arn)) ? "arn:aws:iam::${local.environment_management.account_ids[terraform.workspace]}:role/${var.collaborator_access}" : "arn:aws:iam::${data.aws_caller_identity.original_session.id}:role/MemberInfrastructureAccess" + } +} + +# AWS provider for the Modernisation Platform, to get things from there if required +provider "aws" { + alias = "modernisation-platform" + region = "eu-west-2" + assume_role { + role_arn = "arn:aws:iam::${local.modernisation_platform_account_id}:role/modernisation-account-limited-read-member-access" + } +} + +# AWS provider for core-vpc-, to access resources in the core-vpc accounts +provider "aws" { + alias = "core-vpc" + region = "eu-west-2" + assume_role { + role_arn = !can(regex("githubactionsrolesession|AdministratorAccess", data.aws_caller_identity.original_session.arn)) ? "arn:aws:iam::${local.environment_management.account_ids[local.provider_name]}:role/member-delegation-read-only" : "arn:aws:iam::${local.environment_management.account_ids[local.provider_name]}:role/member-delegation-${local.vpc_name}-${local.environment}" + } +} + +# AWS provider for network services to enable dns entries for certificate validation to be created +provider "aws" { + alias = "core-network-services" + region = "eu-west-2" + assume_role { + role_arn = !can(regex("githubactionsrolesession|AdministratorAccess", data.aws_caller_identity.original_session.arn)) ? "arn:aws:iam::${local.environment_management.account_ids["core-network-services-production"]}:role/read-log-records" : "arn:aws:iam::${local.environment_management.account_ids["core-network-services-production"]}:role/modify-dns-records" + } +} + +# Provider for creating resources in us-east-1, eg ACM resources for CloudFront +provider "aws" { + alias = "us-east-1" + region = "us-east-1" + assume_role { + role_arn = !can(regex("githubactionsrolesession|AdministratorAccess|user", data.aws_caller_identity.original_session.arn)) ? null : can(regex("user", data.aws_caller_identity.original_session.arn)) ? "arn:aws:iam::${local.environment_management.account_ids[terraform.workspace]}:role/${var.collaborator_access}" : "arn:aws:iam::${data.aws_caller_identity.original_session.id}:role/MemberInfrastructureAccessUSEast" + } +} diff --git a/terraform/environments/cortex-xsiam/platform_secrets.tf b/terraform/environments/cortex-xsiam/platform_secrets.tf new file mode 100644 index 00000000000..bb006856534 --- /dev/null +++ b/terraform/environments/cortex-xsiam/platform_secrets.tf @@ -0,0 +1,17 @@ +# Get modernisation account id from ssm parameter +data "aws_ssm_parameter" "modernisation_platform_account_id" { + provider = aws.original-session + name = "modernisation_platform_account_id" +} + +# Get secret by arn for environment management +data "aws_secretsmanager_secret" "environment_management" { + provider = aws.modernisation-platform + name = "environment_management" +} + +# Get latest secret value with ID from above. This secret stores account IDs for the Modernisation Platform sub-accounts +data "aws_secretsmanager_secret_version" "environment_management" { + provider = aws.modernisation-platform + secret_id = data.aws_secretsmanager_secret.environment_management.id +} diff --git a/terraform/environments/cortex-xsiam/platform_versions.tf b/terraform/environments/cortex-xsiam/platform_versions.tf new file mode 100644 index 00000000000..6161ef3bc02 --- /dev/null +++ b/terraform/environments/cortex-xsiam/platform_versions.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + aws = { + version = "~> 5.0" + source = "hashicorp/aws" + } + http = { + version = "~> 3.0" + source = "hashicorp/http" + } + } + required_version = "~> 1.0" +} diff --git a/terraform/environments/cortex-xsiam/secrets.tf b/terraform/environments/cortex-xsiam/secrets.tf new file mode 100644 index 00000000000..a6a94d9c098 --- /dev/null +++ b/terraform/environments/cortex-xsiam/secrets.tf @@ -0,0 +1 @@ +#### This file can be used to store secrets specific to the member account #### diff --git a/terraform/environments/dacp/application_variables.json b/terraform/environments/dacp/application_variables.json index 800d68bb54b..2467b318431 100644 --- a/terraform/environments/dacp/application_variables.json +++ b/terraform/environments/dacp/application_variables.json @@ -1,14 +1,13 @@ { "accounts": { "development": { - "moj_ip": "81.134.202.29/32", "db_name": "dacp_db_dev", "identifier": "dacp-db-dev", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -22,14 +21,13 @@ "tactical_products_db_secrets_arn": "5fWKaj" }, "preproduction": { - "moj_ip": "81.134.202.29/32", "db_name": "dacp_db_pre_prod", "identifier": "dacp-db-pre-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -43,14 +41,13 @@ "tactical_products_db_secrets_arn": "AHK8Tj" }, "production": { - "moj_ip": "81.134.202.29/32", "db_name": "dacp_db_prod", "identifier": "dacp-db-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", diff --git a/terraform/environments/dacp/load_balancer.tf b/terraform/environments/dacp/load_balancer.tf index 251853d6c1c..8c162a5e5c9 100644 --- a/terraform/environments/dacp/load_balancer.tf +++ b/terraform/environments/dacp/load_balancer.tf @@ -4,14 +4,22 @@ resource "aws_security_group" "dacp_lb_sc" { vpc_id = data.aws_vpc.shared.id ingress { - description = "allow access on HTTPS for the MOJ VPN" + description = "allow access on HTTPS for the Dom1 Cisco VPN" from_port = 443 to_port = 443 protocol = "tcp" - cidr_blocks = [local.application_data.accounts[local.environment].moj_ip] + cidr_blocks = ["194.33.192.1/32"] } - // whitelist all IPs from the tacticalproducts prod load balancer security group + ingress { + description = "allow access on HTTPS for the Global Protect VPN" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["35.176.93.186/32"] + } + + // whitelist user IPs ingress { from_port = 443 to_port = 443 @@ -30,7 +38,10 @@ resource "aws_security_group" "dacp_lb_sc" { "93.56.171.15/32", "213.121.161.124/32", "188.172.252.34/32", - "194.33.197.0/25" + "194.33.197.0/25", + "18.169.147.172/32", + "18.130.148.126/32", + "35.176.148.126/32" ] } diff --git a/terraform/environments/delius-core/application_variables.json b/terraform/environments/delius-core/application_variables.json index dadb6ba3caf..19c8512caf2 100644 --- a/terraform/environments/delius-core/application_variables.json +++ b/terraform/environments/delius-core/application_variables.json @@ -25,7 +25,7 @@ "rds_apply_immediately": "true" }, "test": { - "migration_source_account_id": "479759138745", + "migration_source_account_id": "728765553488", "rds_create": "false", "rds_instance_class": "db.t3.large", "rds_db_name": "MODNDA", diff --git a/terraform/environments/delius-core/locals.tf b/terraform/environments/delius-core/locals.tf index b204cccc40a..7ff1a9b2f75 100644 --- a/terraform/environments/delius-core/locals.tf +++ b/terraform/environments/delius-core/locals.tf @@ -10,8 +10,6 @@ locals { frontend_image_tag = "5.7.6" frontend_container_port = 8080 - ldap_port = 389 - delius_environments_per_account = { # account = [env1, env2] prod = [] diff --git a/terraform/environments/delius-core/locals_development.tf b/terraform/environments/delius-core/locals_development.tf index 2b7cd78ef65..e0a43cdc76b 100644 --- a/terraform/environments/delius-core/locals_development.tf +++ b/terraform/environments/delius-core/locals_development.tf @@ -24,7 +24,7 @@ locals { } db_config_dev = { - instance_type = "r6i.xlarge" + instance_type = "r6i.xlarge" ami_name_regex = "^delius_core_ol_8_5_oracle_db_19c_patch_2024-01-31T16-06-00.575Z" ebs_volumes = { "/dev/sdb" = { label = "app", size = 200 } # /u01 @@ -84,6 +84,13 @@ locals { container_cpu = 1024 } + user_management_config_dev = { + image_tag = "5.7.6" + container_port = 8080 + container_memory = 4096 + container_cpu = 1024 + } + bastion_config_dev = { business_unit = local.vpc_name subnet_set = local.subnet_set diff --git a/terraform/environments/delius-core/locals_test.tf b/terraform/environments/delius-core/locals_test.tf index f43e9c84850..61f2ce9b155 100644 --- a/terraform/environments/delius-core/locals_test.tf +++ b/terraform/environments/delius-core/locals_test.tf @@ -86,6 +86,14 @@ locals { ui_image_tag = "REPLACE" } + user_management_config_test = { + image_tag = "5.7.6" + container_port = 8080 + container_memory = 4096 + container_cpu = 2048 + } + + bastion_config_test = { business_unit = local.vpc_name diff --git a/terraform/environments/delius-core/main_development.tf b/terraform/environments/delius-core/main_development.tf index 981f76a7962..8cd413c0773 100644 --- a/terraform/environments/delius-core/main_development.tf +++ b/terraform/environments/delius-core/main_development.tf @@ -18,15 +18,16 @@ module "environment_dev" { app_name = local.application_name platform_vars = local.platform_vars - account_config = local.account_config - environment_config = local.environment_config_dev - ldap_config = local.ldap_config_dev - db_config = local.db_config_dev - weblogic_config = local.weblogic_config_dev - weblogic_eis_config = local.weblogic_eis_config_dev - bastion_config = local.bastion_config_dev - gdpr_config = local.gdpr_config_dev - merge_config = local.merge_config_dev + account_config = local.account_config + environment_config = local.environment_config_dev + ldap_config = local.ldap_config_dev + db_config = local.db_config_dev + weblogic_config = local.weblogic_config_dev + weblogic_eis_config = local.weblogic_eis_config_dev + bastion_config = local.bastion_config_dev + gdpr_config = local.gdpr_config_dev + merge_config = local.merge_config_dev + user_management_config = local.user_management_config_dev account_info = local.account_info diff --git a/terraform/environments/delius-core/main_test.tf b/terraform/environments/delius-core/main_test.tf index a9b9396daea..ab306b2bd3d 100644 --- a/terraform/environments/delius-core/main_test.tf +++ b/terraform/environments/delius-core/main_test.tf @@ -19,15 +19,16 @@ module "environment_test" { app_name = local.application_name platform_vars = local.platform_vars - account_config = local.account_config - environment_config = local.environment_config_test - ldap_config = local.ldap_config_test - db_config = local.db_config_test - weblogic_config = local.weblogic_config_test - weblogic_eis_config = local.weblogic_eis_config_test - merge_config = local.merge_config_test - gdpr_config = local.gdpr_config_test - bastion_config = local.bastion_config_test + account_config = local.account_config + environment_config = local.environment_config_test + ldap_config = local.ldap_config_test + db_config = local.db_config_test + weblogic_config = local.weblogic_config_test + weblogic_eis_config = local.weblogic_eis_config_test + merge_config = local.merge_config_test + gdpr_config = local.gdpr_config_test + bastion_config = local.bastion_config_test + user_management_config = local.user_management_config_test account_info = local.account_info diff --git a/terraform/environments/delius-core/modules/components/delius_microservice/alb_reg.tf b/terraform/environments/delius-core/modules/components/delius_microservice/alb_reg.tf index 1bceb7d9170..d11cfbe502b 100644 --- a/terraform/environments/delius-core/modules/components/delius_microservice/alb_reg.tf +++ b/terraform/environments/delius-core/modules/components/delius_microservice/alb_reg.tf @@ -25,10 +25,10 @@ resource "aws_lb_target_group" "this" { } } -resource "aws_lb_listener_rule" "blocked_paths_listener_rule" { +resource "aws_lb_listener_rule" "this" { count = var.alb_listener_rule_paths != null ? 1 : 0 listener_arn = var.microservice_lb_https_listener_arn - priority = var.alb_listener_rule_priority + priority = var.alb_listener_rule_priority != null ? var.alb_listener_rule_priority : null condition { path_pattern { values = var.alb_listener_rule_paths @@ -39,4 +39,3 @@ resource "aws_lb_listener_rule" "blocked_paths_listener_rule" { target_group_arn = aws_lb_target_group.this.arn } } - diff --git a/terraform/environments/delius-core/modules/components/delius_microservice/ecs.tf b/terraform/environments/delius-core/modules/components/delius_microservice/ecs.tf index 350fba3cc98..f5ce56248fa 100644 --- a/terraform/environments/delius-core/modules/components/delius_microservice/ecs.tf +++ b/terraform/environments/delius-core/modules/components/delius_microservice/ecs.tf @@ -36,8 +36,8 @@ module "ecs_service" { launch_type = "FARGATE" network_mode = "awsvpc" - task_cpu = "1024" - task_memory = "4096" + task_cpu = var.container_cpu + task_memory = var.container_memory service_role_arn = "arn:aws:iam::${var.account_info.id}:role/${module.ecs_policies.service_role.name}" task_role_arn = "arn:aws:iam::${var.account_info.id}:role/${module.ecs_policies.task_role.name}" diff --git a/terraform/environments/delius-core/modules/components/oracle_db_instance/instance.tf b/terraform/environments/delius-core/modules/components/oracle_db_instance/instance.tf index 1acd1230a69..9daa37d3275 100644 --- a/terraform/environments/delius-core/modules/components/oracle_db_instance/instance.tf +++ b/terraform/environments/delius-core/modules/components/oracle_db_instance/instance.tf @@ -58,7 +58,7 @@ locals { metadata_endpoint_enabled = var.metadata_options.http_endpoint metadata_options_http_tokens = var.metadata_options.http_tokens monitoring = var.monitoring - ebs_block_device_inline = false + ebs_block_device_inline = true vpc_security_group_ids = var.security_group_ids private_dns_name_options = { enable_resource_name_dns_aaaa_record = false diff --git a/terraform/environments/delius-core/modules/components/oracle_db_shared/locals.tf b/terraform/environments/delius-core/modules/components/oracle_db_shared/locals.tf new file mode 100644 index 00000000000..26fb27a8ff4 --- /dev/null +++ b/terraform/environments/delius-core/modules/components/oracle_db_shared/locals.tf @@ -0,0 +1,6 @@ +locals { + secret_prefix = join("-", [lookup(var.tags, "environment-name", null), lookup(var.tags, "delius-environment", null), lookup(var.tags, "application", null)]) + dba_secret_name = "${local.secret_prefix}-dba-passwords" + application_secret_name = "${local.secret_prefix}-application-passwords" + oem_account_id = var.platform_vars.environment_management.account_ids[join("-",["hmpps-oem", var.account_info.mp_environment])] +} \ No newline at end of file diff --git a/terraform/environments/delius-core/modules/components/oracle_db_shared/secrets.tf b/terraform/environments/delius-core/modules/components/oracle_db_shared/secrets.tf index cf016c58044..ec61ef9165b 100644 --- a/terraform/environments/delius-core/modules/components/oracle_db_shared/secrets.tf +++ b/terraform/environments/delius-core/modules/components/oracle_db_shared/secrets.tf @@ -1,10 +1,28 @@ resource "aws_secretsmanager_secret" "delius_core_dba_passwords" { - name = join("-", [lookup(var.tags, "environment-name", null), lookup(var.tags, "delius-environment", null), replace(lookup(var.tags, "application", null), "-core", ""), "dba-passwords"]) + name = local.dba_secret_name description = "DBA Users Credentials" kms_key_id = var.account_config.kms_keys.general_shared tags = var.tags } +data "aws_iam_policy_document" "delius_core_dba_passwords" { + statement { + sid = "OemAWSAccountToReadTheSecret" + effect = "Allow" + principals { + type = "AWS" + identifiers = ["arn:aws:iam::${local.oem_account_id}:role/EC2OracleEnterpriseManagementSecretsRole"] + } + actions = ["secretsmanager:GetSecretValue"] + resources = ["*"] + } +} + +resource "aws_secretsmanager_secret_policy" "delius_core_dba_passwords" { + secret_arn = aws_secretsmanager_secret.delius_core_dba_passwords.arn + policy = data.aws_iam_policy_document.delius_core_dba_passwords.json +} + resource "aws_secretsmanager_secret_version" "delius_core_dba_passwords" { secret_id = aws_secretsmanager_secret.delius_core_dba_passwords.id secret_string = "REPLACE" @@ -16,9 +34,9 @@ resource "aws_secretsmanager_secret_version" "delius_core_dba_passwords" { } resource "aws_secretsmanager_secret" "delius_core_application_passwords" { - name = join("-", [lookup(var.tags, "environment-name", null), lookup(var.tags, "delius-environment", null), replace(lookup(var.tags, "application", null), "-core", ""), "application-passwords"]) - kms_key_id = var.account_config.kms_keys.general_shared + name = local.application_secret_name description = "Application Users Credentials" + kms_key_id = var.account_config.kms_keys.general_shared tags = var.tags } @@ -30,4 +48,4 @@ resource "aws_secretsmanager_secret_version" "delius_core_application_passwords" secret_string ] } -} +} \ No newline at end of file diff --git a/terraform/environments/delius-core/modules/components/oracle_db_shared/variables.tf b/terraform/environments/delius-core/modules/components/oracle_db_shared/variables.tf index 2a349763945..7755e45b50a 100644 --- a/terraform/environments/delius-core/modules/components/oracle_db_shared/variables.tf +++ b/terraform/environments/delius-core/modules/components/oracle_db_shared/variables.tf @@ -23,6 +23,15 @@ variable "account_config" { type = any } +variable "account_info" { + description = "Account info to pass to the instance" + type = any +} + +variable "platform_vars" { + description = "Platform vars to pass to the instance" + type = any +} variable "public_keys" { description = "Public keys to add to the instance" diff --git a/terraform/environments/delius-core/modules/environment_all_components/community_api.tf b/terraform/environments/delius-core/modules/environment_all_components/community_api.tf new file mode 100644 index 00000000000..2b13af6b877 --- /dev/null +++ b/terraform/environments/delius-core/modules/environment_all_components/community_api.tf @@ -0,0 +1,104 @@ +module "community_api" { + source = "../components/delius_microservice" + + name = var.community_api.name + certificate_arn = aws_acm_certificate.external.arn + alb_security_group_id = aws_security_group.delius_frontend_alb_security_group.id + env_name = var.env_name + container_port_config = [ + { + containerPort = var.community_api.container_port + protocol = var.community_api.protocol + } + ] + ecs_cluster_arn = module.ecs.ecs_cluster_arn + container_secrets = [ + # { + # name = "APPINSIGHTS_INSTRUMENTATIONKEY" + # valueFrom = "/${var.environment_name}/${var.project_name}/newtech/offenderapi/appinsights_key" + # }, + { + name = "SPRING_DATASOURCE_PASSWORD" + valueFrom = aws_ssm_parameter.jdbc_password.arn + # valueFrom = "/${var.environment_name}/${var.project_name}/delius-database/db/delius_pool_password" + } + # , + # { + # name = "SPRING_LDAP_PASSWORD" + # valueFrom = "/${var.environment_name}/${var.project_name}/apacheds/apacheds/ldap_admin_password" + # }, + # { + # name = "DELIUS_USERNAME" + # valueFrom = "/${var.environment_name}/${var.project_name}/apacheds/apacheds/casenotes_user" + # }, + # { + # name = "DELIUS_PASSWORD" + # valueFrom = "/${var.environment_name}/${var.project_name}/apacheds/apacheds/casenotes_password" + # }, + # { + # name = "SENTRY_DSN" + # valueFrom = "/${var.environment_name}/${var.project_name}/probation-integration/community-api/sentry-dsn" + # } + ] + ingress_security_groups = [] + tags = var.tags + # TODO - This LB is a placeholder marked no 13 on the architecture diagram: https://dsdmoj.atlassian.net/wiki/spaces/DAM/pages/3773105057/High-Level+Architecture + # Two LBs (public and secure) are needed as show on the architecture diagram. There is an architectural discussion to be had if we could get away with just one LB instead + microservice_lb_arn = aws_lb.delius_core_frontend.arn + microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn + # Please check with the app team what the rule path should be here. + alb_listener_rule_paths = ["/secure", "/secure/*"] + platform_vars = var.platform_vars + container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-community-api-ecr-repo:${var.community_api.image_tag}" + account_config = var.account_config + health_check_path = "/health/ping" + account_info = var.account_info + container_environment_vars = [ + { + name = "SPRING_PROFILES_ACTIVE" + # The value below is from the legacy + value = "oracle" + }, + { + name = "SPRING_DATASOURCE_USERNAME" + # The value below is from the legacy + value = "delius_pool" + }, + { + name = "SPRING_DATASOURCE_URL" + value = aws_ssm_parameter.jdbc_url.arn + # The value below is from the legacy + # value = data.terraform_remote_state.database.outputs.jdbc_failover_url + }, + { + name = "DELIUS_LDAP_USERS_BASE" + value = aws_ssm_parameter.delius_core_ldap_principal.arn + # The value below is from the legacy + # value = data.terraform_remote_state.ldap.outputs.ldap_base_users + }, + { + name = "SPRING_LDAP_USERNAME" + value = aws_secretsmanager_secret.delius_core_ldap_credential.arn + # The value below is from the legacy + # value = data.terraform_remote_state.ldap.outputs.ldap_bind_user + }, + { + name = "SPRING_LDAP_URLS" + value = "ldap://${module.ldap.nlb_dns_name}:${var.ldap_config.port}" + # The value below is from the legacy + # value = "${data.terraform_remote_state.ldap.outputs.ldap_protocol}://${data.terraform_remote_state.ldap.outputs.private_fqdn_ldap_elb}:${data.terraform_remote_state.ldap.outputs.ldap_port}" + }, + # { + # name = "ALFRESCO_BASEURL" + # value = "https://alfresco.${data.terraform_remote_state.vpc.outputs.public_zone_name}/alfresco/s/noms-spg" + # }, + # { + # name = "DELIUS_BASEURL" + # value = "http://${data.terraform_remote_state.interface.outputs.service_discovery_url}:7001/api" + # }, + { + name = "SENTRY_ENVIRONMENT" + value = var.env_name + } + ] +} diff --git a/terraform/environments/delius-core/modules/environment_all_components/database.tf b/terraform/environments/delius-core/modules/environment_all_components/database.tf index 0726aae7184..736a50bff21 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/database.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/database.tf @@ -7,6 +7,8 @@ module "oracle_db_shared" { source = "../components/oracle_db_shared" account_config = var.account_config environment_config = var.environment_config + account_info = var.account_info + platform_vars = var.platform_vars env_name = var.env_name tags = local.tags public_keys = local.db_public_key_data.keys[var.account_info.mp_environment] @@ -97,11 +99,9 @@ module "oracle_db_standby" { subnet_id = var.account_config.ordered_private_subnet_ids[(count.index + length(module.oracle_db_primary)) % 3] availability_zone = "eu-west-2${lookup(local.availability_zone_map, (count.index + length(module.oracle_db_primary)) % 3, "a")}" tags = local.tags - user_data = base64encode( - templatefile( - "${path.module}/templates/userdata.sh.tftpl", - var.db_config.ansible_user_data_config - ) + user_data = templatefile( + "${path.module}/templates/userdata.sh.tftpl", + var.db_config.ansible_user_data_config ) ssh_keys_bucket_name = module.oracle_db_shared.ssh_keys_bucket_name diff --git a/terraform/environments/delius-core/modules/environment_all_components/delius_frontend_alb.tf b/terraform/environments/delius-core/modules/environment_all_components/delius_frontend_alb.tf index ca16b3b1806..d7d829279b6 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/delius_frontend_alb.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/delius_frontend_alb.tf @@ -150,6 +150,7 @@ resource "aws_lb_listener_rule" "homepage_listener_rule" { resource "aws_lb_listener_rule" "allowed_paths_listener_rule" { listener_arn = aws_lb_listener.listener_https.arn + priority = 2 condition { path_pattern { values = [ diff --git a/terraform/environments/delius-core/modules/environment_all_components/gdpr_api_service.tf b/terraform/environments/delius-core/modules/environment_all_components/gdpr_api_service.tf index dd2305e568c..8ddb8bbce0b 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/gdpr_api_service.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/gdpr_api_service.tf @@ -32,7 +32,6 @@ module "gdpr_api_service" { tags = var.tags microservice_lb_arn = aws_lb.delius_core_frontend.arn microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn - alb_listener_rule_priority = 5 alb_listener_rule_paths = ["/gdpr/api", "/gdpr/api/*"] platform_vars = var.platform_vars container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-gdpr-api-ecr-repo:${var.gdpr_config.api_image_tag}" diff --git a/terraform/environments/delius-core/modules/environment_all_components/gdpr_ui_service.tf b/terraform/environments/delius-core/modules/environment_all_components/gdpr_ui_service.tf index 07970ce5913..5f4d58aa3e9 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/gdpr_ui_service.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/gdpr_ui_service.tf @@ -17,7 +17,6 @@ module "gdpr_ui_service" { tags = var.tags microservice_lb_arn = aws_lb.delius_core_frontend.arn microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn - alb_listener_rule_priority = 6 alb_listener_rule_paths = ["/gdpr/ui", "/gdpr/ui/*"] platform_vars = var.platform_vars container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-gdpr-ui-ecr-repo:${var.gdpr_config.ui_image_tag}" diff --git a/terraform/environments/delius-core/modules/environment_all_components/ldap_ecs.tf b/terraform/environments/delius-core/modules/environment_all_components/ldap_ecs.tf deleted file mode 100644 index c89b11298a5..00000000000 --- a/terraform/environments/delius-core/modules/environment_all_components/ldap_ecs.tf +++ /dev/null @@ -1,392 +0,0 @@ -#module "ldap_ecs_policies" { -# source = "../ecs_policies" -# env_name = var.env_name -# service_name = "openldap" -# tags = local.tags -# extra_exec_role_allow_statements = [ -# "elasticfilesystem:ClientRootAccess", -# "elasticfilesystem:ClientWrite", -# "elasticfilesystem:ClientMount" -# ] -# extra_task_role_policies = { -# migration_s3 = data.aws_iam_policy_document.migration_s3 -# } -#} -# -#data "aws_iam_policy_document" "migration_s3" { -# statement { -# sid = "CustomPolicyActions" -# effect = "Allow" -# actions = [ -# "s3:GetObject", -# "s3:ListBucket", -# "s3:HeadBucket", -# "s3:HeadObject" -# ] -# resources = [ -# module.s3_bucket_migration.bucket.arn -# ] -# } -#} -# -#module "s3_bucket_migration" { -# -# source = "github.com/ministryofjustice/modernisation-platform-terraform-s3-bucket?ref=v7.0.0" -# -# providers = { -# aws.bucket-replication = aws.bucket-replication -# } -# -# bucket_prefix = "${var.app_name}-${var.env_name}-ldap-" -# versioning_enabled = true -# sse_algorithm = "AES256" -# # Useful guide - https://aws.amazon.com/blogs/storage/how-to-use-aws-datasync-to-migrate-data-between-amazon-s3-buckets/ -# bucket_policy_v2 = [{ -# effect = "Allow" -# actions = [ -# "s3:GetBucketLocation", -# "s3:ListBucket", -# "s3:ListBucketMultipartUploads", -# "s3:AbortMultipartUpload", -# "s3:DeleteObject", -# "s3:GetObject", -# "s3:ListMultipartUploadParts", -# "s3:PutObject", -# "s3:GetObjectTagging", -# "s3:PutObjectTagging" -# ] -# principals = { -# type = "AWS" -# identifiers = [ -# "arn:aws:iam::${var.ldap_config.migration_source_account_id}:role/${var.ldap_config.migration_lambda_role}" -# ] -# } -# }, -# { -# effect = "Allow" -# actions = ["s3:ListBucket"] -# principals = { -# type = "AWS" -# identifiers = [ -# "arn:aws:iam::${var.ldap_config.migration_source_account_id}:role/terraform" -# ] -# } -# }, -# { -# effect = "Allow" -# actions = ["s3:ListBucket"] -# principals = { -# type = "AWS" -# identifiers = [ -# "arn:aws:iam::${var.ldap_config.migration_source_account_id}:role/admin" -# ] -# } -# }, -# { -# effect = "Allow" -# actions = [ -# "s3:GetObject", -# "s3:ListBucket" -# ] -# principals = { -# type = "AWS" -# identifiers = [ -# module.ldap_ecs_policies.task_role.arn -# ] -# } -# } -# ] -# -# ownership_controls = "BucketOwnerEnforced" # Disable all S3 bucket ACL -# -# lifecycle_rule = [ -# { -# id = "main" -# enabled = "Enabled" -# prefix = "" -# -# tags = { -# rule = "log" -# autoclean = "true" -# } -# -# noncurrent_version_transition = [ -# { -# days = 120 -# storage_class = "STANDARD_IA" -# }, { -# days = 180 -# storage_class = "GLACIER" -# } -# ] -# -# noncurrent_version_expiration = { -# days = 365 -# } -# } -# ] -# -# tags = merge( -# local.tags, -# { -# Name = "${var.env_name}-ldap-migration-s3-bucket" -# }, -# ) -#} -# -## Create s3 bucket for deployment state -#module "s3_bucket_ldap_deployment" { -# -# source = "github.com/ministryofjustice/modernisation-platform-terraform-s3-bucket?ref=v7.0.0" -# -# providers = { -# aws.bucket-replication = aws.bucket-replication -# } -# bucket_prefix = "${var.env_name}-ldap-deployment-" -# versioning_enabled = true -# -# lifecycle_rule = [ -# { -# id = "main" -# enabled = "Enabled" -# prefix = "" -# -# tags = { -# rule = "log" -# autoclean = "true" -# } -# -# noncurrent_version_transition = [ -# { -# days = 90 -# storage_class = "STANDARD_IA" -# }, { -# days = 365 -# storage_class = "GLACIER" -# } -# ] -# -# noncurrent_version_expiration = { -# days = 730 -# } -# } -# ] -# -# tags = local.tags -#} -# -#resource "aws_security_group" "ldap" { -# name = "${var.env_name}-ldap-sg" -# description = "Security group for the ${var.env_name} ldap service" -# vpc_id = var.account_info.vpc_id -# tags = local.tags -# lifecycle { -# create_before_destroy = true -# } -#} -# -#resource "aws_security_group_rule" "allow_all_egress" { -# description = "Allow all outbound traffic to any IPv4 address" -# type = "egress" -# from_port = 0 -# to_port = 0 -# protocol = "-1" -# cidr_blocks = ["0.0.0.0/0"] -# security_group_id = aws_security_group.ldap.id -#} -# -#resource "aws_security_group_rule" "ldap_nlb" { -# for_each = toset(["tcp", "udp"]) -# description = "Allow inbound traffic from VPC" -# type = "ingress" -# from_port = local.ldap_port -# to_port = local.ldap_port -# protocol = each.value -# security_group_id = aws_security_group.ldap.id -# cidr_blocks = [var.account_config.shared_vpc_cidr] -#} -# -#resource "aws_security_group_rule" "top_ldap_from_bastion" { -# for_each = toset(["tcp", "udp"]) -# description = "Allow inbound traffic from bastion" -# type = "ingress" -# from_port = local.ldap_port -# to_port = local.ldap_port -# protocol = each.value -# security_group_id = aws_security_group.ldap.id -# source_security_group_id = var.account_config.bastion.bastion_security_group -#} -# -#resource "aws_security_group_rule" "allow_ldap_from_legacy_env" { -# for_each = toset(["tcp", "udp"]) -# description = "Allow inbound LDAP traffic from corresponding legacy VPC" -# type = "ingress" -# from_port = local.ldap_port -# to_port = local.ldap_port -# protocol = each.value -# security_group_id = aws_security_group.ldap.id -# cidr_blocks = var.environment_config.migration_environment_private_cidr -#} -# -#resource "aws_security_group_rule" "efs_ingress_ldap" { -# type = "ingress" -# from_port = 2049 -# to_port = 2049 -# protocol = "tcp" -# source_security_group_id = module.efs.ldap_security_group_id -# security_group_id = aws_security_group.ldap.id -#} -# -#resource "aws_cloudwatch_log_group" "ldap" { -# name = "${var.env_name}-ldap-ecs" -# retention_in_days = 30 -#} -# -#output "s3_bucket_ldap_deployment_name" { -# value = module.s3_bucket_ldap_deployment.bucket.id -#} -# -#data "aws_iam_policy_document" "ecs_task" { -# statement { -# effect = "Allow" -# actions = ["sts:AssumeRole"] -# -# principals { -# type = "Service" -# identifiers = ["ecs-tasks.amazonaws.com"] -# } -# } -#} -# -#resource "aws_iam_role" "ldap_ecs_task" { -# name = "${var.env_name}-ldap-task" -# assume_role_policy = data.aws_iam_policy_document.ecs_task.json -# tags = local.tags -#} -# -#data "aws_iam_policy_document" "ecs_service" { -# statement { -# effect = "Allow" -# actions = ["sts:AssumeRole"] -# -# principals { -# type = "Service" -# identifiers = ["ecs.amazonaws.com"] -# } -# } -#} -# -#resource "aws_iam_role" "ldap_ecs_service" { -# name = "${var.env_name}-ldap-service" -# assume_role_policy = data.aws_iam_policy_document.ecs_service.json -# tags = local.tags -#} -# -#data "aws_iam_policy_document" "ecs_service_policy" { -# statement { -# effect = "Allow" -# resources = ["*"] -# -# actions = [ -# "elasticloadbalancing:Describe*", -# "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", -# "elasticloadbalancing:RegisterInstancesWithLoadBalancer", -# "ec2:Describe*", -# "ec2:AuthorizeSecurityGroupIngress", -# "elasticloadbalancing:RegisterTargets", -# "elasticloadbalancing:DeregisterTargets" -# ] -# } -#} -# -#resource "aws_iam_role_policy" "ldap_ecs_service" { -# name = "${var.env_name}-ldap-service" -# policy = data.aws_iam_policy_document.ecs_service_policy.json -# role = aws_iam_role.ldap_ecs_service.id -#} -# -#data "aws_iam_policy_document" "ecs_ssm_exec" { -# statement { -# effect = "Allow" -# resources = ["*"] -# -# actions = [ -# "ssmmessages:CreateControlChannel", -# "ssmmessages:CreateDataChannel", -# "ssmmessages:OpenControlChannel", -# "ssmmessages:OpenDataChannel" -# ] -# } -#} -# -#data "aws_iam_policy_document" "ecs_s3" { -# statement { -# effect = "Allow" -# resources = [module.s3_bucket_migration.bucket.arn] -# -# actions = [ -# "s3:*" -# ] -# } -#} -# -#resource "aws_iam_role_policy" "ldap_ecs_s3" { -# name = "${var.env_name}-ldap-service-s3" -# policy = data.aws_iam_policy_document.ecs_s3.json -# role = aws_iam_role.ldap_ecs_task.id -#} -# -#resource "aws_iam_role_policy" "ecs_ssm_exec" { -# name = "${var.env_name}-ldap-service-ssm-exec" -# policy = data.aws_iam_policy_document.ecs_ssm_exec.json -# role = aws_iam_role.ldap_ecs_task.id -#} -# -## IAM role that the Amazon ECS container agent and the Docker daemon can assume -#data "aws_iam_policy_document" "ecs_task_exec" { -# statement { -# actions = ["sts:AssumeRole"] -# -# principals { -# type = "Service" -# identifiers = ["ecs-tasks.amazonaws.com"] -# } -# } -#} -# -#resource "aws_iam_role" "ldap_ecs_exec" { -# name = "${var.env_name}-ldap-task-exec" -# assume_role_policy = data.aws_iam_policy_document.ecs_task_exec.json -# tags = local.tags -#} -# -#data "aws_iam_policy_document" "ecs_exec" { -# statement { -# effect = "Allow" -# resources = ["*"] -# -# actions = [ -# "ssm:GetParameters", -# "ecr:GetAuthorizationToken", -# "ecr:BatchCheckLayerAvailability", -# "ecr:GetDownloadUrlForLayer", -# "ecr:BatchGetImage", -# "logs:CreateLogGroup", -# "logs:CreateLogStream", -# "logs:PutLogEvents", -# "secretsmanager:GetSecretValue" -# ] -# } -#} -# -#resource "aws_iam_role_policy" "ecs_exec" { -# name = "${var.env_name}-ldap-task-exec" -# policy = data.aws_iam_policy_document.ecs_exec.json -# role = aws_iam_role.ldap_ecs_exec.id -#} -# -## temp log group for testing ldap -#resource "aws_cloudwatch_log_group" "ldap_test" { -# name = "/ecs/ldap_${var.env_name}" -# retention_in_days = 5 -#} diff --git a/terraform/environments/delius-core/modules/environment_all_components/ldap_efs.tf b/terraform/environments/delius-core/modules/environment_all_components/ldap_efs.tf deleted file mode 100644 index 8660e95971c..00000000000 --- a/terraform/environments/delius-core/modules/environment_all_components/ldap_efs.tf +++ /dev/null @@ -1,80 +0,0 @@ -# resource "aws_efs_file_system" "ldap" { -# creation_token = "${var.env_name}-ldap" -# encrypted = true -# kms_key_id = var.account_config.general_shared_kms_key_arn -# throughput_mode = var.ldap_config.efs_throughput_mode -# provisioned_throughput_in_mibps = var.ldap_config.efs_provisioned_throughput -# tags = merge( -# local.tags, -# { -# Name = "ldap-efs-${var.env_name}" -# } -# ) -# } - -# resource "aws_efs_mount_target" "ldap" { -# for_each = toset(var.account_config.private_subnet_ids) -# file_system_id = aws_efs_file_system.ldap.id -# subnet_id = each.value -# security_groups = [ -# aws_security_group.ldap_efs.id, -# ] -# } - -# resource "aws_efs_access_point" "ldap" { -# file_system_id = aws_efs_file_system.ldap.id -# root_directory { -# path = "/" -# } -# tags = merge( -# local.tags, -# { -# Name = "${var.env_name}-ldap-efs-access-point" -# } -# ) -# } - -# resource "aws_security_group" "ldap_efs" { -# name = "ldap-efs-${var.env_name}" -# description = "Allow traffic between ldap service and efs in ${var.env_name}" -# vpc_id = var.account_info.vpc_id -# tags = merge( -# local.tags, -# { -# Name = "ldap-efs-${var.env_name}" -# } -# ) - -# # see https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group#recreating-a-security-group -# lifecycle { -# create_before_destroy = true -# } - -# } - -# resource "aws_security_group_rule" "efs_ingress" { -# type = "ingress" -# from_port = 2049 -# to_port = 2049 -# protocol = "tcp" -# source_security_group_id = aws_security_group.ldap.id -# security_group_id = aws_security_group.ldap_efs.id -# } - -# resource "aws_security_group_rule" "efs_ingress_vpc" { -# type = "ingress" -# from_port = 2049 -# to_port = 2049 -# protocol = "tcp" -# cidr_blocks = [var.account_config.shared_vpc_cidr] -# security_group_id = aws_security_group.ldap_efs.id -# } - -# resource "aws_security_group_rule" "efs_egress" { -# type = "egress" -# from_port = 0 -# to_port = 0 -# protocol = "all" -# cidr_blocks = [var.account_config.shared_vpc_cidr] -# security_group_id = aws_security_group.ldap_efs.id -# } diff --git a/terraform/environments/delius-core/modules/environment_all_components/ldap_nlb.tf b/terraform/environments/delius-core/modules/environment_all_components/ldap_nlb.tf deleted file mode 100644 index 5589a9bbebe..00000000000 --- a/terraform/environments/delius-core/modules/environment_all_components/ldap_nlb.tf +++ /dev/null @@ -1,66 +0,0 @@ -# locals { -# ldap_name = "${var.env_name}-ldap" -# ldap_nlb_name = "${local.ldap_name}-nlb" -# ldap_nlb_tags = merge( -# local.tags, -# { -# Name = local.ldap_nlb_name -# } -# ) - -# ldap_protocol = "TCP" -# } - -# resource "aws_lb" "ldap" { -# name = local.ldap_nlb_name -# internal = true -# load_balancer_type = "network" -# subnets = var.account_config.private_subnet_ids -# drop_invalid_header_fields = true -# enable_deletion_protection = false - -# tags = local.ldap_nlb_tags -# } - -# resource "aws_lb_listener" "ldap" { -# load_balancer_arn = aws_lb.ldap.arn -# port = local.ldap_port -# protocol = local.ldap_protocol - -# default_action { -# type = "forward" -# target_group_arn = aws_lb_target_group.ldap.arn -# } - -# tags = local.ldap_nlb_tags -# } - -# resource "aws_lb_target_group" "ldap" { -# name = local.ldap_name -# port = local.ldap_port -# protocol = local.ldap_protocol -# vpc_id = var.account_info.vpc_id - -# target_type = "ip" -# deregistration_delay = "30" -# tags = merge( -# local.tags, -# { -# Name = local.ldap_name -# } -# ) -# } - -# # Internal DNS name for LDAP load balancer - Internal LDAP consumers will use this -# resource "aws_route53_record" "ldap_dns_internal" { -# provider = aws.core-vpc -# zone_id = var.account_config.route53_inner_zone_info.zone_id -# name = "${var.env_name}.ldap.${var.account_info.application_name}" -# type = "A" - -# alias { -# name = aws_lb.ldap.dns_name -# zone_id = aws_lb.ldap.zone_id -# evaluate_target_health = true # Could be true or false based on https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-values-alias.html#rrsets-values-alias-evaluate-target-health -# } -# } diff --git a/terraform/environments/delius-core/modules/environment_all_components/ldap_params.tf b/terraform/environments/delius-core/modules/environment_all_components/ldap_params.tf index 354fe85318d..7ca88bdecac 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/ldap_params.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/ldap_params.tf @@ -31,6 +31,10 @@ resource "aws_secretsmanager_secret_version" "delius_core_ldap_seed_uri" { } } +#################### +# LDAP HOST +#################### + resource "aws_ssm_parameter" "delius_core_ldap_host" { name = format("/%s-%s/LDAP_HOST", var.account_info.application_name, var.env_name) type = "SecureString" @@ -46,6 +50,7 @@ resource "aws_ssm_parameter" "delius_core_ldap_host" { #################### # LDAP PRINCIPAL #################### + resource "aws_ssm_parameter" "delius_core_ldap_principal" { name = format("/%s-%s/LDAP_PRINCIPAL", var.account_info.application_name, var.env_name) type = "SecureString" @@ -58,6 +63,34 @@ resource "aws_ssm_parameter" "delius_core_ldap_principal" { tags = local.tags } -data "aws_ssm_parameter" "delius_core_ldap_principal" { - name = aws_ssm_parameter.delius_core_ldap_principal.name +#################### +# LDAP SEED URI +#################### + +resource "aws_ssm_parameter" "delius_core_ldap_seed_uri" { + name = format("/%s-%s/LDAP_SEED_URI", var.account_info.application_name, var.env_name) + type = "SecureString" + value = "INITIAL_VALUE_OVERRIDDEN" + lifecycle { + ignore_changes = [ + value + ] + } + tags = local.tags +} + +#################### +# LDAP CREDENTIAL +#################### + +resource "aws_ssm_parameter" "delius_core_ldap_credential" { + name = format("/%s-%s/LDAP_CREDENTIAL", var.account_info.application_name, var.env_name) + type = "SecureString" + value = "INITIAL_VALUE_OVERRIDDEN" + lifecycle { + ignore_changes = [ + value + ] + } + tags = local.tags } diff --git a/terraform/environments/delius-core/modules/environment_all_components/ldap_s3.tf b/terraform/environments/delius-core/modules/environment_all_components/ldap_s3.tf deleted file mode 100644 index db886d0afb0..00000000000 --- a/terraform/environments/delius-core/modules/environment_all_components/ldap_s3.tf +++ /dev/null @@ -1,146 +0,0 @@ -# module "s3_bucket_migration" { - -# source = "github.com/ministryofjustice/modernisation-platform-terraform-s3-bucket?ref=v7.0.0" - -# providers = { -# aws.bucket-replication = aws.bucket-replication -# } - -# bucket_prefix = "${var.app_name}-${var.env_name}-ldap-" -# versioning_enabled = true -# sse_algorithm = "AES256" -# # Useful guide - https://aws.amazon.com/blogs/storage/how-to-use-aws-datasync-to-migrate-data-between-amazon-s3-buckets/ -# bucket_policy_v2 = [{ -# effect = "Allow" -# actions = [ -# "s3:GetBucketLocation", -# "s3:ListBucket", -# "s3:ListBucketMultipartUploads", -# "s3:AbortMultipartUpload", -# "s3:DeleteObject", -# "s3:GetObject", -# "s3:ListMultipartUploadParts", -# "s3:PutObject", -# "s3:GetObjectTagging", -# "s3:PutObjectTagging" -# ] -# principals = { -# type = "AWS" -# identifiers = [ -# "arn:aws:iam::${var.ldap_config.migration_source_account_id}:role/${var.ldap_config.migration_lambda_role}" -# ] -# } -# }, -# { -# effect = "Allow" -# actions = ["s3:ListBucket"] -# principals = { -# type = "AWS" -# identifiers = [ -# "arn:aws:iam::${var.ldap_config.migration_source_account_id}:role/terraform" -# ] -# } -# }, -# { -# effect = "Allow" -# actions = ["s3:ListBucket"] -# principals = { -# type = "AWS" -# identifiers = [ -# "arn:aws:iam::${var.ldap_config.migration_source_account_id}:role/admin" -# ] -# } -# }, -# { -# effect = "Allow" -# actions = [ -# "s3:GetObject", -# "s3:ListBucket" -# ] -# principals = { -# type = "AWS" -# identifiers = [ -# module.ldap_ecs_policies.task_role.arn -# ] -# } -# } -# ] - -# ownership_controls = "BucketOwnerEnforced" # Disable all S3 bucket ACL - -# lifecycle_rule = [ -# { -# id = "main" -# enabled = "Enabled" -# prefix = "" - -# tags = { -# rule = "log" -# autoclean = "true" -# } - -# noncurrent_version_transition = [ -# { -# days = 120 -# storage_class = "STANDARD_IA" -# }, { -# days = 180 -# storage_class = "GLACIER" -# } -# ] - -# noncurrent_version_expiration = { -# days = 365 -# } -# } -# ] - -# tags = merge( -# local.tags, -# { -# Name = "${var.env_name}-ldap-migration-s3-bucket" -# }, -# ) -# } - -# # Create s3 bucket for deployment state -# module "s3_bucket_app_deployment" { - -# source = "github.com/ministryofjustice/modernisation-platform-terraform-s3-bucket?ref=v7.0.0" - -# bucket_name = "${var.app_name}-${var.env_name}-openldap-deployment" -# versioning_enabled = true - -# providers = { -# aws.bucket-replication = aws.bucket-replication -# } - -# lifecycle_rule = [ -# { -# id = "main" -# enabled = "Enabled" -# prefix = "" - -# tags = { -# rule = "log" -# autoclean = "true" -# } - -# noncurrent_version_transition = [ -# { -# days = 90 -# storage_class = "STANDARD_IA" -# }, { -# days = 365 -# storage_class = "GLACIER" -# } -# ] - -# noncurrent_version_expiration = { -# days = 730 -# } -# } -# ] - -# tags = local.tags -# } diff --git a/terraform/environments/delius-core/modules/environment_all_components/locals.tf b/terraform/environments/delius-core/modules/environment_all_components/locals.tf index 4d26bd22f88..a7bf24267c1 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/locals.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/locals.tf @@ -1,6 +1,4 @@ locals { - ldap_port = 389 - tags = merge( var.tags, { diff --git a/terraform/environments/delius-core/modules/environment_all_components/merge_api_service.tf b/terraform/environments/delius-core/modules/environment_all_components/merge_api_service.tf index 2c9b3742152..c2a98f988af 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/merge_api_service.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/merge_api_service.tf @@ -30,7 +30,6 @@ module "merge_api_service" { tags = var.tags microservice_lb_arn = aws_lb.delius_core_frontend.arn microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn - alb_listener_rule_priority = 7 alb_listener_rule_paths = ["/merge/api", "/merge/api/*"] platform_vars = var.platform_vars container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-merge-api-ecr-repo:${var.merge_config.api_image_tag}" diff --git a/terraform/environments/delius-core/modules/environment_all_components/merge_ui_service.tf b/terraform/environments/delius-core/modules/environment_all_components/merge_ui_service.tf index cff7f66c084..d3cc68f35ba 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/merge_ui_service.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/merge_ui_service.tf @@ -17,7 +17,6 @@ module "merge_ui_service" { tags = var.tags microservice_lb_arn = aws_lb.delius_core_frontend.arn microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn - alb_listener_rule_priority = 8 alb_listener_rule_paths = ["/merge/ui", "/merge/ui/*"] platform_vars = var.platform_vars container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-merge-ui-ecr-repo:${var.merge_config.ui_image_tag}" diff --git a/terraform/environments/delius-core/modules/environment_all_components/password_reset_service.tf b/terraform/environments/delius-core/modules/environment_all_components/password_reset_service.tf new file mode 100644 index 00000000000..0a319a64dd3 --- /dev/null +++ b/terraform/environments/delius-core/modules/environment_all_components/password_reset_service.tf @@ -0,0 +1,74 @@ +module "password_reset_service" { + source = "../components/delius_microservice" + + name = "password-reset" + certificate_arn = local.certificate_arn + alb_security_group_id = aws_security_group.delius_frontend_alb_security_group.id + env_name = var.env_name + container_port_config = [ + { + containerPort = 8080 + protocol = "tcp" + } + ] + + ecs_cluster_arn = module.ecs.ecs_cluster_arn + container_secrets = [ + { + name = "SECURITY_KEY" + valueFrom = "REPLACE" + # "/${var.environment_name}/${var.project_name}/pwm/pwm/security_key" + }, + { + name = "CONFIG_PASSWORD" + valueFrom = aws_ssm_parameter.delius_core_pwm_config_password.arn + #value = "/${var.environment_name}/${var.project_name}/pwm/pwm/config_password" + }, + { + name = "LDAP_PASSWORD" + valueFrom = aws_ssm_parameter.ldap_admin_password.arn + #value = "/${var.environment_name}/${var.project_name}/apacheds/apacheds/ldap_admin_password" + } + ] + ingress_security_groups = [] + tags = var.tags + microservice_lb_arn = aws_lb.delius_core_frontend.arn + microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn + #TODO - check the path based routing based on shared ALB or dedicated + alb_listener_rule_paths = ["/password-reset"] + platform_vars = var.platform_vars + container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-password-management-ecr-repo:${var.pwm_config.image_tag}" + account_config = var.account_config + #TODO check the health end-point + health_check_path = "/pwm/actuator/health" + account_info = var.account_info + + container_environment_vars = [ + { + name = "CONFIG_XML_BASE64" + value = base64encode(templatefile("${path.module}/templates/PwmConfiguration.xml.tpl", { + region = var.account_info["region"] + ldap_url = "ldap://${module.ldap.nlb_dns_name}:${var.ldap_config.port}" + ldap_user = aws_ssm_parameter.delius_core_ldap_principal.arn + user_base = "REPLACE" + # site_url = "https://${aws_route53_record.public_dns.fqdn}" + site_url = "REPLACE" + # email_smtp_address = "smtp.${data.terraform_remote_state.vpc.outputs.private_zone_name}" + email_smtp_address = "REPLACE" + # email_from_address = "no-reply@${data.terraform_remote_state.vpc.outputs.public_zone_name}" + email_from_address = "REPLACE" + })) + } + ] +} + +#TODO move this to variable after merge + +variable "pwm_config" { + type = object({ + image_tag = string + }) + default = { + image_tag = "default_image_tag" + } +} diff --git a/terraform/environments/delius-core/modules/environment_all_components/templates/PwmConfiguration.xml.tpl b/terraform/environments/delius-core/modules/environment_all_components/templates/PwmConfiguration.xml.tpl new file mode 100644 index 00000000000..d423e955ab8 --- /dev/null +++ b/terraform/environments/delius-core/modules/environment_all_components/templates/PwmConfiguration.xml.tpl @@ -0,0 +1,167 @@ + + + + + + + + + + + true + $${PWM_CONFIG_PASSWORD_HASH} + false + 1 + + + + + $${SECURITY_KEY} + + + + + + + + + + + + + + + + + + + + + + + + $${LDAP_PASSWORD} + + + + + + + + + + + + + + + + {"ldapBase":"${user_base}","ldapQuery":"(pwmAdmin=TRUE)","type":"ldapQuery"} + + + + false + + + + + + + + + + + + + + + + false + + + + true + + + + true + + + + PasswordSetTime + PasswordSetTimeDelta + PasswordViolatesPolicy + UserEmail + UserSMS + Username + + + + + + + + false + + + + false + + + + + + + + 8 + + + + true + + + + true + + + + + + + + + + + + false + + + + + + + + + + + + + + + + true + + + + false + + + + false + + + + + + + diff --git a/terraform/environments/delius-core/modules/environment_all_components/user_management.tf b/terraform/environments/delius-core/modules/environment_all_components/user_management.tf new file mode 100644 index 00000000000..b3790e949b3 --- /dev/null +++ b/terraform/environments/delius-core/modules/environment_all_components/user_management.tf @@ -0,0 +1,44 @@ +module "user_management" { + source = "../components/delius_microservice" + account_config = var.account_config + account_info = var.account_info + alb_security_group_id = aws_security_group.delius_frontend_alb_security_group.id + certificate_arn = aws_acm_certificate.external.arn + container_environment_vars = [ + ] + container_secrets = [ + ] + container_port_config = [ + { + containerPort = var.user_management_config.container_port + protocol = "tcp" + } + ] + + name = "user-management" + env_name = var.env_name + + ecs_cluster_arn = module.ecs.ecs_cluster_arn + container_memory = var.user_management_config.container_memory + container_cpu = var.user_management_config.container_cpu + + health_check_path = "/umt" + health_check_grace_period_seconds = 600 + health_check_interval = 30 + + ingress_security_groups = [] + + microservice_lb_arn = aws_lb.delius_core_frontend.arn + microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn + alb_listener_rule_paths = ["/umt"] + + container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-user-management-ecr-repo:${var.user_management_config.image_tag}" + + platform_vars = var.platform_vars + tags = var.tags +} + + +####################### +# User management EIS Params # +####################### \ No newline at end of file diff --git a/terraform/environments/delius-core/modules/environment_all_components/variables.tf b/terraform/environments/delius-core/modules/environment_all_components/variables.tf index 501db37eef5..83a385fd4a4 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/variables.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/variables.tf @@ -85,6 +85,11 @@ variable "weblogic_eis_config" { type = any } +variable "user_management_config" { + type = any +} + + variable "tags" { type = any } @@ -103,4 +108,23 @@ variable "bastion_config" { variable "environments_in_account" { type = list(string) default = [] -} \ No newline at end of file +} + +variable "community_api" { + type = object({ + name = string + image_tag = string + container_port = number + host_port = number + protocol = string + db_name = string + }) + default = { + name = "community-api" + image_tag = "default_image_tag" + container_port = 8080 + host_port = 8080 + protocol = "tcp" + db_name = "default_db_name" + } +} diff --git a/terraform/environments/delius-core/modules/environment_all_components/weblogic.tf b/terraform/environments/delius-core/modules/environment_all_components/weblogic.tf index 55e95090ca1..6381f19e103 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/weblogic.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/weblogic.tf @@ -7,7 +7,7 @@ module "weblogic" { container_environment_vars = [ { name = "LDAP_PORT" - value = local.ldap_port + value = var.ldap_config.port }, { name = "LDAP_HOST" @@ -47,10 +47,10 @@ module "weblogic" { ecs_cluster_arn = module.ecs.ecs_cluster_arn env_name = var.env_name health_check_path = "/NDelius-war/delius/JSP/healthcheck.jsp?ping" - ingress_security_groups = [] microservice_lb_arn = aws_lb.delius_core_frontend.arn name = "weblogic" container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-weblogic-ecr-repo:${var.weblogic_config.image_tag}" platform_vars = var.platform_vars tags = var.tags + ingress_security_groups = [] } diff --git a/terraform/environments/delius-core/modules/environment_all_components/weblogic_eis.tf b/terraform/environments/delius-core/modules/environment_all_components/weblogic_eis.tf index b20c6341871..51fabdce862 100644 --- a/terraform/environments/delius-core/modules/environment_all_components/weblogic_eis.tf +++ b/terraform/environments/delius-core/modules/environment_all_components/weblogic_eis.tf @@ -7,7 +7,7 @@ module "weblogic_eis" { container_environment_vars = [ { name = "LDAP_PORT" - value = local.ldap_port + value = var.ldap_config.port }, { name = "LDAP_HOST" @@ -187,7 +187,6 @@ module "weblogic_eis" { microservice_lb_arn = aws_lb.delius_core_frontend.arn microservice_lb_https_listener_arn = aws_lb_listener.listener_https.arn - alb_listener_rule_priority = 10 alb_listener_rule_paths = ["/eis"] container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-weblogic-eis-ecr-repo:${var.weblogic_eis_config.image_tag}" diff --git a/terraform/environments/delius-core/modules/environment_all_components/weblogic_service.tf b/terraform/environments/delius-core/modules/environment_all_components/weblogic_service.tf deleted file mode 100644 index 343997c98e5..00000000000 --- a/terraform/environments/delius-core/modules/environment_all_components/weblogic_service.tf +++ /dev/null @@ -1,203 +0,0 @@ -#module "weblogic_container" { -# source = "git::https://github.com/cloudposse/terraform-aws-ecs-container-definition.git?ref=tags/0.59.0" -# container_name = "${var.env_name}-weblogic" -# container_image = "${var.platform_vars.environment_management.account_ids["core-shared-services-production"]}.dkr.ecr.eu-west-2.amazonaws.com/delius-core-weblogic-ecr-repo:${var.weblogic_config.frontend_image_tag}" -# container_memory = 4096 -# container_cpu = 1024 -# essential = true -# readonly_root_filesystem = false -# environment = [ -# { -# name = "LDAP_PORT" -# value = local.ldap_port -# }, -# { -# name = "LDAP_HOST" -# value = aws_lb.ldap.dns_name -# } -# ] -# secrets = [ -# { -# name = "JDBC_URL" -# valueFrom = aws_ssm_parameter.delius_core_frontend_env_var_jdbc_url.arn -# }, -# { -# name = "JDBC_PASSWORD" -# valueFrom = aws_ssm_parameter.delius_core_frontend_env_var_jdbc_password.arn -# }, -# { -# name = "TEST_MODE" -# valueFrom = aws_ssm_parameter.delius_core_frontend_env_var_test_mode.arn -# }, -# { -# name = "LDAP_PRINCIPAL" -# valueFrom = aws_ssm_parameter.delius_core_ldap_principal.arn -# }, -# { name = "LDAP_CREDENTIAL" -# valueFrom = aws_secretsmanager_secret.delius_core_ldap_credential.arn -# }, -# { -# name = "USER_CONTEXT" -# valueFrom = data.aws_ssm_parameter.delius_core_frontend_env_var_user_context.arn -# }, -# { -# name = "EIS_USER_CONTEXT" -# valueFrom = data.aws_ssm_parameter.delius_core_frontend_env_var_eis_user_context.arn -# } -# ] -# port_mappings = [ -# { -# containerPort = var.weblogic_config.frontend_container_port -# hostPort = var.weblogic_config.frontend_container_port -# protocol = "tcp" -# }, -# ] -# log_configuration = { -# logDriver = "awslogs" -# options = { -# "awslogs-group" = aws_cloudwatch_log_group.delius_core_frontend_log_group.name -# "awslogs-region" = "eu-west-2" -# "awslogs-stream-prefix" = var.weblogic_config.frontend_fully_qualified_name -# } -# } -#} -# -#module "weblogic_ecs_policies" { -# source = "../ecs_policies" -# env_name = var.env_name -# service_name = "weblogic" -# tags = local.tags -#} -# -#module "weblogic_service" { -# source = "git::https://github.com/ministryofjustice/modernisation-platform-terraform-ecs-cluster//service?ref=c195026bcf0a1958fa4d3cc2efefc56ed876507e" -# container_definition_json = module.weblogic_container.json_map_encoded_list -# ecs_cluster_arn = module.ecs.ecs_cluster_arn -# name = "weblogic" -# vpc_id = var.account_config.shared_vpc_id -# -# launch_type = "FARGATE" -# network_mode = "awsvpc" -# -# task_cpu = "1024" -# task_memory = "4096" -# -# # terraform will not let you use module.weblogic_ecs_policies.service_role.arn as it is not created yet and can't evaluate the count in this module -# service_role_arn = "arn:aws:iam::${var.account_info.id}:role/${module.weblogic_ecs_policies.service_role.name}" -# task_role_arn = "arn:aws:iam::${var.account_info.id}:role/${module.weblogic_ecs_policies.task_role.name}" -# task_exec_role_arn = "arn:aws:iam::${var.account_info.id}:role/${module.weblogic_ecs_policies.task_exec_role.name}" -# -# environment = var.env_name -# namespace = var.app_name -# -# health_check_grace_period_seconds = 0 -# -# ecs_load_balancers = [ -# { -# target_group_arn = aws_lb_target_group.delius_core_frontend_target_group.id -# container_name = "${var.env_name}-weblogic" -# container_port = var.weblogic_config.frontend_container_port -# } -# ] -# -# security_group_ids = [aws_security_group.weblogic_service.id] -# -# subnet_ids = var.account_config.private_subnet_ids -# -# exec_enabled = true -# -# ignore_changes_task_definition = true -# redeploy_on_apply = false -# force_new_deployment = false -#} -# -#resource "aws_security_group" "weblogic_service" { -# name = format("%s - Delius Core Weblogic service", var.env_name) -# description = "Security group for the ${var.env_name} weblogic service" -# vpc_id = var.account_info.vpc_id -# tags = local.tags -# lifecycle { -# create_before_destroy = true -# } -#} -# -#resource "aws_vpc_security_group_egress_rule" "delius_core_weblogic_to_db" { -# security_group_id = aws_security_group.weblogic_service.id -# description = "weblogic service to db" -# from_port = var.delius_db_container_config.port -# to_port = var.delius_db_container_config.port -# ip_protocol = "tcp" -# referenced_security_group_id = module.oracle_db_shared.security_group.id -#} -# -#resource "aws_vpc_security_group_ingress_rule" "delius_core_frontend_ldap_tcp" { -# security_group_id = aws_security_group.weblogic_service.id -# description = "ingress from ldap server tcp" -# from_port = local.ldap_port -# to_port = local.ldap_port -# ip_protocol = "tcp" -# cidr_ipv4 = var.account_config.shared_vpc_cidr -#} -# -#resource "aws_vpc_security_group_ingress_rule" "delius_core_frontend_ldap_udp" { -# security_group_id = aws_security_group.weblogic_service.id -# description = "ingress from ldap server udp" -# from_port = local.ldap_port -# to_port = local.ldap_port -# ip_protocol = "udp" -# cidr_ipv4 = var.account_config.shared_vpc_cidr -#} -# -# -#resource "aws_vpc_security_group_egress_rule" "delius_core_frontend_security_group_ldap_tcp" { -# security_group_id = aws_security_group.weblogic_service.id -# description = "ldap tcp outbound from weblogic" -# ip_protocol = "tcp" -# to_port = local.ldap_port -# from_port = local.ldap_port -# cidr_ipv4 = var.account_config.shared_vpc_cidr -#} -# -#resource "aws_vpc_security_group_egress_rule" "delius_core_frontend_security_group_ldap_udp" { -# security_group_id = aws_security_group.weblogic_service.id -# description = "ldap udp outbound from weblogic" -# ip_protocol = "udp" -# to_port = local.ldap_port -# from_port = local.ldap_port -# cidr_ipv4 = var.account_config.shared_vpc_cidr -#} -# -#resource "aws_vpc_security_group_ingress_rule" "alb_to_weblogic" { -# security_group_id = aws_security_group.weblogic_service.id -# description = "load balancer to weblogic frontend" -# from_port = var.weblogic_config.frontend_container_port -# to_port = var.weblogic_config.frontend_container_port -# ip_protocol = "tcp" -# referenced_security_group_id = aws_security_group.delius_frontend_alb_security_group.id -#} -# -#resource "aws_security_group_rule" "weblogic_allow_all_egress" { -# description = "Allow all outbound traffic to any IPv4 address on 443" -# type = "egress" -# from_port = 443 -# to_port = 443 -# protocol = "tcp" -# cidr_blocks = ["0.0.0.0/0"] -# security_group_id = aws_security_group.weblogic_service.id -#} -# -#resource "aws_security_group_rule" "weblogic_alb" { -# description = "Allow inbound traffic from VPC" -# type = "ingress" -# from_port = var.weblogic_config.frontend_container_port -# to_port = var.weblogic_config.frontend_container_port -# protocol = "TCP" -# security_group_id = aws_security_group.ldap.id -# cidr_blocks = [var.account_config.shared_vpc_cidr] -#} -# -#resource "aws_cloudwatch_log_group" "delius_core_frontend_log_group" { -# name = var.weblogic_config.frontend_fully_qualified_name -# retention_in_days = 7 -# tags = local.tags -#} diff --git a/terraform/environments/delius-mis/application_variables.json b/terraform/environments/delius-mis/application_variables.json index 6b52bfe9b30..43a51f9b609 100644 --- a/terraform/environments/delius-mis/application_variables.json +++ b/terraform/environments/delius-mis/application_variables.json @@ -1,7 +1,7 @@ { "accounts": { "development": { - "example_var": "dev-data" + "legacy_counterpart_cidr": "10.162.32.0/20" }, "test": { "example_var": "test-data" diff --git a/terraform/environments/delius-mis/temp-ec2.tf b/terraform/environments/delius-mis/temp-ec2.tf new file mode 100644 index 00000000000..1c62db8515c --- /dev/null +++ b/terraform/environments/delius-mis/temp-ec2.tf @@ -0,0 +1,68 @@ +# Example security group with rules required for connectivity with legacy +resource "aws_security_group" "example" { + name = "example" + description = "Example SG for legacy connectivity" + vpc_id = data.aws_vpc.shared.id + tags = merge(local.tags, + { Name = lower(format("sg-%s-%s-example", local.application_name, local.environment)) } + ) +} + +resource "aws_vpc_security_group_ingress_rule" "icmp" { + security_group_id = aws_security_group.example.id + cidr_ipv4 = local.application_data.accounts[local.environment].legacy_counterpart_cidr + ip_protocol = "icmp" + from_port = -1 + to_port = -1 +} + +resource "aws_vpc_security_group_egress_rule" "icmp" { + security_group_id = aws_security_group.example.id + cidr_ipv4 = local.application_data.accounts[local.environment].legacy_counterpart_cidr + ip_protocol = "icmp" + from_port = -1 + to_port = -1 +} + +resource "aws_vpc_security_group_egress_rule" "http" { + for_each = toset(["80", "443"]) + + security_group_id = aws_security_group.example.id + cidr_ipv4 = "0.0.0.0/0" + ip_protocol = "tcp" + from_port = each.key + to_port = each.key +} + +resource "aws_vpc_security_group_egress_rule" "oracle_db" { + for_each = toset(["1521"]) + + description = "Legacy Oracle DB" + security_group_id = aws_security_group.example.id + cidr_ipv4 = local.application_data.accounts[local.environment].legacy_counterpart_cidr + ip_protocol = "tcp" + from_port = each.key + to_port = each.key +} + +resource "aws_vpc_security_group_egress_rule" "ad_tcp" { + for_each = toset(["53", "88", "135", "389", "445", "464", "636"]) + + description = "Legacy AD TCP" + security_group_id = aws_security_group.example.id + cidr_ipv4 = local.application_data.accounts[local.environment].legacy_counterpart_cidr + ip_protocol = "tcp" + from_port = each.key + to_port = each.key +} + +resource "aws_vpc_security_group_egress_rule" "ad_udp" { + for_each = toset(["53", "88", "123", "138", "389", "445","464"]) + + description = "Legacy AD UDP" + security_group_id = aws_security_group.example.id + cidr_ipv4 = local.application_data.accounts[local.environment].legacy_counterpart_cidr + ip_protocol = "udp" + from_port = each.key + to_port = each.key +} diff --git a/terraform/environments/digital-prison-reporting/application_variables.json b/terraform/environments/digital-prison-reporting/application_variables.json index ad6f70e2aed..38cb880fcc1 100644 --- a/terraform/environments/digital-prison-reporting/application_variables.json +++ b/terraform/environments/digital-prison-reporting/application_variables.json @@ -85,13 +85,9 @@ "enable_dms_replication_task": true, "enable_domain_builder_lambda": true, "enable_dbuilder_flyway_lambda": true, - "enable_s3_file_transfer_lambda": true, "enable_s3_file_transfer_trigger": true, "scheduled_s3_file_transfer_retention_days": 2, "scheduled_s3_file_transfer_schedule": "cron(0 0/3 ? * * *)", - "enable_step_function_notification_lambda": true, - "enable_data_ingestion_step_function": true, - "dms_task_time_out": 28800, "enable_domain_builder_rds": true, "enable_domain_builder_agent": true, "enable_cloud_trail": false, @@ -261,13 +257,9 @@ "enable_dms_replication_task": true, "enable_domain_builder_lambda": true, "enable_dbuilder_flyway_lambda": true, - "enable_s3_file_transfer_lambda": true, "enable_s3_file_transfer_trigger": true, "scheduled_s3_file_transfer_retention_days": 2, "scheduled_s3_file_transfer_schedule": "cron(0 0/3 ? * * *)", - "enable_step_function_notification_lambda": true, - "enable_data_ingestion_step_function": true, - "dms_task_time_out": 28800, "enable_domain_builder_rds": true, "enable_domain_builder_agent": true, "enable_cloud_trail": false, @@ -437,13 +429,9 @@ "enable_dms_replication_task": true, "enable_domain_builder_lambda": true, "enable_dbuilder_flyway_lambda": true, - "enable_s3_file_transfer_lambda": true, "enable_s3_file_transfer_trigger": true, "scheduled_s3_file_transfer_retention_days": 2, "scheduled_s3_file_transfer_schedule": "cron(0 0/3 ? * * *)", - "enable_step_function_notification_lambda": true, - "enable_data_ingestion_step_function": true, - "dms_task_time_out": 28800, "enable_domain_builder_rds": true, "enable_domain_builder_agent": true, "enable_cloud_trail": false, @@ -615,13 +603,9 @@ "enable_dms_replication_task": true, "enable_domain_builder_lambda": true, "enable_dbuilder_flyway_lambda": true, - "enable_s3_file_transfer_lambda": true, "enable_s3_file_transfer_trigger": true, "scheduled_s3_file_transfer_retention_days": 2, "scheduled_s3_file_transfer_schedule": "cron(0 0/3 ? * * *)", - "enable_step_function_notification_lambda": true, - "enable_data_ingestion_step_function": true, - "dms_task_time_out": 28800, "enable_domain_builder_rds": true, "enable_domain_builder_agent": true, "enable_cloud_trail": false, diff --git a/terraform/environments/digital-prison-reporting/data_ingestion_pipeline.tf b/terraform/environments/digital-prison-reporting/data_ingestion_pipeline.tf deleted file mode 100644 index 318da7705d2..00000000000 --- a/terraform/environments/digital-prison-reporting/data_ingestion_pipeline.tf +++ /dev/null @@ -1,187 +0,0 @@ -# Lambda which notifies step function when DMS task stops -module "step_function_notification_lambda" { - source = "./modules/lambdas/generic" - - enable_lambda = local.enable_step_function_notification_lambda - name = local.step_function_notification_lambda_name - s3_bucket = local.step_function_notification_lambda_code_s3_bucket - s3_key = local.reporting_lambda_code_s3_key - handler = local.step_function_notification_lambda_handler - runtime = local.step_function_notification_lambda_runtime - policies = local.step_function_notification_lambda_policies - tracing = local.step_function_notification_lambda_tracing - timeout = 300 # 5 minutes - - vpc_settings = { - subnet_ids = [ - data.aws_subnet.data_subnets_a.id, - data.aws_subnet.data_subnets_b.id, - data.aws_subnet.data_subnets_c.id - ] - - security_group_ids = [ - aws_security_group.lambda_generic[0].id - ] - } - - tags = merge( - local.all_tags, - { - Resource_Group = "ingestion-pipeline" - Jira = "DPR2-209" - Resource_Type = "Lambda" - Name = local.step_function_notification_lambda_name - } - ) - - depends_on = [ - aws_iam_policy.kms_read_access_policy, - aws_iam_policy.dynamodb_access_policy, - aws_iam_policy.all_state_machine_policy - ] -} - -module "step_function_notification_lambda_trigger" { - source = "./modules/lambda_trigger" - - enable_lambda_trigger = local.enable_step_function_notification_lambda - - event_name = "${local.project}-step-function-notification-${local.env}" - lambda_function_arn = module.step_function_notification_lambda.lambda_function - lambda_function_name = module.step_function_notification_lambda.lambda_name - - trigger_event_pattern = jsonencode( - { - "source" : ["aws.dms"], - "detail-type" : ["DMS Replication Task State Change"], - "detail" : { - "eventId" : ["DMS-EVENT-0079"] - } - } - ) - - depends_on = [ - module.step_function_notification_lambda - ] -} - -# Data Ingest Pipeline Step Function -module "data_ingestion_pipeline" { - source = "./modules/step_function" - - enable_step_function = local.enable_data_ingestion_step_function - step_function_name = local.data_ingestion_step_function_name - dms_task_time_out = local.dms_task_time_out - - additional_policies = [ - "arn:aws:iam::${local.account_id}:policy/${aws_iam_policy.invoke_lambda_policy.name}", - "arn:aws:iam::${local.account_id}:policy/${aws_iam_policy.start_dms_task_policy.name}", - "arn:aws:iam::${local.account_id}:policy/${aws_iam_policy.trigger_glue_job_policy.name}" - ] - - depends_on = [ - aws_iam_policy.invoke_lambda_policy, - aws_iam_policy.start_dms_task_policy, - aws_iam_policy.trigger_glue_job_policy, - module.dms_nomis_to_s3_ingestor.dms_replication_task_arn, - module.glue_reporting_hub_batch_job.name, - module.glue_reporting_hub_cdc_job.name, - module.glue_hive_table_creation_job.name, - module.step_function_notification_lambda.lambda_function - ] - - definition = jsonencode( - { - "Comment" : "Data Ingestion Pipeline Step Function", - "StartAt" : "Start DMS Replication Task", - "States" : { - "Start DMS Replication Task" : { - "Type" : "Task", - "Resource" : "arn:aws:states:::aws-sdk:databasemigration:startReplicationTask", - "Parameters" : { - "ReplicationTaskArn" : "${module.dms_nomis_to_s3_ingestor.dms_replication_task_arn}", - "StartReplicationTaskType" : "reload-target" - }, - "Next" : "Invoke DMS State Control Lambda" - }, - "Invoke DMS State Control Lambda" : { - "Type" : "Task", - "TimeoutSeconds" : local.dms_task_time_out, - "Resource" : "arn:aws:states:::lambda:invoke.waitForTaskToken", - "Parameters" : { - "Payload" : { - "token.$" : "$$.Task.Token", - "replicationTaskArn" : "${module.dms_nomis_to_s3_ingestor.dms_replication_task_arn}" - }, - "FunctionName" : "${module.step_function_notification_lambda.lambda_function}" - }, - "Retry" : [ - { - "ErrorEquals" : [ - "Lambda.ServiceException", - "Lambda.AWSLambdaException", - "Lambda.SdkClientException", - "Lambda.TooManyRequestsException" - ], - "IntervalSeconds" : 60, - "MaxAttempts" : 2, - "BackoffRate" : 2 - } - ], - "Next" : "Start Glue Batch Job" - }, - "Start Glue Batch Job" : { - "Type" : "Task", - "Resource" : "arn:aws:states:::glue:startJobRun.sync", - "Parameters" : { - "JobName" : module.glue_reporting_hub_batch_job.name - }, - "Next" : "Archive Raw Data" - }, - "Archive Raw Data" : { - "Type" : "Task", - "Resource" : "arn:aws:states:::glue:startJobRun.sync", - "Parameters" : { - "JobName" : module.glue_s3_file_transfer_job.name, - "Arguments" : { - "--dpr.file.transfer.source.bucket" : module.s3_raw_bucket.bucket_id, - "--dpr.file.transfer.destination.bucket" : module.s3_raw_archive_bucket.bucket_id, - "--dpr.file.transfer.retention.days" : "0", - "--dpr.file.transfer.delete.copied.files" : "true", - "--dpr.allowed.s3.file.extensions" : ".parquet", - "--dpr.config.s3.bucket" : module.s3_glue_job_bucket.bucket_id - } - }, - "Next" : "Create Hive Tables" - }, - "Create Hive Tables" : { - "Type" : "Task", - "Resource" : "arn:aws:states:::glue:startJobRun.sync", - "Parameters" : { - "JobName" : "${module.glue_hive_table_creation_job.name}" - }, - "Next" : "Resume DMS Replication Task" - }, - "Resume DMS Replication Task" : { - "Type" : "Task", - "Resource" : "arn:aws:states:::aws-sdk:databasemigration:startReplicationTask", - "Parameters" : { - "ReplicationTaskArn" : "${module.dms_nomis_to_s3_ingestor.dms_replication_task_arn}", - "StartReplicationTaskType" : "resume-processing" - }, - "Next" : "Start Glue Streaming Job" - }, - "Start Glue Streaming Job" : { - "Type" : "Task", - "Resource" : "arn:aws:states:::glue:startJobRun", - "Parameters" : { - "JobName" : "${module.glue_reporting_hub_cdc_job.name}" - }, - "End" : true - } - } - } - ) - - -} \ No newline at end of file diff --git a/terraform/environments/digital-prison-reporting/locals.tf b/terraform/environments/digital-prison-reporting/locals.tf index 050bd673fab..0ccd80f41a8 100644 --- a/terraform/environments/digital-prison-reporting/locals.tf +++ b/terraform/environments/digital-prison-reporting/locals.tf @@ -223,43 +223,18 @@ locals { reporting_lambda_code_s3_key = "build-artifacts/digital-prison-reporting-lambdas/jars/digital-prison-reporting-lambdas-vLatest-all.jar" # s3 transfer - enable_s3_file_transfer_lambda = local.application_data.accounts[local.environment].enable_s3_file_transfer_lambda - s3_file_transfer_lambda_name = "${local.project}-s3-file-transfer" - s3_file_transfer_lambda_handler = "uk.gov.justice.digital.lambda.S3FileTransferLambda::handleRequest" - s3_file_transfer_lambda_code_s3_bucket = module.s3_artifacts_store.bucket_id - s3_file_transfer_lambda_runtime = "java11" - s3_file_transfer_lambda_tracing = "Active" - scheduled_s3_file_transfer_retention_days = local.application_data.accounts[local.environment].scheduled_s3_file_transfer_retention_days scheduled_s3_file_transfer_schedule = local.application_data.accounts[local.environment].scheduled_s3_file_transfer_schedule enable_s3_file_transfer_trigger = local.application_data.accounts[local.environment].enable_s3_file_transfer_trigger - s3_file_transfer_lambda_policies = [ - "arn:aws:iam::${local.account_id}:policy/${local.s3_all_object_actions_policy}", - "arn:aws:iam::${local.account_id}:policy/${local.kms_read_access_policy}", - "arn:aws:iam::${local.account_id}:policy/${local.s3_read_access_policy}", - "arn:aws:iam::${local.account_id}:policy/${local.all_state_machine_policy}" - ] - # step function notification lambda - enable_step_function_notification_lambda = local.application_data.accounts[local.environment].enable_step_function_notification_lambda - step_function_notification_lambda_name = "${local.project}-step-function-notification" - step_function_notification_lambda_handler = "uk.gov.justice.digital.lambda.StepFunctionDMSNotificationLambda::handleRequest" - step_function_notification_lambda_code_s3_bucket = module.s3_artifacts_store.bucket_id - step_function_notification_lambda_runtime = "java11" - step_function_notification_lambda_tracing = "Active" - + step_function_notification_lambda_handler = "uk.gov.justice.digital.lambda.StepFunctionDMSNotificationLambda::handleRequest" step_function_notification_lambda_policies = [ "arn:aws:iam::${local.account_id}:policy/${local.kms_read_access_policy}", "arn:aws:iam::${local.account_id}:policy/${local.all_state_machine_policy}", "arn:aws:iam::${local.account_id}:policy/${local.dynamo_db_access_policy}" ] - # Data Ingestion Pipeline Step Function - enable_data_ingestion_step_function = local.application_data.accounts[local.environment].enable_data_ingestion_step_function - data_ingestion_step_function_name = "${local.project}-data-ingestion-step-function-${local.environment}" - dms_task_time_out = local.application_data.accounts[local.environment].dms_task_time_out - # Datamart create_scheduled_action_iam_role = local.application_data.accounts[local.environment].setup_scheduled_action_iam_role create_redshift_schedule = local.application_data.accounts[local.environment].setup_redshift_schedule diff --git a/terraform/environments/digital-prison-reporting/main.tf b/terraform/environments/digital-prison-reporting/main.tf index 043e122ddf3..9e2363babb2 100644 --- a/terraform/environments/digital-prison-reporting/main.tf +++ b/terraform/environments/digital-prison-reporting/main.tf @@ -191,14 +191,14 @@ module "glue_reporting_hub_cdc_job" { module "glue_hive_table_creation_job" { source = "./modules/glue_job" create_job = local.create_job - name = "${local.project}-hive_table_creation-${local.env}" - short_name = "${local.project}-hive_table_creation" + name = "${local.project}-hive-table-creation-${local.env}" + short_name = "${local.project}-hive-table-creation" command_type = "glueetl" - description = "Creates Hive tables for schemas in the registry" + description = "Creates Hive tables for schemas in the registry.\nArguments:\n--dpr.config.key: (Optional) config key e.g. prisoner" create_security_configuration = local.create_sec_conf job_language = "scala" - temp_dir = "s3://${module.s3_glue_job_bucket.bucket_id}/tmp/${local.project}-hive_table_creation-${local.env}/" - spark_event_logs = "s3://${module.s3_glue_job_bucket.bucket_id}/spark-logs/${local.project}-hive_table_creation-${local.env}/" + temp_dir = "s3://${module.s3_glue_job_bucket.bucket_id}/tmp/${local.project}-hive-table-creation-${local.env}/" + spark_event_logs = "s3://${module.s3_glue_job_bucket.bucket_id}/spark-logs/${local.project}-hive-table-creation-${local.env}/" # Placeholder Script Location script_location = local.glue_placeholder_script_location enable_continuous_log_filter = false @@ -216,7 +216,7 @@ module "glue_hive_table_creation_job" { tags = merge( local.all_tags, { - Name = "${local.project}-hive_table_creation-${local.env}" + Name = "${local.project}-hive-table-creation-${local.env}" Resource_Type = "Glue Job" Jira = "DPR2-209" } @@ -227,7 +227,6 @@ module "glue_hive_table_creation_job" { "--class" = "uk.gov.justice.digital.job.HiveTableCreationJob" "--dpr.aws.region" = local.account_region "--dpr.config.s3.bucket" = module.s3_glue_job_bucket.bucket_id, - # "--dpr.config.key" = "(Required) config key. Will be specified at point of call in the reload step-functions" "--dpr.raw.archive.s3.path" = "s3://${module.s3_raw_archive_bucket.bucket_id}" "--dpr.structured.s3.path" = "s3://${module.s3_structured_bucket.bucket_id}" "--dpr.curated.s3.path" = "s3://${module.s3_curated_bucket.bucket_id}" @@ -260,7 +259,7 @@ module "glue_s3_file_transfer_job" { name = "${local.project}-s3-file-transfer-job-${local.env}" short_name = "${local.project}-s3-file-transfer-job" command_type = "glueetl" - description = "Transfers s3 data from one bucket to another" + description = "Transfers s3 data from one bucket to another.\nArguments:\n(Optional) config key e.g prisoner, when provided, the job will only transfer data belonging to specified config otherwise all data will be transferred" create_security_configuration = local.create_sec_conf job_language = "scala" temp_dir = "s3://${module.s3_glue_job_bucket.bucket_id}/tmp/${local.project}-s3-file-transfer-${local.env}/" @@ -293,7 +292,6 @@ module "glue_s3_file_transfer_job" { "--class" = "uk.gov.justice.digital.job.S3FileTransferJob" "--dpr.aws.region" = local.account_region "--dpr.config.s3.bucket" = module.s3_glue_job_bucket.bucket_id, - # "--dpr.config.key" = "(Optional) config key, when provided, the job will only transfer data belonging to config otherwise all data will be transferred" "--dpr.file.transfer.source.bucket" = module.s3_raw_bucket.bucket_id "--dpr.file.transfer.destination.bucket" = module.s3_raw_archive_bucket.bucket_id "--dpr.file.transfer.retention.days" = tostring(local.scheduled_s3_file_transfer_retention_days) @@ -310,6 +308,7 @@ module "glue_s3_file_transfer_job" { } resource "aws_glue_trigger" "glue_s3_file_transfer_job_trigger" { + count = local.enable_s3_file_transfer_trigger ? 1 : 0 name = "${module.glue_s3_file_transfer_job.name}-trigger" schedule = local.scheduled_s3_file_transfer_schedule type = "SCHEDULED" @@ -326,7 +325,7 @@ module "glue_switch_prisons_hive_data_location_job" { name = "${local.project}-switch-prisons-hive-data-location-${local.env}" short_name = "${local.project}-switch-prisons-hive-data-location" command_type = "glueetl" - description = "Switch Prisons Hive tables data location" + description = "Switch Prisons Hive tables data location.\nArguments:\n--dpr.config.key: (Required) config key e.g. prisoner\n--dpr.prisons.data.switch.target.s3.path: (Required) s3 path to point the prisons data to e.g. s3://dpr-curated-zone-" create_security_configuration = local.create_sec_conf job_language = "scala" temp_dir = "s3://${module.s3_glue_job_bucket.bucket_id}/tmp/${local.project}-switch-prisons-hive-data-location-${local.env}/" @@ -359,8 +358,6 @@ module "glue_switch_prisons_hive_data_location_job" { "--class" = "uk.gov.justice.digital.job.SwitchHiveTableJob" "--dpr.aws.region" = local.account_region "--dpr.config.s3.bucket" = module.s3_glue_job_bucket.bucket_id, - # "--dpr.config.key" = "(Required) config key. Will be specified at point of call in the reload step-functions" - # "--dpr.prisons.data.switch.target.s3.path" = "(Required) s3 path to point the prisons data to" "--dpr.prisons.database" = module.glue_prisons_database.db_name "--dpr.contract.registryName" = module.s3_schema_registry_bucket.bucket_id "--dpr.schema.cache.max.size" = local.hive_table_creation_job_schema_cache_max_size @@ -387,7 +384,7 @@ module "glue_s3_data_deletion_job" { name = "${local.project}-s3-data-deletion-job-${local.env}" short_name = "${local.project}-s3-data-deletion-job" command_type = "glueetl" - description = "Deletes s3 data belonging to a configured domain from specified bucket" + description = "Deletes s3 data belonging to a configured domain from specified bucket.\nArguments:\n--dpr.config.key: (Required) config key e.g. prisoner\n--dpr.file.deletion.buckets: (Required) comma separated set of s3 buckets from which to delete data from e.g dpr-raw-zone-,dpr-structured-zone-" create_security_configuration = local.create_sec_conf job_language = "scala" temp_dir = "s3://${module.s3_glue_job_bucket.bucket_id}/tmp/${local.project}-s3-data-deletion-${local.env}/" @@ -420,8 +417,6 @@ module "glue_s3_data_deletion_job" { "--class" = "uk.gov.justice.digital.job.S3DataDeletionJob" "--dpr.aws.region" = local.account_region "--dpr.config.s3.bucket" = module.s3_glue_job_bucket.bucket_id, - # "--dpr.config.key" = "(Required) config key. Will be specified at point of call in the reload step-functions" - # "--dpr.file.deletion.buckets" = "(Required) comma separated set of s3 buckets from which to delete data from" "--dpr.allowed.s3.file.extensions" = "*" "--dpr.log.level" = local.refresh_job_log_level } @@ -442,7 +437,7 @@ module "glue_stop_glue_instance_job" { name = "${local.project}-stop-glue-instance-job-${local.env}" short_name = "${local.project}-stop-glue-instance-job" command_type = "glueetl" - description = "Stops a running Glue job instance" + description = "Stops a running Glue job instance.\nArguments:\n--dpr.stop.glue.instance.job.name: (Required) name of the glue job whose running instance is to be stopped" create_security_configuration = local.create_sec_conf job_language = "scala" temp_dir = "s3://${module.s3_glue_job_bucket.bucket_id}/tmp/${local.project}-stop-glue-instance-${local.env}/" @@ -474,7 +469,6 @@ module "glue_stop_glue_instance_job" { "--extra-jars" = local.glue_jobs_latest_jar_location "--class" = "uk.gov.justice.digital.job.StopGlueInstanceJob" "--dpr.aws.region" = local.account_region - # "--dpr.stop.glue.instance.job.name" = "(Required) name of the glue job whose running instance is to be stopped" "--dpr.log.level" = local.refresh_job_log_level } } @@ -1024,48 +1018,6 @@ module "datamart" { ) } -# Lambda for moving files from the raw bucket to the raw archive bucket -module "s3_file_transfer_lambda" { - source = "./modules/lambdas/generic" - - enable_lambda = local.enable_s3_file_transfer_lambda - name = local.s3_file_transfer_lambda_name - s3_bucket = local.s3_file_transfer_lambda_code_s3_bucket - s3_key = local.reporting_lambda_code_s3_key - handler = local.s3_file_transfer_lambda_handler - runtime = local.s3_file_transfer_lambda_runtime - policies = local.s3_file_transfer_lambda_policies - tracing = local.s3_file_transfer_lambda_tracing - timeout = 900 # Max timeout of 15 minutes - - vpc_settings = { - subnet_ids = [ - data.aws_subnet.data_subnets_a.id, - data.aws_subnet.data_subnets_b.id, - data.aws_subnet.data_subnets_c.id - ] - - security_group_ids = [ - aws_security_group.lambda_generic[0].id - ] - } - - tags = merge( - local.all_tags, - { - Resource_Group = "ingestion-pipeline" - Jira = "DPR2-209" - Resource_Type = "Lambda" - Name = local.s3_file_transfer_lambda_name - } - ) - - depends_on = [ - aws_iam_policy.s3_all_object_actions_policy, - aws_iam_policy.kms_read_access_policy - ] -} - # DMS Nomis Data Collector module "dms_nomis_ingestor" { source = "./modules/dms_dps" diff --git a/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/glue.tf b/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/glue.tf index 0057880a5eb..b2f210fab3a 100644 --- a/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/glue.tf +++ b/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/glue.tf @@ -72,37 +72,3 @@ module "glue_reporting_hub_batch_job" { ) } -# Hive Tables Creation JOB -module "glue_hive_table_setup_job" { - source = "../../glue_job" - create_job = var.setup_hive_job - create_role = var.glue_hive_create_role # Needs to Set to TRUE - name = var.glue_hive_job_name - short_name = var.glue_hive_job_short_name - command_type = "glueetl" - description = var.glue_hive_description - create_security_configuration = var.glue_hive_create_sec_conf - job_language = "scala" - temp_dir = var.glue_hive_temp_dir - spark_event_logs = var.glue_hive_spark_event_logs - script_location = "s3://${var.project_id}-artifact-store-${var.env}/build-artifacts/digital-prison-reporting-jobs/scripts/${var.script_version}" - enable_continuous_log_filter = var.glue_hive_enable_cont_log_filter - project_id = var.project_id - aws_kms_key = var.s3_kms_arn - execution_class = var.glue_hive_execution_class - worker_type = var.glue_hive_job_worker_type - number_of_workers = var.glue_hive_job_num_workers - max_concurrent = var.glue_hive_max_concurrent #64 - region = var.account_region - account = var.account_id - log_group_retention_in_days = var.glue_hive_log_group_retention_in_days - - arguments = var.glue_hive_arguments - - tags = merge( - var.tags, - { - Resource_Type = "Glue Job" - } - ) -} diff --git a/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/variables.tf b/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/variables.tf index 011a5bb63f0..73854e153ec 100644 --- a/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/variables.tf +++ b/terraform/environments/digital-prison-reporting/modules/domains/ingestion-jobs/variables.tf @@ -346,125 +346,3 @@ variable "env" { variable "script_version" {} variable "jar_version" {} -# HIVE - -## Glue job hive -variable "glue_hive_arguments" { - type = map(any) - default = {} -} - -variable "setup_hive_job" { - description = "Enable hive Job, True or False" - type = bool - default = false -} - -variable "glue_hive_job_name" { - description = "Name of the Glue CDC Job" - default = "" -} - -variable "glue_hive_job_short_name" { - description = "Name of the Glue CDC Job" - default = "" -} - -variable "glue_hive_description" { - description = "Job Description" - default = "" -} - -variable "glue_hive_create_sec_conf" { - type = bool - default = false - description = "(Optional) Create AWS Glue Security Configuration associated with the job." -} - -variable "glue_hive_log_group_retention_in_days" { - type = number - default = 1 - description = "(Optional) The default number of days log events retained in the glue job log group." -} - - -variable "glue_hive_language" { - type = string - default = "python" - description = "(Optional) The script programming language." - - validation { - condition = contains(["scala", "python"], var.glue_hive_language) - error_message = "Accepts a value of 'scala' or 'python'." - } -} - -variable "glue_hive_temp_dir" { - type = string - default = null - description = "(Optional) Specifies an Amazon S3 path to a bucket that can be used as a temporary directory for the job." -} - -variable "glue_hive_checkpoint_dir" { - type = string - default = null - description = "(Optional) Specifies an Amazon S3 path to a bucket that can be used as a Checkoint directory for the job." -} - -variable "glue_hive_spark_event_logs" { - type = string - default = null - description = "(Optional) Specifies an Amazon S3 path to a bucket that can be used as a Spark Event Logs directory for the job." -} - -variable "glue_hive_script_location" { - type = string - description = "(Optional) Specifies the S3 path to a script that executes a job." - default = "" -} - -variable "glue_hive_enable_cont_log_filter" { - type = bool - default = true - description = "(Optional) Specifies a standard filter or no filter when you create or edit a job enabled for continuous logging." -} - -variable "glue_hive_execution_class" { - default = "STANDARD" - description = "Execution CLass Standard or FLex" -} - -variable "glue_hive_job_worker_type" { - type = string - default = "G.1X" - description = "(Optional) The type of predefined worker that is allocated when a job runs." - - validation { - condition = contains(["Standard", "G.1X", "G.2X"], var.glue_hive_job_worker_type) - error_message = "Accepts a value of Standard, G.1X, or G.2X." - } -} - -variable "glue_hive_job_num_workers" { - type = number - default = 2 - description = "(Optional) The number of workers of a defined workerType that are allocated when a job runs." -} - -variable "glue_hive_additional_policies" { - type = string - default = "" - description = "(Optional) The list of Policies used for this job." -} - -variable "glue_hive_max_concurrent" { - type = number - default = 1 - description = "(Optional) The maximum number of concurrent runs allowed for a job." -} - -variable "glue_hive_create_role" { - type = bool - default = false - description = "(Optional) Create AWS IAM role associated with the job." -} diff --git a/terraform/environments/electronic-monitoring-data/locals.tf b/terraform/environments/electronic-monitoring-data/locals.tf index 3b181cc52c6..3e7b3418083 100644 --- a/terraform/environments/electronic-monitoring-data/locals.tf +++ b/terraform/environments/electronic-monitoring-data/locals.tf @@ -1,35 +1,57 @@ #### This file can be used to store locals specific to the member account #### locals { + sftp_account_capita = { + name = "capita" + ssh_keys = [ + "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFc140uxPfjq1ilaOxcLYbnyIau2vURzKWFHLsxra+5Vf1nSZypOZ/g9eavBxcf2tkxBjgTx06BeRh3j+QhA8rnV9vKtyh9ZXIe5SNcrGlsGLKMyn+eB05Dt2m58oyMwWA==", + ] + cidr_ipv4s = [ + "82.203.33.112/28", + "82.203.33.128/28", + "85.115.52.0/24", + "85.115.53.0/24", + "85.115.54.0/24", + ] + cidr_ipv6s = [] + } - developer_cidr_ipv6s = [ - # Pen tester - "2001:8b0:13dc::/48", - "2a05:d01c:e83:b500::/64", - "2a05:d01c:e83:b500:f25:37ec:29e9:4b6e/128", - "2603:1020:700:2::e2/128" - ] + sftp_account_civica = { + name = "civica" + ssh_keys = [ + "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBCJBwZM5nMigS31soM45PITAHCmyhQpdDAkdX1liqnIZSd8A+zn3XQyVRy5E2a39gfsng5hAQetDFJKn+SaayATCQAzN0cJWlcrvtv314UsRV+PxO236sWVf+RwguUDZRQ==", + ] + cidr_ipv4s = [ + "20.0.26.153/32", + ] + cidr_ipv6s = [] + } - developer_cidr_ipv4s = [ - # Pen tester - "90.155.48.192/26", - "81.2.127.144/28", - "81.187.169.170/32", - "88.97.60.11/32", - "13.42.192.167/32", - "51.104.217.191/32", - # fy nhy - "46.69.144.146/32", - # Petty France - "81.134.202.29/32" - ] + sftp_account_g4s_test = { + name = "g4s_test" + ssh_keys = [ + "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBK85G9UwgU1KKgsYXfTWDsT4MqGSmjku1XGpH1EqmSuXLk5lmwFsgoLqqsROq2oEw2Yrr3uLyNVY2Dl6Pfm+dkdljfbPtqku+AkRSkhDo4K7bIwhWPh7HImcalxhde6BUA== ecdsa-key-20240208", + ] + cidr_ipv4s = [ + "10.180.2.161/32", + ] + cidr_ipv6s = [] + } - developer_ssh_keys = [ - # Pen tester - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDE9c0YBOGrtSqz0JX2Z4bBP2I1nPCt8XMgE80p7iPQ7wBd5bHTTp5uMhwXkInNjffWq6d6BcDU71Ri+MRYYg4WsLi4oRSvY4FQdu6ejMcNA59GYFkFI/tIERPJ5eiYNPAY9GcrVQJTrxClma9cDpEaRPsOdJ16sZfjEVcic6Fak/Vv7Quj7smfVB6jAXBGhRM9O8iEZIW2uJnECNBbuzxJV+MSZDRpGNBP7T/QYalodnpUSpYxMGrLjqMzXb1AjYqAnO1Aj9HfDq0cAMujWs+Il4zFVfr5qn/hYRL1ozZ17n53XzKwkYD7jelQX0tfDepEbWdzQ/7qj70w1WGDR9N7v9ya7T8v27JazTO43V96QMlYORvLLMieO/d0O6wiWhDi3wf2Ig4ZWBao4GtdSotPNnmUZZW/4Ozg1QaS6IHkbLwmGOTgc/HmvggIlZdb6hJLjQGDYhflg+cH9aiudFOiu6DY/J9DprtzAFeFaOTuU1J8uqqP0OZNZq0SPt5bUHs=", - # Matt Price - "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBA3BsCFaNiGxbmJffRi9q/W3aLmZWgqE6QkeFJD5O6F4nDdjsV1R0ZMUvTSoi3tKqoAE+1RYYj2Ra/F1buHov9e+sFPrlMl0wql6uMsBA1ndiIiKuq+NLY1NOxEvqm2J9Q==", - # Matt Heery - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClyRRkvW162H2NQm5IlavjE4zBhnzGJ/V+raqe7ynPumIgKhmNto8GD6iKlWkzLGxfwXQhONM/9J8+u9tqncw5FzEWEYdX/FEJF5VwLYma/OtMUio3vtwsc9zbae4EyTvROvbJSMgL07ZicUjQ9pS4+pst2KVjDtgCXD8l7A66wOkmht2Cb2Ebfk+wk965uN5wE5vHDQBx6QQ4z9UiGEp34n/g2O9gUGUJcFdYCEHVl1MY+dicCJwsRzEC1a0s/LzCtiCo66yWW8VEpMpDJNCAJccxadwWBI1d+8R94LTUakxkYhAVCpzs+A/qjaAUKsT/1KQm0+3gJIfLqmWYUumB4VgP2+cYiFbdxWQt2lLAUYZmsTwR5EktCftA5OGcwKO11sKnouj+IYiN9wfRl8kQEs+KZDDSjXKAdsWvRwhRMbBZdLqIzO2InyLCQaujZqMupMh5KkmrhL9eYFn0qtWSG274vnmUacvaIl1e8EmIb9j5ksyVXysPlIVxbNks51E= matt.heery@MJ004484" - ] + sftp_account_dev = { + name = "dev" + ssh_keys = [ + # Matt Price + "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBA3BsCFaNiGxbmJffRi9q/W3aLmZWgqE6QkeFJD5O6F4nDdjsV1R0ZMUvTSoi3tKqoAE+1RYYj2Ra/F1buHov9e+sFPrlMl0wql6uMsBA1ndiIiKuq+NLY1NOxEvqm2J9Q==", + # Matt Heery + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClyRRkvW162H2NQm5IlavjE4zBhnzGJ/V+raqe7ynPumIgKhmNto8GD6iKlWkzLGxfwXQhONM/9J8+u9tqncw5FzEWEYdX/FEJF5VwLYma/OtMUio3vtwsc9zbae4EyTvROvbJSMgL07ZicUjQ9pS4+pst2KVjDtgCXD8l7A66wOkmht2Cb2Ebfk+wk965uN5wE5vHDQBx6QQ4z9UiGEp34n/g2O9gUGUJcFdYCEHVl1MY+dicCJwsRzEC1a0s/LzCtiCo66yWW8VEpMpDJNCAJccxadwWBI1d+8R94LTUakxkYhAVCpzs+A/qjaAUKsT/1KQm0+3gJIfLqmWYUumB4VgP2+cYiFbdxWQt2lLAUYZmsTwR5EktCftA5OGcwKO11sKnouj+IYiN9wfRl8kQEs+KZDDSjXKAdsWvRwhRMbBZdLqIzO2InyLCQaujZqMupMh5KkmrhL9eYFn0qtWSG274vnmUacvaIl1e8EmIb9j5ksyVXysPlIVxbNks51E= matt.heery@MJ004484", + ] + cidr_ipv4s = [ + # fy nhy + "46.69.144.146/32", + # Petty France + "81.134.202.29/32", + ] + cidr_ipv6s = [] + } } \ No newline at end of file diff --git a/terraform/environments/electronic-monitoring-data/main.tf b/terraform/environments/electronic-monitoring-data/main.tf index 6e47c318603..3ea7c55770a 100644 --- a/terraform/environments/electronic-monitoring-data/main.tf +++ b/terraform/environments/electronic-monitoring-data/main.tf @@ -3,30 +3,17 @@ module "capita" { supplier = "capita" - give_access = true - supplier_shh_key = "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBIhggGYKbOk6BH7fpEs6JGRnMyLRK/9/tAMQOVYOZtehKTRcM5vGsJFRGjjm2wEan3/uYOuto0NoVkbRfIi0AIG6EWrp1gvHNQlUTtxQVp7rFeOnZAjVEE9xVUEgHhMNLw==" - supplier_cidr_ipv4s = [ - "82.203.33.112/28", - "82.203.33.128/28", - "85.115.52.0/24", - "85.115.53.0/24", - "85.115.54.0/24" + user_accounts = [ + local.sftp_account_capita, + local.sftp_account_dev, ] - supplier_cidr_ipv6s = [] data_store_bucket = aws_s3_bucket.data_store - kms_key_id = data.aws_kms_key.general_shared.arn - account_id = data.aws_caller_identity.current.account_id vpc_id = data.aws_vpc.shared.id subnet_ids = [data.aws_subnet.public_subnets_b.id] - - give_dev_access = true - dev_ssh_keys = local.developer_ssh_keys - dev_cidr_ipv4s = local.developer_cidr_ipv4s - dev_cidr_ipv6s = local.developer_cidr_ipv6s } module "civica" { @@ -34,26 +21,17 @@ module "civica" { supplier = "civica" - give_access = true - supplier_shh_key = "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBCJBwZM5nMigS31soM45PITAHCmyhQpdDAkdX1liqnIZSd8A+zn3XQyVRy5E2a39gfsng5hAQetDFJKn+SaayATCQAzN0cJWlcrvtv314UsRV+PxO236sWVf+RwguUDZRQ==" - supplier_cidr_ipv4s = [ - "20.0.26.153/32" + user_accounts = [ + local.sftp_account_civica, + local.sftp_account_dev, ] - supplier_cidr_ipv6s = [] data_store_bucket = aws_s3_bucket.data_store - kms_key_id = data.aws_kms_key.general_shared.arn - account_id = data.aws_caller_identity.current.account_id vpc_id = data.aws_vpc.shared.id subnet_ids = [data.aws_subnet.public_subnets_b.id] - - give_dev_access = true - dev_ssh_keys = local.developer_ssh_keys - dev_cidr_ipv4s = local.developer_cidr_ipv4s - dev_cidr_ipv6s = local.developer_cidr_ipv6s } module "g4s" { @@ -61,22 +39,15 @@ module "g4s" { supplier = "g4s" - give_access = false - supplier_shh_key = null - supplier_cidr_ipv4s = [] - supplier_cidr_ipv6s = [] + user_accounts = [ + local.sftp_account_g4s_test, + local.sftp_account_dev, + ] data_store_bucket = aws_s3_bucket.data_store - kms_key_id = data.aws_kms_key.general_shared.arn - account_id = data.aws_caller_identity.current.account_id vpc_id = data.aws_vpc.shared.id subnet_ids = [data.aws_subnet.public_subnets_b.id] - - give_dev_access = true - dev_ssh_keys = local.developer_ssh_keys - dev_cidr_ipv4s = local.developer_cidr_ipv4s - dev_cidr_ipv6s = local.developer_cidr_ipv6s } diff --git a/terraform/environments/electronic-monitoring-data/modules/landing_zone/landing_zone_user/main.tf b/terraform/environments/electronic-monitoring-data/modules/landing_zone/landing_zone_user/main.tf new file mode 100644 index 00000000000..a4c12bfbf3a --- /dev/null +++ b/terraform/environments/electronic-monitoring-data/modules/landing_zone/landing_zone_user/main.tf @@ -0,0 +1,73 @@ +data "aws_iam_policy_document" "transfer_assume_role" { + statement { + effect = "Allow" + + principals { + type = "Service" + identifiers = ["transfer.amazonaws.com"] + } + + actions = ["sts:AssumeRole"] + } +} + +#------------------------------------------------------------------------------ +# AWS transfer user +# +# Create user profile that has put access for specified landing zone bucket. +#------------------------------------------------------------------------------ + +resource "aws_transfer_user" "this" { + server_id = var.transfer_server.id + user_name = var.user_name + role = aws_iam_role.this_transfer_user.arn + + home_directory = "/${var.landing_bucket.id}/" + + tags = { + supplier = var.user_name + } +} + +resource "aws_iam_role" "this_transfer_user" { + name = "${var.supplier}-${var.user_name}-transfer-user-iam-role" + assume_role_policy = data.aws_iam_policy_document.transfer_assume_role.json + managed_policy_arns = [ + "arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess" + ] +} + +resource "aws_iam_role_policy" "this_transfer_user" { + name = "${var.user_name}-transfer-user-iam-policy" + role = aws_iam_role.this_transfer_user.id + policy = data.aws_iam_policy_document.this_transfer_user.json +} + +data "aws_iam_policy_document" "this_transfer_user" { + statement { + sid = "AllowListAccessToLandingS3" + effect = "Allow" + actions = ["s3:ListBucket"] + resources = [var.landing_bucket.arn] + } + statement { + sid = "AllowPutAccessToLandingS3" + effect = "Allow" + actions = ["s3:PutObject"] + resources = ["${var.landing_bucket.arn}/*"] + } +} + +#------------------------------------------------------------------------------ +# AWS transfer ssh key +# +# Set the public ssh key for the user profile to access SFTP server. +#------------------------------------------------------------------------------ + +resource "aws_transfer_ssh_key" "this" { + server_id = var.transfer_server.id + user_name = aws_transfer_user.this.user_name + + for_each = { for ssh_key in var.ssh_keys : ssh_key => ssh_key } + body = each.key +} diff --git a/terraform/environments/electronic-monitoring-data/modules/landing_zone/landing_zone_user/variables.tf b/terraform/environments/electronic-monitoring-data/modules/landing_zone/landing_zone_user/variables.tf new file mode 100644 index 00000000000..28e26368620 --- /dev/null +++ b/terraform/environments/electronic-monitoring-data/modules/landing_zone/landing_zone_user/variables.tf @@ -0,0 +1,22 @@ +variable "landing_bucket" { + description = "The landing bucket that data is placed in" +} + +variable "ssh_keys" { + description = "The public ssh key for the SFTP server" + type = list(string) +} + +variable "supplier" { + description = "The name of the supplier the SFTP server is for" + type = string +} + +variable "transfer_server" { + description = "The SFTP server" +} + +variable "user_name" { + description = "The user name for the SFTP server account" + type = string +} diff --git a/terraform/environments/electronic-monitoring-data/modules/landing_zone/main.tf b/terraform/environments/electronic-monitoring-data/modules/landing_zone/main.tf index ed2dee4f842..ffbcc36eb69 100644 --- a/terraform/environments/electronic-monitoring-data/modules/landing_zone/main.tf +++ b/terraform/environments/electronic-monitoring-data/modules/landing_zone/main.tf @@ -118,6 +118,7 @@ module "log_bucket" { resource "aws_kms_key" "this" { description = "${var.supplier} server cloudwatch log encryption key" + enable_key_rotation = true key_usage = "ENCRYPT_DECRYPT" deletion_window_in_days = 30 @@ -189,10 +190,7 @@ resource "aws_transfer_server" "this" { vpc_id = var.vpc_id subnet_ids = var.subnet_ids address_allocation_ids = [aws_eip.this.id] - security_group_ids = [ - aws_security_group.this.id, - aws_security_group.dev.id - ] + security_group_ids = local.landing_zone_security_group_ids } domain = "S3" @@ -244,7 +242,7 @@ resource "aws_transfer_workflow" "this" { steps { tag_step_details { - name = "example" + name = "tag-with-supplier" source_file_location = "$${original.file}" tags { key = "supplier" @@ -255,11 +253,12 @@ resource "aws_transfer_workflow" "this" { } steps { copy_step_details { + name = "copy-file-to-data-store" source_file_location = "$${original.file}" destination_file_location { s3_file_location { bucket = var.data_store_bucket.bucket - key = "${var.supplier}/" + key = "${var.supplier}/$${transfer:UserName}/$${transfer:UploadDate}/" } } } @@ -267,6 +266,7 @@ resource "aws_transfer_workflow" "this" { } steps { delete_step_details { + name = "delete-file-from-landing-zone" source_file_location = "$${original.file}" } type = "DELETE" @@ -346,157 +346,42 @@ resource "aws_iam_role_policy" "this_transfer_workflow" { #------------------------------------------------------------------------------ # AWS transfer user # -# Create supplier user profile that has put access to only their landing zone -# bucket. +# Create user profiles that has put access to only this landing zone bucket. #------------------------------------------------------------------------------ -resource "aws_transfer_user" "this" { - count = var.give_access ? 1 : 0 - - server_id = aws_transfer_server.this.id - user_name = var.supplier - role = aws_iam_role.this_transfer_user.arn - - home_directory = "/${aws_s3_bucket.landing_bucket.id}/" - - tags = { - supplier = var.supplier - } -} - -resource "aws_iam_role" "this_transfer_user" { - name = "${var.supplier}-transfer-user-iam-role" - assume_role_policy = data.aws_iam_policy_document.transfer_assume_role.json - managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess"] -} - -resource "aws_iam_role_policy" "this_transfer_user" { - name = "${var.supplier}-transfer-user-iam-policy" - role = aws_iam_role.this_transfer_user.id - policy = data.aws_iam_policy_document.this_transfer_user.json -} - -data "aws_iam_policy_document" "this_transfer_user" { - statement { - sid = "AllowListAccessToLandingS3" - effect = "Allow" - actions = ["s3:ListBucket"] - resources = [aws_s3_bucket.landing_bucket.arn] - } - statement { - sid = "AllowPutAccessToLandingS3" - effect = "Allow" - actions = ["s3:PutObject"] - resources = ["${aws_s3_bucket.landing_bucket.arn}/*"] - } -} +module "landing_zone_users" { + source = "./landing_zone_user" -#------------------------------------------------------------------------------ -# AWS transfer ssh key -# -# Set the public ssh key for the supplier user profile to access SFTP server. -#------------------------------------------------------------------------------ - -resource "aws_transfer_ssh_key" "this" { - count = var.give_access ? 1 : 0 + for_each = { for idx, item in var.user_accounts : idx => item } - server_id = aws_transfer_server.this.id - user_name = aws_transfer_user.this[0].user_name - body = var.supplier_shh_key + landing_bucket = aws_s3_bucket.landing_bucket + ssh_keys = each.value.ssh_keys + supplier = var.supplier + transfer_server = aws_transfer_server.this + user_name = each.value.name } #------------------------------------------------------------------------------ # AWS security group # -# Set the allowed IP addresses for the supplier. +# Set the allowed IP addresses for the this SFTP server. #------------------------------------------------------------------------------ -resource "aws_security_group" "this" { - name = "${var.supplier}-inbound-ips" - description = "Allowed IP addresses for ${var.supplier}" - vpc_id = var.vpc_id - - tags = { - supplier = var.supplier - } -} +module "landing_zone_security_groups" { + source = "./server_security_group" -resource "aws_vpc_security_group_ingress_rule" "this_ipv4" { - security_group_id = aws_security_group.this.id - description = "Allow specific access to IPv4 address via port 2222" - ip_protocol = "tcp" - from_port = 2222 - to_port = 2222 + for_each = { for idx, item in var.user_accounts : idx => item } - for_each = { for cidr_ipv4 in var.supplier_cidr_ipv4s : cidr_ipv4 => cidr_ipv4 } - cidr_ipv4 = each.key + cidr_ipv4s = each.value.cidr_ipv4s + cidr_ipv6s = each.value.cidr_ipv6s + supplier = var.supplier + user_name = each.value.name + vpc_id = var.vpc_id } -resource "aws_vpc_security_group_ingress_rule" "this_ipv6" { - security_group_id = aws_security_group.this.id - description = "Allow specific access to IPv6 address via port 2222" - ip_protocol = "tcp" - from_port = 2222 - to_port = 2222 - - for_each = { for cidr_ipv6 in var.supplier_cidr_ipv6s : cidr_ipv6 => cidr_ipv6 } - cidr_ipv6 = each.key -} - -#------------------------------------------------------------------------------ -# Create dev account for testing -#------------------------------------------------------------------------------ - -resource "aws_transfer_user" "dev" { - count = var.give_dev_access ? 1 : 0 - - server_id = aws_transfer_server.this.id - user_name = "dev" - role = aws_iam_role.this_transfer_user.arn - - home_directory = "/${aws_s3_bucket.landing_bucket.id}/" - - tags = { - supplier = var.supplier - } -} - -resource "aws_transfer_ssh_key" "dev_ssh_key" { - server_id = aws_transfer_server.this.id - user_name = aws_transfer_user.dev[0].user_name - - for_each = { for ssh_key in var.dev_ssh_keys : ssh_key => ssh_key } - body = each.key -} - -resource "aws_security_group" "dev" { - name = "${var.supplier}-dev-inbound-ips" - description = "Allowed MoJ developer IP addresses for testing ${var.supplier} landing zone" - vpc_id = var.vpc_id - - tags = { - supplier = var.supplier - } -} - -resource "aws_vpc_security_group_ingress_rule" "dev_ipv4" { - security_group_id = aws_security_group.dev.id - - ip_protocol = "tcp" - from_port = 2222 - to_port = 2222 - - for_each = { for cidr_ipv4 in var.dev_cidr_ipv4s : cidr_ipv4 => cidr_ipv4 } - cidr_ipv4 = each.key -} - -resource "aws_vpc_security_group_ingress_rule" "dev_ipv6" { - security_group_id = aws_security_group.dev.id - - ip_protocol = "tcp" - from_port = 2222 - to_port = 2222 - - for_each = { for cidr_ipv6 in var.dev_cidr_ipv6s : cidr_ipv6 => cidr_ipv6 } - cidr_ipv6 = each.key +locals { + landing_zone_security_group_ids = flatten([ + for module_instance in values(module.landing_zone_security_groups) : + module_instance.security_group_id + ]) } \ No newline at end of file diff --git a/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/main.tf b/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/main.tf new file mode 100644 index 00000000000..9a9ef49a65f --- /dev/null +++ b/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/main.tf @@ -0,0 +1,41 @@ +#------------------------------------------------------------------------------ +# AWS security group +# +# Set the allowed IP addresses for the SFTP server. +#------------------------------------------------------------------------------ + +resource "aws_security_group" "this" { + name = "${var.supplier}-${var.user_name}-inbound-ips" + description = "Allowed IP addresses for ${var.user_name} on ${var.supplier} server" + vpc_id = var.vpc_id + + lifecycle { + create_before_destroy = true + } + + tags = { + supplier = var.user_name + } +} + +resource "aws_vpc_security_group_ingress_rule" "this_ipv4" { + security_group_id = aws_security_group.this.id + description = "Allow specific access to IPv4 address via port 2222" + ip_protocol = "tcp" + from_port = 2222 + to_port = 2222 + + for_each = { for cidr_ipv4 in var.cidr_ipv4s : cidr_ipv4 => cidr_ipv4 } + cidr_ipv4 = each.key +} + +resource "aws_vpc_security_group_ingress_rule" "this_ipv6" { + security_group_id = aws_security_group.this.id + description = "Allow specific access to IPv6 address via port 2222" + ip_protocol = "tcp" + from_port = 2222 + to_port = 2222 + + for_each = { for cidr_ipv6 in var.cidr_ipv6s : cidr_ipv6 => cidr_ipv6 } + cidr_ipv6 = each.key +} diff --git a/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/outputs.tf b/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/outputs.tf new file mode 100644 index 00000000000..ba422cb1abc --- /dev/null +++ b/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/outputs.tf @@ -0,0 +1,3 @@ +output "security_group_id" { + value = aws_security_group.this.id +} \ No newline at end of file diff --git a/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/variables.tf b/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/variables.tf new file mode 100644 index 00000000000..201dbc0435d --- /dev/null +++ b/terraform/environments/electronic-monitoring-data/modules/landing_zone/server_security_group/variables.tf @@ -0,0 +1,25 @@ +variable "cidr_ipv4s" { + description = "The allowed IPv4 addresses that can access the SFTP server" + type = list(string) + default = [] +} + +variable "cidr_ipv6s" { + description = "The allowed IPv6 addresses that can access the SFTP server" + type = list(string) + default = [] +} + +variable "supplier" { + description = "The name of the supplier the SFTP server is for" + type = string +} + +variable "user_name" { + description = "The user name for the SFTP server account" + type = string +} + +variable "vpc_id" { + description = "The vpc used for the SFTP server" +} diff --git a/terraform/environments/electronic-monitoring-data/modules/landing_zone/variables.tf b/terraform/environments/electronic-monitoring-data/modules/landing_zone/variables.tf index bf82fc36be8..1977d62df0e 100644 --- a/terraform/environments/electronic-monitoring-data/modules/landing_zone/variables.tf +++ b/terraform/environments/electronic-monitoring-data/modules/landing_zone/variables.tf @@ -1,69 +1,32 @@ -variable "supplier" { - description = "The name of the supplier the SFTP server is for" - type = string -} - -variable "give_access" { - description = "When true, access is given to supplier" - type = bool -} - -variable "supplier_shh_key" { - description = "The public ssh key for the supplier the SFTP server is for" - type = string -} - -variable "supplier_cidr_ipv4s" { - description = "The allowed IPv4 addresses for the supplier that can access the SFTP server" - type = list(string) - default = [] -} - -variable "supplier_cidr_ipv6s" { - description = "The allowed IPv6 addresses for the supplier that can access the SFTP server" - type = list(string) - default = [] +variable "account_id" { + description = "The AWS account id" } variable "data_store_bucket" { description = "The bucket landed data is moved to" } -variable "account_id" { - description = "The account id" -} - -variable "vpc_id" { - description = "The vpc used for the SFTP server" -} - variable "subnet_ids" { description = "The subnet ids used for the SFTP server" type = list(string) } -variable "kms_key_id" { - description = "The AWS KMS key" -} - -variable "give_dev_access" { - description = "When true, developer access is given to sftp server" - type = bool -} - -variable "dev_ssh_keys" { - description = "The public ssh key for devs for the SFTP server" - type = list(string) +variable "supplier" { + description = "The name of the supplier the SFTP server is for" + type = string } -variable "dev_cidr_ipv4s" { - description = "The allowed IPv4 addresses for developers that can access the SFTP server" - type = list(string) +variable "user_accounts"{ + description = "The names of the user accounts to create" + type = list(object({ + name = string + ssh_keys = list(string) + cidr_ipv4s = list(string) + cidr_ipv6s = list(string) + })) default = [] } -variable "dev_cidr_ipv6s" { - description = "The allowed IPv6 addresses for developers that can access the SFTP server" - type = list(string) - default = [] +variable "vpc_id" { + description = "The vpc used for the SFTP server" } diff --git a/terraform/environments/electronic-monitoring-data/modules/s3_log_bucket/main.tf b/terraform/environments/electronic-monitoring-data/modules/s3_log_bucket/main.tf index bca6e7b226c..fc49613b077 100644 --- a/terraform/environments/electronic-monitoring-data/modules/s3_log_bucket/main.tf +++ b/terraform/environments/electronic-monitoring-data/modules/s3_log_bucket/main.tf @@ -7,6 +7,13 @@ resource "aws_s3_bucket" "this" { tags = var.tags } +resource "aws_s3_bucket_versioning" "this" { + bucket = aws_s3_bucket.this.id + versioning_configuration { + status = "Enabled" + } +} + resource "aws_s3_bucket_server_side_encryption_configuration" "this" { bucket = aws_s3_bucket.this.id @@ -31,6 +38,25 @@ resource "aws_s3_bucket_policy" "this" { } data "aws_iam_policy_document" "this" { + statement { + sid = "EnforceTLSv12orHigher" + principals { + type = "AWS" + identifiers = ["*"] + } + effect = "Deny" + actions = ["s3:*"] + resources = [ + aws_s3_bucket.this.arn, + "${aws_s3_bucket.this.arn}/*" + ] + condition { + test = "NumericLessThan" + variable = "s3:TlsVersion" + values = [1.2] + } + } + statement { sid = "S3ServerAccessLogsPolicy" effect = "Allow" diff --git a/terraform/environments/electronic-monitoring-data/s3.tf b/terraform/environments/electronic-monitoring-data/s3.tf index 9d964c3bbb6..c1a5e521906 100644 --- a/terraform/environments/electronic-monitoring-data/s3.tf +++ b/terraform/environments/electronic-monitoring-data/s3.tf @@ -42,6 +42,32 @@ resource "aws_s3_bucket_versioning" "data_store" { } } +resource "aws_s3_bucket_policy" "data_store" { + bucket = aws_s3_bucket.data_store.id + policy = data.aws_iam_policy_document.data_store.json +} + +data "aws_iam_policy_document" "data_store" { + statement { + sid = "EnforceTLSv12orHigher" + principals { + type = "AWS" + identifiers = ["*"] + } + effect = "Deny" + actions = ["s3:*"] + resources = [ + aws_s3_bucket.data_store.arn, + "${aws_s3_bucket.data_store.arn}/*" + ] + condition { + test = "NumericLessThan" + variable = "s3:TlsVersion" + values = [1.2] + } + } +} + resource "aws_s3_bucket_logging" "data_store" { bucket = aws_s3_bucket.data_store.id diff --git a/terraform/environments/equip/main.tf b/terraform/environments/equip/main.tf index 3f91a36385a..4b035b03ba5 100644 --- a/terraform/environments/equip/main.tf +++ b/terraform/environments/equip/main.tf @@ -725,3 +725,71 @@ module "win2022_STD_multiple" { { instance-scheduling = local.application_data.accounts[local.environment].instance-scheduling } ) } + + +locals { + win2019_STD_powerBI_instances = { + COR-A-GW01 = { + instance_type = "t3a.xlarge" + subnet_id = data.aws_subnet.private_subnets_a.id + vpc_security_group_ids = [aws_security_group.aws_equip_security_group.id, aws_security_group.all_internal_groups.id] + root_block_device = [ + { + encrypted = true + volume_type = "gp3" + volume_size = 90 + kms_key_id = aws_kms_key.this.arn + tags = merge(local.tags, + { Name = "${local.name}-COR-A-GWP01-root-block" } + ) + } + ] + ebs_block_device = [ + { + device_name = "/dev/sdg" + volume_type = "gp3" + volume_size = 20 + encrypted = true + kms_key_id = aws_kms_key.this.arn + tags = merge(local.tags, + { Name = "${local.name}-COR-A-GW01-ebs-block-1" } + ) + } + + ] + tags = merge(local.tags, + { Name = "${local.name}-COR-A-GW01" + Role = "Nimbus PowerBI Services" } + ) + } + } +} + + +module "PowerBI_server" { + source = "./ec2-instance-module" + + + for_each = local.win2019_STD_powerBI_instances + + name = "${local.name}-${each.key}" + ami = "ami-0df480245c4679e0b" + instance_type = each.value.instance_type + vpc_security_group_ids = each.value.vpc_security_group_ids + subnet_id = each.value.subnet_id + monitoring = true + ebs_optimized = true + key_name = aws_key_pair.windowskey.key_name + user_data = data.template_file.windows-userdata.rendered + iam_instance_profile = aws_iam_instance_profile.instance-profile-moj.name + + enable_volume_tags = false + root_block_device = lookup(each.value, "root_block_device", []) + ebs_block_device = lookup(each.value, "ebs_block_device", []) + + tags = merge(each.value.tags, local.tags, { + Environment = "development" + terraform_managed = "true" }, + { instance-scheduling = local.application_data.accounts[local.environment].instance-scheduling } + ) +} \ No newline at end of file diff --git a/terraform/environments/hmpps-domain-services/ec2_common.tf b/terraform/environments/hmpps-domain-services/ec2_common.tf index d8ca48acb3c..9a906b930c1 100644 --- a/terraform/environments/hmpps-domain-services/ec2_common.tf +++ b/terraform/environments/hmpps-domain-services/ec2_common.tf @@ -81,3 +81,17 @@ resource "aws_ssm_document" "rds_app" { }, ) } + +resource "aws_ssm_document" "winrm_https" { + name = "winrm_https" + document_type = "Command" + document_format = "YAML" + content = file("./ssm-documents/winrm_https.yaml") + + tags = merge( + local.tags, + { + os-type = "Windows" + }, + ) +} \ No newline at end of file diff --git a/terraform/environments/hmpps-domain-services/lambda.tf b/terraform/environments/hmpps-domain-services/lambda.tf index 12de60b64fc..32d117f2ba9 100644 --- a/terraform/environments/hmpps-domain-services/lambda.tf +++ b/terraform/environments/hmpps-domain-services/lambda.tf @@ -6,7 +6,7 @@ locals { module "ad-clean-up-lambda" { source = "github.com/ministryofjustice/modernisation-platform-terraform-lambda-function" # ref for V3.1 - count = local.environment == "test" ? 1 : 0 # temporary whilst on-going work + count = local.environment == "development" ? 1 : 0 # temporary application_name = local.lambda_ad_object_cleanup.function_name @@ -33,9 +33,9 @@ module "ad-clean-up-lambda" { } data "archive_file" "ad-cleanup-lambda" { - type = "zip" - source_dir = "lambda/ad-clean-up" - output_path = "lambda/ad-cleanup/ad-cleanup-lambda-payload-test.zip" + type = "zip" + source_dir = "lambda/ad-clean-up" + output_path = "lambda/ad-clean-up/ad-clean-up-lambda-payload-test.zip" } data "aws_iam_policy_document" "lambda_assume_role_policy" { @@ -51,7 +51,7 @@ data "aws_iam_policy_document" "lambda_assume_role_policy" { } resource "aws_iam_role" "lambda-ad-role" { - count = local.environment == "test" ? 1 : 0 # temporary whilst on-going work + count = local.environment == "development" ? 1 : 0 # temporary name = "LambdaFunctionADObjectCleanUp" tags = local.tags @@ -59,7 +59,13 @@ resource "aws_iam_role" "lambda-ad-role" { } resource "aws_iam_role_policy_attachment" "lambda-vpc-attachment" { - count = local.environment == "test" ? 1 : 0 # temporary whilst on-going work + count = local.environment == "development" ? 1 : 0 # temporary role = aws_iam_role.lambda-ad-role[count.index].name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" } + +resource "aws_iam_role_policy_attachment" "lambda_secrets_manager" { + count = local.environment == "development" ? 1 : 0 # temporary + role = aws_iam_role.lambda-ad-role[count.index].name + policy_arn = "arn:aws:iam::aws:policy/SecretsManagerReadWrite" +} diff --git a/terraform/environments/hmpps-domain-services/lambda/ad-clean-up/lambda_function.py b/terraform/environments/hmpps-domain-services/lambda/ad-clean-up/lambda_function.py index 0d24e11aac5..7aacc512236 100644 --- a/terraform/environments/hmpps-domain-services/lambda/ad-clean-up/lambda_function.py +++ b/terraform/environments/hmpps-domain-services/lambda/ad-clean-up/lambda_function.py @@ -1,88 +1,106 @@ import json import boto3 -from ldap3 import Server, Connection, ALL +from ldap3 import Server, Connection, SUBTREE # checks for objects within active directory -def check_ad_for_object(object): - - # create a secrets manager client - secrets_manager_client = boto3.client('secretsmanager') +def check_ad_for_object(hostname, domain_fqdn, domain_name, search_base): - test_domain = 'azure.noms.root' - prod_domain = 'azure.hmpp.root' + # create a secrets manager connection + secrets_manager = boto3.client('secretsmanager') # extract the secret value from hmpps-domain-services-test / hmpps-domain-services-prod - test_secret = '/microsoft/AD/azure.noms.root/shared-passwords' # this acould be variablised - prod_secret = '/microsoft/AD/azure.hmpp.root/shared-passwords' - - # password logic to be added DSOS-2545 - - response = secrets_manager_client.get_secret_value(SecretId=secret_name) - secret_data = response['SecretString'] - - # extract the secret value from hmpps-domain-services-prod - - response = secrets_manager_client.get_secret_value(SecretId=secret_name) + secret_name = f"/microsoft/AD/{domain_fqdn}/shared-passwords" + response = secrets_manager.get_secret_value(SecretId=secret_name) secret_data = response['SecretString'] # parse the JSON format secret data secret_json = json.loads(secret_data) - ad_password = secret_json['aws-lambda'] + ad_password = secret_json.get('svc_join_domain') - # dev test domain controller connection details - test_server = Server('MGMCW0002.{test_domain}:389', get_info=ALL) - test_username = r'azure\aws-lambda' - test_password = ad_password - - # preprod and prod domain controller connection details - prod_server = Server('MGMCW0002.{prod_domain}:389', get_info=ALL) - prod_username = r'azure\aws-lambda' - prod_password = ad_password + # domain connection details + domain_controller = Server(f'{domain_fqdn}:389') + ad_username = rf'{domain_name}\aws-lambda' - with Connection(server, user=username, password=password, auto_bind=True) as conn: - search_base = 'ou=Managed-Windows-Servers,ou=Computers,dc=azure,dc=noms,dc=root' - search_filter = f'(sAMAccountName={object})' - - search_result = conn.search(search_base, search_filter) # not doing anything with this right now need to pass in result into print and delete + with Connection(Server, user=ad_username, password=ad_password, auto_bind=True) as conn: + ad_search = search_base + search_filter = f'(sAMAccountName={hostname})' + # subtree for recursive search through defined OU + search_result = conn.search(ad_search, search_filter, SUBTREE) print(search_result) - + if conn.entries: # Get the distinguished name (DN) of the found object object_dn = conn.entries[0].entry_dn print(object_dn) - print(f"The object {object} is present in Active Directory and will be deleted.") - conn.delete(object_dn) + print(f"The object {object_dn} is present in Active Directory and will be deleted...") + # conn.delete(object_dn) # action removed during testing + return 0 # success status else: - print(f"The object {object} is not found in Active Directory - no further action taken.") + print(f"The terminated server object {hostname} was not found in Active Directory - no further action taken.") + return 1 # object not found status -# function to iterate through instance tags +# function to iterate through instance tags def get_tag_value(tags, key): for tag in tags: if tag['Key'] == key: return tag['Value'] return None +# function to determine test or prod domain values to be used +def determine_domain(environment_tag): + domain_info = {} + if "development" in environment_tag.split('-') or "test" in environment_tag.split('-'): + domain_info['domain_type'] = "dev/test" + domain_info['domain_name'] = "azure" + domain_info['domain_fqdn'] = "azure.noms.root" + domain_info['search_base'] = "ou=Managed-Windows-Servers,ou=Computers,dc=azure,dc=noms,dc=root" + # domain_info['account'] = "hmpps-domain-services-test" + elif "preproduction" in environment_tag.split('-') or "production" in environment_tag.split('-'): + domain_info['domain_type'] = "preprod/prod" + domain_info['domain_name'] = "hmpp" + domain_info['domain_fqdn'] = "azure.hmpp.root" + domain_info['search_base'] = "ou=MEMBER_SERVERS,dc=azure,dc=hmpp,dc=root" + # domain_info['account'] = "hmpps-domain-services-production" + else: + print("Unexpected environment-name tag. Aborting lambda function...") + return None + return domain_info + # function to search active directory if an instance is stopped, final iteration will be state terminated def lambda_handler(event, context): - if event['detail']['state'] == 'stopped': + + if event['detail']['state'] == 'stopped': # to be updated to terminated instance_id = event['detail']['instance-id'] + # creates an ec2 connection for terminated instance ec2 = boto3.client('ec2') response = ec2.describe_instances(InstanceIds=[instance_id]) - + # return the tags associated with the terminated instance tags = response['Reservations'][0]['Instances'][0]['Tags'] + # terminated instance server-name value, same as hostname resource_name = 'server-name' - resource_environment = 'environment' + + # obtain the hostame for the terminated server hostname = get_tag_value(tags, resource_name) - environment = get_tag_value(tags, resource_environment) + print(f"Server hostname is: {hostname}") - if hostname is not None: - check_ad_for_object(hostname) + # obtain terminated instance environment-name value + resource_environment = 'environment-name' + environment_tag = get_tag_value(tags, resource_environment) + + # determine appropriate domain variables + domain = determine_domain(environment_tag) + print("Domain address: {}".format(domain['domain_type'])) + + # pass hostname and domain variables into AD oject deletion function + if hostname is not None and domain is not None: + check_ad_for_object(hostname, domain['domain_fqdn'], domain['domain_name'], domain['search_base']) + print(f"The Active Directory object {hostname} has been deleted.") else: - print(f"The tag '{resource_name}' was not found for the instance.") + print(f"The '{resource_name}' tag was not found for the terminated instance.") # 200 http response lambda run successful return { 'statusCode': 200, - 'body': 'Active Directory search complete. Check logs for results' + 'body': 'Active Directory clean up complete. Computer object {resource_name} has been removed.' } diff --git a/terraform/environments/hmpps-domain-services/lambda/ad-cleanup/ad-cleanup-lambda-payload-test.zip b/terraform/environments/hmpps-domain-services/lambda/ad-cleanup/ad-cleanup-lambda-payload-test.zip deleted file mode 100644 index a92de137aee..00000000000 Binary files a/terraform/environments/hmpps-domain-services/lambda/ad-cleanup/ad-cleanup-lambda-payload-test.zip and /dev/null differ diff --git a/terraform/environments/hmpps-domain-services/locals_domain.tf b/terraform/environments/hmpps-domain-services/locals_domain.tf index 28fa4ed304c..24452f36302 100644 --- a/terraform/environments/hmpps-domain-services/locals_domain.tf +++ b/terraform/environments/hmpps-domain-services/locals_domain.tf @@ -7,9 +7,11 @@ locals { "arn:aws:iam::${module.environment.account_ids.hmpps-domain-services-test}:role/EC2HmppsDomainSecretsRole", "arn:aws:iam::${module.environment.account_ids.corporate-staff-rostering-development}:role/EC2HmppsDomainSecretsRole", "arn:aws:iam::${module.environment.account_ids.corporate-staff-rostering-test}:role/EC2HmppsDomainSecretsRole", - "arn:aws:iam::${module.environment.account_ids.corporate-staff-rostering-development}:role/AmazonSSMRoleForInstancesQuickSetup", "arn:aws:iam::${module.environment.account_ids.planetfm-development}:role/EC2HmppsDomainSecretsRole", "arn:aws:iam::${module.environment.account_ids.planetfm-test}:role/EC2HmppsDomainSecretsRole", + "arn:aws:iam::${module.environment.account_ids.corporate-staff-rostering-test}:role/LambdaFunctionADObjectCleanUp", # testing + # "arn:aws:iam::${module.environment.account_ids.hmpps-domain-services-development}:role/LambdaFunctionADObjectCleanUp", # to be added after hmpps dev apply + ] preproduction = [] production = [ diff --git a/terraform/environments/hmpps-domain-services/locals_production.tf b/terraform/environments/hmpps-domain-services/locals_production.tf index 83fc23a7aaa..7dc983b9dd4 100644 --- a/terraform/environments/hmpps-domain-services/locals_production.tf +++ b/terraform/environments/hmpps-domain-services/locals_production.tf @@ -129,6 +129,7 @@ locals { { name = "development", type = "NS", ttl = "86400", records = ["ns-1447.awsdns-52.org", "ns-1826.awsdns-36.co.uk", "ns-1022.awsdns-63.net", "ns-418.awsdns-52.com", ] }, { name = "test", type = "NS", ttl = "86400", records = ["ns-134.awsdns-16.com", "ns-1426.awsdns-50.org", "ns-1934.awsdns-49.co.uk", "ns-927.awsdns-51.net", ] }, { name = "preproduction", type = "NS", ttl = "86400", records = ["ns-1509.awsdns-60.org", "ns-1925.awsdns-48.co.uk", "ns-216.awsdns-27.com", "ns-753.awsdns-30.net", ] }, + { name = "smtp", type = "A", ttl = 300, records = ["10.180.104.100", "10.180.105.100"] } # smtp.internal.network.justice.gov.uk not publicly resolvable ] lb_alias_records = [ diff --git a/terraform/environments/hmpps-domain-services/ssm-documents/winrm_https.yaml b/terraform/environments/hmpps-domain-services/ssm-documents/winrm_https.yaml new file mode 100644 index 00000000000..8a030453ee3 --- /dev/null +++ b/terraform/environments/hmpps-domain-services/ssm-documents/winrm_https.yaml @@ -0,0 +1,52 @@ +--- +schemaVersion: "2.2" +description: "SSM Document for enabling WinRM over HTTPS" +mainSteps: + - name: EnableWinRMHTTPS + action: aws:runPowerShellScript + precondition: + StringEquals: + - platformType + - Windows + inputs: + runCommand: + - | + $ErrorActionPreference = "Stop"; + $HostName = $env:COMPUTERNAME + $HostIP=(Get-NetAdapter| Get-NetIPAddress).IPv4Address|Out-String + + # Create a self-signed certificate + $HostSSCert = New-SelfSignedCertificate -DnsName $HostName,$HostIP -CertStoreLocation Cert:\LocalMachine\My + + # Remove default listeners + Get-ChildItem wsman:\localhost\Listener\ | Where-Object -Property Keys -like 'Transport=HTTP*' | Remove-Item -Recurse + + # Create a new listener bound to the self-signed certificate + New-Item -Path WSMan:\localhost\Listener\ -Transport HTTPS -Address * -CertificateThumbPrint $HostSSCert.Thumbprint -Force + + $FirewallRules = Get-NetFirewallRule + $WinRMHttpsRule = @{ + DisplayName = "WinRM - Powershell remoting HTTPS-In" + LocalPort = 5986 + Protocol = "TCP" + Action = "Allow" + Profile = "Any" + } + + # Create a firewall rule for WinRM HTTPS traffic if it does not exist + if (-not $FirewallRules.DisplayName.Contains($WinRMHttpsRule.DisplayName)) { + New-NetFirewallRule @WinRMHttpsRule + } + + Restart-Service WinRM + + # Test WinRM + Export-Certificate -Cert $HostSSCert -FilePath c:\SSL_PS_Remoting.cer + Import-Certificate -FilePath c:\SSL_PS_Remoting.cer -CertStoreLocation Cert:\LocalMachine\root\ + del c:\SSL_PS_Remoting.cer + + if(Test-WSMan -ComputerName $HostName -Authentication Negotiate -UseSSL){ + Write-Host "WinRM HTTPS is enabled" + } else { + Write-Error "WinRM HTTPS is not enabled" + } \ No newline at end of file diff --git a/terraform/environments/maat/api-gw.tf b/terraform/environments/maat/api-gw.tf index 8571f8ac817..92d5ee825d2 100644 --- a/terraform/environments/maat/api-gw.tf +++ b/terraform/environments/maat/api-gw.tf @@ -52,15 +52,6 @@ resource "aws_apigatewayv2_route" "maat_api_route_crime_means_assessment" { target = "integrations/${aws_apigatewayv2_integration.maat_api_integration.id}" } -resource "aws_apigatewayv2_route" "maat_api_route_crown_court_proceeding" { - api_id = aws_apigatewayv2_api.maat_api_gateway.id - route_key = "ANY /api/internal/v1/crowncourtproceeding" - authorization_type = "JWT" - authorization_scopes = ["${local.application_name}/${local.maat_api_api_scope}"] - authorizer_id = aws_apigatewayv2_authorizer.maat_api_authorizer.id - target = "integrations/${aws_apigatewayv2_integration.maat_api_integration.id}" -} - resource "aws_apigatewayv2_route" "maat_api_route_eform_staging" { api_id = aws_apigatewayv2_api.maat_api_gateway.id route_key = "ANY /api/eform/{proxy+}" @@ -169,10 +160,10 @@ resource "aws_route53_record" "external_validation" { count = local.environment == "production" ? 0 : 1 allow_overwrite = true - name = local.domain_name_main[0] - records = local.domain_record_main + name = local.maat_api_domain_name_main[0] + records = local.maat_api_domain_record_main ttl = 60 - type = local.domain_type_main[0] + type = local.maat_api_domain_type_main[0] zone_id = data.aws_route53_zone.network-services.zone_id } @@ -181,16 +172,16 @@ resource "aws_route53_record" "external_validation_subdomain" { count = local.environment == "production" ? 0 : 1 allow_overwrite = true - name = local.domain_name_sub[0] - records = local.domain_record_sub + name = local.maat_api_domain_name_sub[0] + records = local.maat_api_domain_record_sub ttl = 60 - type = local.domain_type_sub[0] + type = local.maat_api_domain_type_sub[0] zone_id = data.aws_route53_zone.external.zone_id } resource "aws_acm_certificate_validation" "maat_api_acm_certificate_validation" { certificate_arn = aws_acm_certificate.maat_api_acm_certificate.arn - validation_record_fqdns = [local.domain_name_main[0], local.domain_name_sub[0]] + validation_record_fqdns = [local.maat_api_domain_name_main[0], local.maat_api_domain_name_sub[0]] } resource "aws_apigatewayv2_api_mapping" "maat_api_mapping" { diff --git a/terraform/environments/maat/api-param.tf b/terraform/environments/maat/api-param.tf index 7419d286484..1043bf87a22 100644 --- a/terraform/environments/maat/api-param.tf +++ b/terraform/environments/maat/api-param.tf @@ -7,7 +7,7 @@ resource "aws_ssm_parameter" "data_source_username" { value = "replace in console" lifecycle { ignore_changes = [ - "value", + value, ] } } @@ -18,7 +18,7 @@ resource "aws_ssm_parameter" "data_source_password" { value = "replace in console" lifecycle { ignore_changes = [ - "value", + value, ] } } @@ -29,7 +29,7 @@ resource "aws_ssm_parameter" "cda_client_id" { value = "replace in console" lifecycle { ignore_changes = [ - "value", + value, ] } } @@ -40,7 +40,7 @@ resource "aws_ssm_parameter" "cda_client_secret" { value = "replace in console" lifecycle { ignore_changes = [ - "value", + value, ] } } @@ -51,7 +51,7 @@ resource "aws_ssm_parameter" "togdata_datasource_password" { value = "replace in console" lifecycle { ignore_changes = [ - "value", + value, ] } } \ No newline at end of file diff --git a/terraform/environments/maat/application_variables.json b/terraform/environments/maat/application_variables.json index 2d0a76b2f9f..611abea22d6 100644 --- a/terraform/environments/maat/application_variables.json +++ b/terraform/environments/maat/application_variables.json @@ -45,7 +45,7 @@ "maat_api_alb_4xx_alarm_threshold": 10, "maat_api_pagerduty_integration_key_name": "laa_maat_api_nonprod_alarms", "maat_api_api_scope": "standard", - "domain_name": "modernisation-platform.service.justice.gov.uk", + "cloudfront_domain_name": "modernisation-platform.service.justice.gov.uk", "ext_lb_enable_deletion_protection": "false", "ami_id": "ami-0631049bf050d0d46", "instance_type": "m5.large", @@ -54,7 +54,7 @@ "ec2_asg_max_size": "2", "ec2_cpu_scaling_up_threshold": "74", "ec2_cpu_scaling_down_threshold": "51", - "docker_image_tag": "19af94e9", + "docker_image_tag": "development", "region": "eu-west-2", "maat_orch_base_url": "https://laa-maat-orchestration-dev.apps.live.cloud-platform.service.justice.gov.uk", "maat_ccp_base_url": "https://laa-crown-court-proceeding-dev.apps.live.cloud-platform.service.justice.gov.uk", @@ -69,9 +69,13 @@ "maat_mlra_url": "https://mlra.dev.legalservices.gov.uk", "maat_caa_base_url": "https://w2vr5w4fke.execute-api.eu-west-2.amazonaws.com/v1", "maat_cma_base_url": "https://laa-crime-means-assessment-dev.apps.live.cloud-platform.service.justice.gov.uk", - "maat_aws_logs_group": "MAAT-ECS", + "maat_ecs_log_group": "MAAT-ECS", + "maat_ec2_log_group": "MAAT-EC2", "maat_aws_stream_prefix": "MAAT-app", - "SSM_managed_core_policy_arn": "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" + "SSM_managed_core_policy_arn": "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", + "maat_ecs_scaling_target_max": "2", + "maat_ecs_scaling_target_min": "1", + "maat_ecs_service_desired_count": "1" }, "test": { "example_var": "test-data", @@ -81,7 +85,8 @@ "maat_api_ecs_memory": 2048, "maat_api_ecs_container_cpu": 922, "maat_api_ecs_container_memory": 1792, - "maat_api_pagerduty_integration_key_name": "laa_maat_api_nonprod_alarms" + "maat_api_pagerduty_integration_key_name": "laa_maat_api_nonprod_alarms", + "cloudfront_domain_name": "modernisation-platform.service.justice.gov.uk" }, "preproduction": { "example_var": "preproduction-data", @@ -91,7 +96,8 @@ "maat_api_ecs_memory": 3072, "maat_api_ecs_container_cpu": 922, "maat_api_ecs_container_memory": 2816, - "maat_api_pagerduty_integration_key_name": "laa_maat_api_nonprod_alarms" + "maat_api_pagerduty_integration_key_name": "laa_maat_api_nonprod_alarms", + "cloudfront_domain_name": "modernisation-platform.service.justice.gov.uk" }, "production": { "example_var": "production-data", @@ -102,7 +108,8 @@ "maat_api_ecs_container_cpu": 922, "maat_api_ecs_container_memory": 2816, "maat_api_pagerduty_integration_key_name": "laa_maat_api_prod_alarms", - "ext_lb_enable_deletion_protection": "true" + "ext_lb_enable_deletion_protection": "true", + "cloudfront_domain_name": "meansassessment.service.justice.gov.uk" } } } diff --git a/terraform/environments/maat/cloudfront.tf b/terraform/environments/maat/cloudfront.tf index 4c5b781cf0f..0ac90e1974f 100644 --- a/terraform/environments/maat/cloudfront.tf +++ b/terraform/environments/maat/cloudfront.tf @@ -1,8 +1,10 @@ locals { application_url_prefix = "meansassessment" - lower_env_url = "${local.application_url_prefix}.${var.networking[0].business-unit}-${local.environment}.${local.application_data.accounts[local.environment].domain_name}" + lower_env_cloudfront_url = "${local.application_url_prefix}.${data.aws_route53_zone.external.name}" custom_header = "X-Custom-Header-LAA-${upper(local.application_name)}" - cloudfront_alias = local.environment == "production" ? local.application_data.accounts[local.environment].domain_name : local.lower_env_url + + # TODO Note that the application variable's domain_name will be the actual CloudFront alias for production + cloudfront_alias = local.environment == "production" ? local.application_data.accounts[local.environment].cloudfront_domain_name : local.lower_env_cloudfront_url cloudfront_default_cache_behavior = { @@ -160,104 +162,159 @@ resource "aws_s3_bucket_public_access_block" "cloudfront" { } } -# TODO Commenting out CloudFront code as certificate is not validated yet -# resource "aws_cloudfront_distribution" "external" { -# http_version = "http2" -# origin { -# domain_name = aws_lb.external.dns_name -# origin_id = aws_lb.external.id -# custom_origin_config { -# http_port = 80 # This port was not defined in CloudFormation, but should not be used anyways, only required by Terraform -# https_port = 443 -# origin_protocol_policy = "https-only" -# origin_ssl_protocols = ["TLSv1.2"] -# origin_read_timeout = 60 -# origin_keepalive_timeout = 60 -# } -# custom_header { -# name = local.custom_header -# value = data.aws_secretsmanager_secret_version.cloudfront.secret_string -# } -# } -# enabled = "true" -# aliases = [local.cloudfront_alias] -# default_cache_behavior { -# target_origin_id = aws_lb.external.id -# smooth_streaming = lookup(local.cloudfront_default_cache_behavior, "smooth_streaming", null) -# allowed_methods = lookup(local.cloudfront_default_cache_behavior, "allowed_methods", null) -# cached_methods = lookup(local.cloudfront_default_cache_behavior, "cached_methods", null) -# forwarded_values { -# query_string = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_query_string", null) -# headers = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_headers", null) -# cookies { -# forward = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_cookies_forward", null) -# whitelisted_names = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_cookies_whitelisted_names", null) -# } -# } -# viewer_protocol_policy = lookup(local.cloudfront_default_cache_behavior, "viewer_protocol_policy", null) -# } - -# dynamic "ordered_cache_behavior" { -# for_each = local.cloudfront_ordered_cache_behavior -# content { -# target_origin_id = aws_lb.external.id -# smooth_streaming = lookup(ordered_cache_behavior.value, "smooth_streaming", null) -# path_pattern = lookup(ordered_cache_behavior.value, "path_pattern", null) -# min_ttl = lookup(ordered_cache_behavior.value, "min_ttl", null) -# default_ttl = lookup(ordered_cache_behavior.value, "default_ttl", null) -# max_ttl = lookup(ordered_cache_behavior.value, "max_ttl", null) -# allowed_methods = lookup(ordered_cache_behavior.value, "allowed_methods", null) -# cached_methods = lookup(ordered_cache_behavior.value, "cached_methods", null) -# forwarded_values { -# query_string = lookup(ordered_cache_behavior.value, "forwarded_values_query_string", null) -# headers = lookup(ordered_cache_behavior.value, "forwarded_values_headers", null) -# cookies { -# forward = lookup(ordered_cache_behavior.value, "forwarded_values_cookies_forward", null) -# whitelisted_names = lookup(ordered_cache_behavior, "forwarded_values_cookies_whitelisted_names", null) -# } -# } -# viewer_protocol_policy = lookup(ordered_cache_behavior.value, "viewer_protocol_policy", null) -# } -# } - -# price_class = "PriceClass_100" - -# viewer_certificate { -# acm_certificate_arn = aws_acm_certificate.cloudfront.arn -# ssl_support_method = "sni-only" -# minimum_protocol_version = "TLSv1.2_2018" -# } - -# logging_config { -# include_cookies = false -# bucket = aws_s3_bucket.cloudfront.bucket_domain_name -# prefix = local.application_name -# } +resource "aws_cloudfront_distribution" "external" { + http_version = "http2" + origin { + domain_name = aws_lb.external.dns_name + origin_id = aws_lb.external.id + custom_origin_config { + http_port = 80 # This port was not defined in CloudFormation, but should not be used anyways, only required by Terraform + https_port = 443 + origin_protocol_policy = "https-only" + origin_ssl_protocols = ["TLSv1.2"] + origin_read_timeout = 60 + origin_keepalive_timeout = 60 + } + custom_header { + name = local.custom_header + value = data.aws_secretsmanager_secret_version.cloudfront.secret_string + } + } + enabled = "true" + aliases = [local.cloudfront_alias] + default_cache_behavior { + target_origin_id = aws_lb.external.id + smooth_streaming = lookup(local.cloudfront_default_cache_behavior, "smooth_streaming", null) + allowed_methods = lookup(local.cloudfront_default_cache_behavior, "allowed_methods", null) + cached_methods = lookup(local.cloudfront_default_cache_behavior, "cached_methods", null) + forwarded_values { + query_string = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_query_string", null) + headers = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_headers", null) + cookies { + forward = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_cookies_forward", null) + whitelisted_names = lookup(local.cloudfront_default_cache_behavior, "forwarded_values_cookies_whitelisted_names", null) + } + } + viewer_protocol_policy = lookup(local.cloudfront_default_cache_behavior, "viewer_protocol_policy", null) + } + + dynamic "ordered_cache_behavior" { + for_each = local.cloudfront_ordered_cache_behavior + content { + target_origin_id = aws_lb.external.id + smooth_streaming = lookup(ordered_cache_behavior.value, "smooth_streaming", null) + path_pattern = lookup(ordered_cache_behavior.value, "path_pattern", null) + min_ttl = lookup(ordered_cache_behavior.value, "min_ttl", null) + default_ttl = lookup(ordered_cache_behavior.value, "default_ttl", null) + max_ttl = lookup(ordered_cache_behavior.value, "max_ttl", null) + allowed_methods = lookup(ordered_cache_behavior.value, "allowed_methods", null) + cached_methods = lookup(ordered_cache_behavior.value, "cached_methods", null) + forwarded_values { + query_string = lookup(ordered_cache_behavior.value, "forwarded_values_query_string", null) + headers = lookup(ordered_cache_behavior.value, "forwarded_values_headers", null) + cookies { + forward = lookup(ordered_cache_behavior.value, "forwarded_values_cookies_forward", null) + whitelisted_names = lookup(ordered_cache_behavior, "forwarded_values_cookies_whitelisted_names", null) + } + } + viewer_protocol_policy = lookup(ordered_cache_behavior.value, "viewer_protocol_policy", null) + } + } + + price_class = "PriceClass_100" + + viewer_certificate { + acm_certificate_arn = aws_acm_certificate.cloudfront.arn + ssl_support_method = "sni-only" + minimum_protocol_version = "TLSv1.2_2018" + } + + logging_config { + include_cookies = false + bucket = aws_s3_bucket.cloudfront.bucket_domain_name + prefix = local.application_name + } -# web_acl_id = aws_waf_web_acl.waf_acl.id + web_acl_id = aws_waf_web_acl.waf_acl.id + + # This is a required block in Terraform. Here we are having no geo restrictions. + restrictions { + geo_restriction { + restriction_type = "none" + locations = [] + } + } -# # This is a required block in Terraform. Here we are having no geo restrictions. -# restrictions { -# geo_restriction { -# restriction_type = "none" -# locations = [] -# } -# } +# is_ipv6_enabled = true -# # is_ipv6_enabled = true + tags = local.tags -# tags = local.tags +} -# } +resource "aws_route53_record" "cloudfront-non-prod" { + count = local.environment != "production" ? 1 : 0 + provider = aws.core-vpc + zone_id = data.aws_route53_zone.external.zone_id + name = "${local.application_url_prefix}.${data.aws_route53_zone.external.name}" + type = "A" + alias { + name = aws_cloudfront_distribution.external.domain_name + zone_id = aws_cloudfront_distribution.external.hosted_zone_id + evaluate_target_health = true + } +} + +resource "aws_route53_record" "cloudfront-prod" { + count = local.environment == "production" ? 1 : 0 + provider = aws.core-network-services + zone_id = data.aws_route53_zone.production-network-services.zone_id + name = local.application_data.accounts[local.environment].cloudfront_domain_name # TODO Production URL to be confirmed + type = "A" + alias { + name = aws_cloudfront_distribution.external.domain_name + zone_id = aws_cloudfront_distribution.external.hosted_zone_id + evaluate_target_health = true + } +} resource "aws_acm_certificate" "cloudfront" { - domain_name = local.application_data.accounts[local.environment].domain_name + domain_name = local.application_data.accounts[local.environment].cloudfront_domain_name validation_method = "DNS" provider = aws.us-east-1 - subject_alternative_names = local.environment == "production" ? null : [local.lower_env_url] + subject_alternative_names = local.environment == "production" ? null : [local.lower_env_cloudfront_url] tags = local.tags # TODO Set prevent_destroy to true to stop Terraform destroying this resource in the future if required lifecycle { prevent_destroy = false } -} \ No newline at end of file +} + +resource "aws_route53_record" "cloudfront_external_validation" { + provider = aws.core-network-services + + count = local.environment == "production" ? 0 : 1 + allow_overwrite = true + name = local.cloudfront_domain_name_main[0] + records = local.cloudfront_domain_record_main + ttl = 60 + type = local.cloudfront_domain_type_main[0] + zone_id = data.aws_route53_zone.network-services.zone_id +} + +resource "aws_route53_record" "cloudfront_external_validation_subdomain" { + provider = aws.core-vpc + + count = local.environment == "production" ? 0 : 1 + allow_overwrite = true + name = local.cloudfront_domain_name_sub[0] + records = local.cloudfront_domain_record_sub + ttl = 60 + type = local.cloudfront_domain_type_sub[0] + zone_id = data.aws_route53_zone.external.zone_id +} + +resource "aws_acm_certificate_validation" "cloudfront" { + provider = aws.us-east-1 + certificate_arn = aws_acm_certificate.cloudfront.arn + validation_record_fqdns = [local.cloudfront_domain_name_main[0], local.cloudfront_domain_name_sub[0]] +} diff --git a/terraform/environments/maat/data.tf b/terraform/environments/maat/data.tf index 96a2521d17e..a056f670559 100644 --- a/terraform/environments/maat/data.tf +++ b/terraform/environments/maat/data.tf @@ -1 +1,11 @@ #### This file can be used to store data specific to the member account #### + +# Note - this is only used in production, but we use application variable for its name to avoid an error in non-prod envs +# This means for non-prod, the cloudfront_domain_name will be "modernisation-platform.service.justice.gov.uk" +# For production, this will be the actual route53 hosted zone name, which will be the same as the A record name, e.g. "meansassessment.service.justice.gov.uk" + +data "aws_route53_zone" "production-network-services" { + provider = aws.core-network-services + name = local.application_data.accounts[local.environment].cloudfront_domain_name + private_zone = false +} diff --git a/terraform/environments/maat/locals.tf b/terraform/environments/maat/locals.tf index 76c0007ae8e..49704ec73d3 100644 --- a/terraform/environments/maat/locals.tf +++ b/terraform/environments/maat/locals.tf @@ -4,18 +4,52 @@ locals { env_account_id = local.environment_management.account_ids[terraform.workspace] env_account_region = data.aws_region.current.id - # create name, record,type for monitoring lb aka maat_api_lb - domain_types = { for dvo in aws_acm_certificate.maat_api_acm_certificate.domain_validation_options : dvo.domain_name => { + # For Route53 validation for MAAT API + maat_api_domain_types = { for dvo in aws_acm_certificate.maat_api_acm_certificate.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type } } + maat_api_domain_name_main = [for k, v in local.maat_api_domain_types : v.name if k == "modernisation-platform.service.justice.gov.uk"] + maat_api_domain_name_sub = [for k, v in local.maat_api_domain_types : v.name if k != "modernisation-platform.service.justice.gov.uk"] + maat_api_domain_record_main = [for k, v in local.maat_api_domain_types : v.record if k == "modernisation-platform.service.justice.gov.uk"] + maat_api_domain_record_sub = [for k, v in local.maat_api_domain_types : v.record if k != "modernisation-platform.service.justice.gov.uk"] + maat_api_domain_type_main = [for k, v in local.maat_api_domain_types : v.type if k == "modernisation-platform.service.justice.gov.uk"] + maat_api_domain_type_sub = [for k, v in local.maat_api_domain_types : v.type if k != "modernisation-platform.service.justice.gov.uk"] + + # For CloudFront validation for MAAT + + cloudfront_domain_types = { for dvo in aws_acm_certificate.cloudfront.domain_validation_options : dvo.domain_name => { + name = dvo.resource_record_name + record = dvo.resource_record_value + type = dvo.resource_record_type + } + } + cloudfront_domain_name_main = [for k, v in local.cloudfront_domain_types : v.name if k == "modernisation-platform.service.justice.gov.uk"] + cloudfront_domain_name_sub = [for k, v in local.cloudfront_domain_types : v.name if k != "modernisation-platform.service.justice.gov.uk"] + cloudfront_domain_record_main = [for k, v in local.cloudfront_domain_types : v.record if k == "modernisation-platform.service.justice.gov.uk"] + cloudfront_domain_record_sub = [for k, v in local.cloudfront_domain_types : v.record if k != "modernisation-platform.service.justice.gov.uk"] + cloudfront_domain_type_main = [for k, v in local.cloudfront_domain_types : v.type if k == "modernisation-platform.service.justice.gov.uk"] + cloudfront_domain_type_sub = [for k, v in local.cloudfront_domain_types : v.type if k != "modernisation-platform.service.justice.gov.uk"] + + # For LBs validation for MAAT + lbs_prod_domain = local.environment == "production" ? "meansassessment.service.justice.gov.uk" : "modernisation-platform.service.justice.gov.uk" + + lbs_domain_types = { for dvo in aws_acm_certificate.load_balancers.domain_validation_options : dvo.domain_name => { + name = dvo.resource_record_name + record = dvo.resource_record_value + type = dvo.resource_record_type + } + } + lbs_domain_name_main = [for k, v in local.lbs_domain_types : v.name if k == "modernisation-platform.service.justice.gov.uk"] + lbs_domain_name_sub = [for k, v in local.lbs_domain_types : v.name if k != "modernisation-platform.service.justice.gov.uk"] + lbs_domain_record_main = [for k, v in local.lbs_domain_types : v.record if k == "modernisation-platform.service.justice.gov.uk"] + lbs_domain_record_sub = [for k, v in local.lbs_domain_types : v.record if k != "modernisation-platform.service.justice.gov.uk"] + lbs_domain_type_main = [for k, v in local.lbs_domain_types : v.type if k == "modernisation-platform.service.justice.gov.uk"] + lbs_domain_type_sub = [for k, v in local.lbs_domain_types : v.type if k != "modernisation-platform.service.justice.gov.uk"] + + + - domain_name_main = [for k, v in local.domain_types : v.name if k == "modernisation-platform.service.justice.gov.uk"] - domain_name_sub = [for k, v in local.domain_types : v.name if k != "modernisation-platform.service.justice.gov.uk"] - domain_record_main = [for k, v in local.domain_types : v.record if k == "modernisation-platform.service.justice.gov.uk"] - domain_record_sub = [for k, v in local.domain_types : v.record if k != "modernisation-platform.service.justice.gov.uk"] - domain_type_main = [for k, v in local.domain_types : v.type if k == "modernisation-platform.service.justice.gov.uk"] - domain_type_sub = [for k, v in local.domain_types : v.type if k != "modernisation-platform.service.justice.gov.uk"] } diff --git a/terraform/environments/maat/maat-ec2-user-data.sh b/terraform/environments/maat/maat-ec2-user-data.sh index 793782df366..5f38edd63e4 100644 --- a/terraform/environments/maat/maat-ec2-user-data.sh +++ b/terraform/environments/maat/maat-ec2-user-data.sh @@ -11,7 +11,7 @@ file = /var/log/secure buffer_duration = 5000 log_stream_name = secure/{instance_id} initial_position = start_of_file -log_group_name = ${app_name}-EC2 +log_group_name = ${maat_ec2_log_group} [/var/log/messages] datetime_format = %b %d %H:%M:%S @@ -19,7 +19,7 @@ file = /var/log/messages buffer_duration = 5000 log_stream_name = messages/{instance_id} initial_position = start_of_file -log_group_name = ${app_name}-EC2 +log_group_name = ${maat_ec2_log_group} EOF chmod 644 /etc/awslogs/awslogs.conf # Change region diff --git a/terraform/environments/maat/maat-ecs.tf b/terraform/environments/maat/maat-ecs.tf index 4c82b464b11..04b7da3ac2a 100644 --- a/terraform/environments/maat/maat-ecs.tf +++ b/terraform/environments/maat/maat-ecs.tf @@ -1,8 +1,12 @@ -###################################### -# ECS Role -###################################### +##################################### +# +# EC2 RESOURCES (from infra stack) +# +##################################### + +##### EC2 IAM Role --------- -resource "aws_iam_role" "ec2_instance_role" { +resource "aws_iam_role" "maat_ec2_instance_role" { name = "${local.application_name}-ec2-instance-role" tags = merge( local.tags, @@ -12,7 +16,6 @@ resource "aws_iam_role" "ec2_instance_role" { ) assume_role_policy = < pre-data.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -t 'dbo.*_seq' > sequences.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=data > data.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=post-data > post-data.sql - - export PGPASSWORD=$NCAS_DB_PASSWORD; - psql -U $NCAS_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f pre-data.sql - psql -U $NCAS_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f sequences.sql - psql -U $NCAS_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f data.sql - psql -U $NCAS_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f post-data.sql -fi diff --git a/terraform/environments/ncas/rds.tf b/terraform/environments/ncas/rds.tf index cee3b33b11a..8877129c1b6 100644 --- a/terraform/environments/ncas/rds.tf +++ b/terraform/environments/ncas/rds.tf @@ -84,49 +84,6 @@ data "http" "myip" { url = "http://ipinfo.io/json" } -resource "null_resource" "setup_db" { - count = local.is-development ? 0 : 1 - - depends_on = [aws_db_instance.ncas_db] - - provisioner "local-exec" { - interpreter = ["bash", "-c"] - command = "chmod +x ./migrate_db.sh; ./migrate_db.sh" - - environment = { - SOURCE_DB_HOSTNAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_HOSTNAME"] - SOURCE_DB_NAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_NAME"] - SOURCE_DB_USERNAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_USERNAME"] - SOURCE_DB_PASSWORD = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_PASSWORD"] - DB_HOSTNAME = aws_db_instance.ncas_db.address - DB_NAME = aws_db_instance.ncas_db.db_name - NCAS_DB_USERNAME = local.application_data.accounts[local.environment].db_username - NCAS_DB_PASSWORD = random_password.password.result - } - } - triggers = { - always_run = "${timestamp()}" - } -} - -// executes a local script to set up the security group for the source RDS instance. -resource "null_resource" "setup_source_rds_security_group" { - provisioner "local-exec" { - interpreter = ["bash", "-c"] - command = "chmod +x ./setup-security-group-${local.environment}.sh; ./setup-security-group-${local.environment}.sh" - - environment = { - RDS_SECURITY_GROUP = aws_security_group.modernisation_ncas_access.id - RDS_SOURCE_ACCOUNT_ACCESS_KEY = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["ACCESS_KEY"] - RDS_SOURCE_ACCOUNT_SECRET_KEY = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SECRET_KEY"] - RDS_SOURCE_ACCOUNT_REGION = "eu-west-2" - } - } - triggers = { - always_run = "${timestamp()}" - } -} - // Sets up empty database for Development environment resource "null_resource" "setup_dev_db" { count = local.is-development ? 1 : 0 diff --git a/terraform/environments/ncas/setup-security-group-development.sh b/terraform/environments/ncas/setup-security-group-development.sh deleted file mode 100644 index f4cf5fc1708..00000000000 --- a/terraform/environments/ncas/setup-security-group-development.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier postgresql-11-dev --vpc-security-group-ids sg-08244ba362f922899 sg-0e0f5cf0883f81945 sg-05ea046c ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user diff --git a/terraform/environments/ncas/setup-security-group-preproduction.sh b/terraform/environments/ncas/setup-security-group-preproduction.sh deleted file mode 100644 index 4ac4bb1592d..00000000000 --- a/terraform/environments/ncas/setup-security-group-preproduction.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier postgresql-11-staging --vpc-security-group-ids sg-08244ba362f922899 sg-0e0f5cf0883f81945 sg-05ea046c ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user diff --git a/terraform/environments/ncas/setup-security-group-production.sh b/terraform/environments/ncas/setup-security-group-production.sh deleted file mode 100644 index 4de7e43fb3f..00000000000 --- a/terraform/environments/ncas/setup-security-group-production.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier ncas --vpc-security-group-ids sg-05ea046c sg-08244ba362f922899 ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user diff --git a/terraform/environments/nomis-data-hub/locals_test.tf b/terraform/environments/nomis-data-hub/locals_test.tf index 0a2f1456ac4..df987ff0486 100644 --- a/terraform/environments/nomis-data-hub/locals_test.tf +++ b/terraform/environments/nomis-data-hub/locals_test.tf @@ -2,27 +2,11 @@ locals { test_config = { baseline_secretsmanager_secrets = { - "/ndh/t1" = local.ndh_secretsmanager_secrets - "/ndh/t2" = local.ndh_secretsmanager_secrets - "/ndh/test" = local.ndh_secretsmanager_secrets + "/ndh/t1" = local.ndh_secretsmanager_secrets + "/ndh/t2" = local.ndh_secretsmanager_secrets } baseline_iam_policies = { - Ec2TestPolicy = { - description = "Permissions required for Test EC2s" - statements = [ - { - effect = "Allow" - actions = [ - "secretsmanager:GetSecretValue", - ] - resources = [ - "arn:aws:secretsmanager:*:*:secret:/ndh/test/*", - ] - } - ] - } - Ec2t1Policy = { description = "Permissions required for t1 EC2s" statements = [ @@ -62,30 +46,6 @@ locals { }) }) - test-ndh-app-a = merge(local.ndh_app_a, { - config = merge(local.ndh_app_a.config, { - instance_profile_policies = concat(local.ndh_app_a.config.instance_profile_policies, [ - "Ec2TestPolicy", - ]) - }) - tags = merge(local.ndh_app_a.tags, { - os-type = "Linux" - nomis-data-hub-environment = "test" - }) - }) - - test-ndh-ems-a = merge(local.ndh_ems_a, { - config = merge(local.ndh_ems_a.config, { - instance_profile_policies = concat(local.ndh_ems_a.config.instance_profile_policies, [ - "Ec2TestPolicy", - ]) - }) - tags = merge(local.ndh_ems_a.tags, { - os-type = "Linux" - nomis-data-hub-environment = "test" - }) - }) - t1-ndh-app-a = merge(local.ndh_app_a, { config = merge(local.ndh_app_a.config, { instance_profile_policies = concat(local.ndh_app_a.config.instance_profile_policies, [ @@ -155,11 +115,11 @@ locals { #{ name = "t1-app", type = "A", ttl = 300, records = ["10.101.3.196"] }, #azure { name = "t1-app", type = "A", ttl = 300, records = ["10.26.8.54"] }, #aws #{ name = "t1-ems", type = "A", ttl = 300, records = ["10.101.3.197"] }, #azure - { name = "t1-ems", type = "A", ttl = 300, records = ["10.26.8.49"] }, #aws - { name = "t2-app", type = "A", ttl = 300, records = ["10.101.33.196"] }, #azure - #{ name = "t2-app", type = "A", ttl = 300, records = ["10.26.8.218"] }, #aws - { name = "t2-ems", type = "A", ttl = 300, records = ["10.101.33.197"] }, #azure - #{ name = "t2-ems", type = "A", ttl = 300, records = ["10.26.8.121"] }, #aws + { name = "t1-ems", type = "A", ttl = 300, records = ["10.26.8.49"] }, #aws + #{ name = "t2-app", type = "A", ttl = 300, records = ["10.101.33.196"] }, #azure + { name = "t2-app", type = "A", ttl = 300, records = ["10.26.8.218"] }, #aws + #{ name = "t2-ems", type = "A", ttl = 300, records = ["10.101.33.197"] }, #azure + { name = "t2-ems", type = "A", ttl = 300, records = ["10.26.8.121"] }, #aws ] } } diff --git a/terraform/environments/nomis/locals_database.tf b/terraform/environments/nomis/locals_database.tf index 28eab3f81c6..1d660a79eb4 100644 --- a/terraform/environments/nomis/locals_database.tf +++ b/terraform/environments/nomis/locals_database.tf @@ -49,7 +49,8 @@ locals { module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dso_pagerduty"].ec2_instance_cwagent_collectd_connectivity_test, ) db_connected = merge( - module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_high_priority_pagerduty"].ec2_instance_cwagent_collectd_oracle_db_connected, + # DBAs have slack integration via OEM for this so don't include pagerduty integration + module.baseline_presets.cloudwatch_metric_alarms.ec2_instance_cwagent_collectd_oracle_db_connected, ) db_backup = merge( module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_pagerduty"].ec2_instance_cwagent_collectd_oracle_db_backup, diff --git a/terraform/environments/nomis/locals_preproduction.tf b/terraform/environments/nomis/locals_preproduction.tf index 3a432b1ab1c..b10dd809d81 100644 --- a/terraform/environments/nomis/locals_preproduction.tf +++ b/terraform/environments/nomis/locals_preproduction.tf @@ -113,6 +113,7 @@ locals { baseline_secretsmanager_secrets = { "/oracle/weblogic/preprod" = local.weblogic_secretsmanager_secrets "/oracle/database/PPCNOM" = local.database_nomis_secretsmanager_secrets + "/oracle/database/PPCNOMHA" = local.database_secretsmanager_secrets "/oracle/database/PPNDH" = local.database_secretsmanager_secrets "/oracle/database/PPTRDAT" = local.database_secretsmanager_secrets "/oracle/database/PPCNMAUD" = local.database_secretsmanager_secrets diff --git a/terraform/environments/nomis/locals_production.tf b/terraform/environments/nomis/locals_production.tf index ee8794f0464..361b01c68ac 100644 --- a/terraform/environments/nomis/locals_production.tf +++ b/terraform/environments/nomis/locals_production.tf @@ -110,6 +110,7 @@ locals { baseline_secretsmanager_secrets = { "/oracle/weblogic/prod" = local.weblogic_secretsmanager_secrets "/oracle/database/PCNOM" = local.database_nomis_secretsmanager_secrets + "/oracle/database/PCNOMHA" = local.database_secretsmanager_secrets "/oracle/database/PNDH" = local.database_secretsmanager_secrets "/oracle/database/PTRDAT" = local.database_secretsmanager_secrets "/oracle/database/PCNMAUD" = local.database_secretsmanager_secrets diff --git a/terraform/environments/nomis/locals_test.tf b/terraform/environments/nomis/locals_test.tf index e9699295c6b..22bf9e861e1 100644 --- a/terraform/environments/nomis/locals_test.tf +++ b/terraform/environments/nomis/locals_test.tf @@ -457,7 +457,7 @@ locals { "/dev/sdc" = { label = "app", size = 100 } }) ebs_volume_config = merge(local.database_ec2.ebs_volume_config, { - data = { total_size = 500 } + data = { total_size = 700 } flash = { total_size = 50 } }) tags = merge(local.database_ec2.tags, { @@ -561,7 +561,7 @@ locals { "/dev/sdc" = { label = "app", size = 500 } }) ebs_volume_config = merge(local.database_ec2.ebs_volume_config, { - data = { total_size = 2000 } + data = { total_size = 2500 } flash = { total_size = 500 } }) tags = merge(local.database_ec2.tags, { diff --git a/terraform/environments/oasys/locals.tf b/terraform/environments/oasys/locals.tf index 9c8ed3d61e4..5044d1c97f1 100644 --- a/terraform/environments/oasys/locals.tf +++ b/terraform/environments/oasys/locals.tf @@ -37,6 +37,24 @@ locals { region = "eu-west-2" availability_zone = "eu-west-2a" + baseline_presets_options = { + cloudwatch_log_groups = null + # cloudwatch_metric_alarms_default_actions = ["dso_pagerduty"] + enable_application_environment_wildcard_cert = true + enable_backup_plan_daily_and_weekly = true + enable_business_unit_kms_cmks = true + enable_image_builder = true + enable_ec2_cloud_watch_agent = true + enable_ec2_self_provision = true + enable_ec2_user_keypair = true + enable_ec2_oracle_enterprise_managed_server = true + enable_shared_s3 = true # adds permissions to ec2s to interact with devtest or prodpreprod buckets + db_backup_s3 = true # adds db backup buckets + iam_policies_ec2_default = ["EC2S3BucketWriteAndDeleteAccessPolicy", "ImageBuilderS3BucketWriteAndDeleteAccessPolicy"] + s3_iam_policies = ["EC2S3BucketWriteAndDeleteAccessPolicy"] + iam_policies_filter = ["ImageBuilderS3BucketWriteAndDeleteAccessPolicy", "Ec2OracleEnterpriseManagerPolicy"] + } + ###### ### env independent webserver vars ###### @@ -138,24 +156,31 @@ locals { instance_type = "r6i.4xlarge" }) cloudwatch_metric_alarms = merge( - module.baseline_presets.cloudwatch_metric_alarms.ec2, - module.baseline_presets.cloudwatch_metric_alarms.ec2_cwagent_linux, - module.baseline_presets.cloudwatch_metric_alarms.ec2_instance_cwagent_collectd_service_status_os, - module.baseline_presets.cloudwatch_metric_alarms.ec2_instance_cwagent_collectd_service_status_app, - { - cpu-utilization-high = { - comparison_operator = "GreaterThanOrEqualToThreshold" - evaluation_periods = "120" - datapoints_to_alarm = "120" - metric_name = "CPUUtilization" - namespace = "AWS/EC2" - period = "60" - statistic = "Maximum" + # standard + module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_pagerduty"].ec2, + module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_pagerduty"].ec2_cwagent_linux, + module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dso_pagerduty"].ec2_instance_cwagent_collectd_service_status_os, + module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_pagerduty"].ec2_instance_cwagent_collectd_service_status_app, + local.environment == "production" ? {} : { + cpu-utilization-high = merge(module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_pagerduty"].ec2["cpu-utilization-high"], { + evaluation_periods = "480" + datapoints_to_alarm = "480" threshold = "95" - alarm_description = "Triggers if the average cpu remains at 95% utilization or above for 2 hours on an oasys-db instance" - alarm_actions = ["dso_pagerduty"] - } - }) + alarm_description = "Triggers if the average cpu remains at 95% utilization or above for 8 hours to allow for DB refreshes. See https://dsdmoj.atlassian.net/wiki/spaces/DSTT/pages/4326064583" + }) + cpu-iowait-high = merge(module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_pagerduty"].ec2_cwagent_linux["cpu-iowait-high"], { + evaluation_periods = "480" + datapoints_to_alarm = "480" + threshold = "40" + alarm_description = "Triggers if the amount of CPU time spent waiting for I/O to complete is continually high for 8 hours allowing for DB refreshes. See https://dsdmoj.atlassian.net/wiki/spaces/DSTT/pages/4325900634" + }) + }, + # db_connected + # DBAs have slack integration via OEM for this so don't include pagerduty integration + module.baseline_presets.cloudwatch_metric_alarms.ec2_instance_cwagent_collectd_oracle_db_connected, + # db_backup + module.baseline_presets.cloudwatch_metric_alarms_by_sns_topic["dba_pagerduty"].ec2_instance_cwagent_collectd_oracle_db_backup, + ) autoscaling_schedules = {} autoscaling_group = module.baseline_presets.ec2_autoscaling_group.default user_data_cloud_init = module.baseline_presets.ec2_instance.user_data_cloud_init.ssm_agent_ansible_no_tags @@ -276,7 +301,8 @@ locals { alarm_description = "Triggers if the average cpu remains at 95% utilization or above for 2 hours on an oasys-db instance" alarm_actions = ["dso_pagerduty"] } - }) + } + ) autoscaling_schedules = {} autoscaling_group = module.baseline_presets.ec2_autoscaling_group.default user_data_cloud_init = module.baseline_presets.ec2_instance.user_data_cloud_init.ssm_agent_ansible_no_tags @@ -293,7 +319,7 @@ locals { } "/dev/sde" = { # DATA01 label = "data" - size = 500 + size = 2000 type = "gp3" } # "/dev/sdf" = { # DATA02 @@ -310,7 +336,7 @@ locals { "/dev/sdj" = { # FLASH01 label = "flash" type = "gp3" - size = 100 + size = 300 } # "/dev/sdk" = { # FLASH02 # } @@ -418,11 +444,22 @@ locals { # other ### - baseline_secretsmanager_secrets = {} + public_key_data = jsondecode(file("./files/bastion_linux.json")) - baseline_cloudwatch_log_groups = {} baseline_cloudwatch_metric_alarms = {} baseline_cloudwatch_log_metric_filters = {} - - public_key_data = jsondecode(file("./files/bastion_linux.json")) + baseline_cloudwatch_log_groups = {} + baseline_ec2_autoscaling_groups = {} + baseline_ec2_instances = {} + baseline_iam_policies = {} + baseline_iam_roles = {} + baseline_iam_service_linked_roles = {} + baseline_key_pairs = {} + baseline_kms_grants = {} + baseline_lbs = {} + baseline_route53_resolvers = {} + baseline_route53_zones = {} + baseline_secretsmanager_secrets = {} + baseline_sns_topics = {} + baseline_ssm_parameters = {} } diff --git a/terraform/environments/oasys/locals_development.tf b/terraform/environments/oasys/locals_development.tf index 3790968fe03..10a8e7b3ff3 100644 --- a/terraform/environments/oasys/locals_development.tf +++ b/terraform/environments/oasys/locals_development.tf @@ -1,7 +1,15 @@ # environment specific settings locals { - development_baseline_presets_options = {} + development_baseline_presets_options = { + sns_topics = { + pagerduty_integrations = { + dso_pagerduty = "oasys_nonprod_alarms" + dba_pagerduty = "hmpps_shef_dba_non_prod" + dba_high_priority_pagerduty = "hmpps_shef_dba_non_prod" + } + } + } development_config = { diff --git a/terraform/environments/oasys/locals_preproduction.tf b/terraform/environments/oasys/locals_preproduction.tf index 5b30ae5fdf2..2de21f86b7a 100644 --- a/terraform/environments/oasys/locals_preproduction.tf +++ b/terraform/environments/oasys/locals_preproduction.tf @@ -1,7 +1,15 @@ # environment specific settings locals { - preproduction_baseline_presets_options = {} + preproduction_baseline_presets_options = { + sns_topics = { + pagerduty_integrations = { + dso_pagerduty = "oasys_alarms" + dba_pagerduty = "hmpps_shef_dba_low_priority" + dba_high_priority_pagerduty = "hmpps_shef_dba_low_priority" + } + } + } preproduction_config = { ec2_common = { @@ -126,9 +134,6 @@ locals { branch = "oracle_11g_oasys_patchset_addition" }) }) - instance = merge(local.database_onr_a.instance, { - instance_type = "r6i.2xlarge" - }) tags = merge(local.database_onr_a.tags, { instance-scheduling = "skip-scheduling" oracle-sids = "PPONRBOD PPOASREP PPONRSYS PPONRAUD" @@ -347,7 +352,8 @@ locals { # } (module.environment.domains.public.business_unit_environment) = { # hmpps-preproduction.modernisation-platform.service.justice.gov.uk records = [ - { name = "db.pp.${local.application_name}", type = "CNAME", ttl = "300", records = ["pp-oasys-db-a.oasys.hmpps-preproduction.modernisation-platform.service.justice.gov.uk"] }, # uncomment when db in aws is set up + { name = "db.pp.${local.application_name}", type = "CNAME", ttl = "300", records = ["pp-oasys-db-a.oasys.hmpps-preproduction.modernisation-platform.service.justice.gov.uk"] }, + { name = "db.pp.onr", type = "CNAME", ttl = "300", records = ["pp-onr-db-a.oasys.hmpps-preproduction.modernisation-platform.service.justice.gov.uk"] }, ] # lb_alias_records = [ # { name = "pp.${local.application_name}", type = "A", lbs_map_key = "public" }, # pp.oasys.hmpps-preproduction.modernisation-platform.service.justice.gov.uk @@ -365,6 +371,7 @@ locals { records = [ # { name = "db.pp.${local.application_name}", type = "A", ttl = "300", records = ["10.40.40.133"] }, # for azure { name = "db.pp.${local.application_name}", type = "CNAME", ttl = "300", records = ["pp-oasys-db-a.oasys.hmpps-preproduction.modernisation-platform.internal"] }, # for aws + { name = "db.pp.onr", type = "CNAME", ttl = "300", records = ["pp-onr-db-a.oasys.hmpps-preproduction.modernisation-platform.internal"] }, # for aws ] lb_alias_records = [ # { name = "pp.${local.application_name}", type = "A", lbs_map_key = "public" }, diff --git a/terraform/environments/oasys/locals_production.tf b/terraform/environments/oasys/locals_production.tf index 00e3175ed42..7343c53048f 100644 --- a/terraform/environments/oasys/locals_production.tf +++ b/terraform/environments/oasys/locals_production.tf @@ -1,7 +1,15 @@ # environment specific settings locals { - production_baseline_presets_options = {} + production_baseline_presets_options = { + sns_topics = { + pagerduty_integrations = { + dso_pagerduty = "oasys_alarms" + dba_pagerduty = "hmpps_shef_dba_low_priority" + dba_high_priority_pagerduty = "hmpps_shef_dba_high_priority" + } + } + } production_config = { diff --git a/terraform/environments/oasys/locals_test.tf b/terraform/environments/oasys/locals_test.tf index 9a8b4c46d2e..63551a915d5 100644 --- a/terraform/environments/oasys/locals_test.tf +++ b/terraform/environments/oasys/locals_test.tf @@ -1,9 +1,15 @@ # environment specific settings locals { - # baseline presets config test_baseline_presets_options = { enable_observability_platform_monitoring = true + sns_topics = { + pagerduty_integrations = { + dso_pagerduty = "oasys_nonprod_alarms" + dba_pagerduty = "hmpps_shef_dba_non_prod" + dba_high_priority_pagerduty = "hmpps_shef_dba_non_prod" + } + } } # baseline config diff --git a/terraform/environments/oasys/main.tf b/terraform/environments/oasys/main.tf index d2011e1bb5d..d54432deb4e 100644 --- a/terraform/environments/oasys/main.tf +++ b/terraform/environments/oasys/main.tf @@ -23,29 +23,10 @@ module "baseline_presets" { environment = module.environment ip_addresses = module.ip_addresses - options = { - cloudwatch_log_groups = null - cloudwatch_metric_alarms_default_actions = ["dso_pagerduty"] - enable_application_environment_wildcard_cert = true - enable_backup_plan_daily_and_weekly = true - enable_business_unit_kms_cmks = true - enable_image_builder = true - enable_ec2_cloud_watch_agent = true - enable_ec2_self_provision = true - enable_ec2_user_keypair = true - enable_ec2_oracle_enterprise_managed_server = true - enable_shared_s3 = true # adds permissions to ec2s to interact with devtest or prodpreprod buckets - enable_observability_platform_monitoring = lookup(local.baseline_environment_presets_options, "enable_observability_platform_monitoring", false) - db_backup_s3 = true # adds db backup buckets - iam_policies_ec2_default = ["EC2S3BucketWriteAndDeleteAccessPolicy", "ImageBuilderS3BucketWriteAndDeleteAccessPolicy"] - s3_iam_policies = ["EC2S3BucketWriteAndDeleteAccessPolicy"] - iam_policies_filter = ["ImageBuilderS3BucketWriteAndDeleteAccessPolicy", "Ec2OracleEnterpriseManagerPolicy"] - sns_topics = { - pagerduty_integrations = { - dso_pagerduty = contains(["development", "test"], local.environment) ? "oasys_nonprod_alarms" : "oasys_alarms" - } - } - } + options = merge( + local.baseline_presets_options, + local.baseline_environment_presets_options, + ) } module "baseline" { @@ -58,44 +39,107 @@ module "baseline" { aws.us-east-1 = aws.us-east-1 } - # bastion_linux = lookup(local.environment_config, "baseline_bastion_linux", null) - # iam_service_linked_roles = module.baseline_presets.iam_service_linked_roles - # rds_instances - sns_topics = module.baseline_presets.sns_topics + environment = module.environment + + # bastion_linux = merge( + # local.baseline_bastion_linux, + # lookup(local.environment_config, "baseline_bastion_linux", {}) + # ) acm_certificates = merge( module.baseline_presets.acm_certificates, lookup(local.environment_config, "baseline_acm_certificates", {}) ) - + # backups = { + # "everything" = { + # plans = merge( + # module.baseline_presets.backup_plans, + # local.baseline_backup_plans, + # lookup(local.environment_config, "baseline_backup_plans", {}) + # ) + # } + # } cloudwatch_metric_alarms = merge( local.baseline_cloudwatch_metric_alarms, lookup(local.environment_config, "baseline_cloudwatch_metric_alarms", {}) ) - cloudwatch_log_metric_filters = merge( local.baseline_cloudwatch_log_metric_filters, lookup(local.environment_config, "baseline_cloudwatch_log_metric_filters", {}) ) - cloudwatch_log_groups = merge( module.baseline_presets.cloudwatch_log_groups, local.baseline_cloudwatch_log_groups, lookup(local.environment_config, "baseline_cloudwatch_log_groups", {}) ) - ec2_autoscaling_groups = lookup(local.environment_config, "baseline_ec2_autoscaling_groups", {}) - ec2_instances = lookup(local.environment_config, "baseline_ec2_instances", {}) - environment = module.environment - iam_policies = merge(module.baseline_presets.iam_policies, lookup(local.environment_config, "baseline_iam_policies", {})) - iam_roles = module.baseline_presets.iam_roles - key_pairs = module.baseline_presets.key_pairs - kms_grants = module.baseline_presets.kms_grants - lbs = lookup(local.environment_config, "baseline_lbs", {}) + ec2_autoscaling_groups = merge( + local.baseline_ec2_autoscaling_groups, + lookup(local.environment_config, "baseline_ec2_autoscaling_groups", {}) + ) + ec2_instances = merge( + local.baseline_ec2_instances, + lookup(local.environment_config, "baseline_ec2_instances", {}) + ) + iam_policies = merge( + module.baseline_presets.iam_policies, + local.baseline_iam_policies, + lookup(local.environment_config, "baseline_iam_policies", {}) + ) + iam_roles = merge( + module.baseline_presets.iam_roles, + local.baseline_iam_roles, + lookup(local.environment_config, "baseline_iam_roles", {}) + ) + # iam_service_linked_roles = merge( + # module.baseline_presets.iam_service_linked_roles, + # local.baseline_iam_service_linked_roles, + # lookup(local.environment_config, "baseline_iam_service_linked_roles", {}) + # ) + key_pairs = merge( + module.baseline_presets.key_pairs, + local.baseline_key_pairs, + lookup(local.environment_config, "baseline_key_pairs", {}) + ) + kms_grants = merge( + module.baseline_presets.kms_grants, + local.baseline_kms_grants, + lookup(local.environment_config, "baseline_kms_grants", {}) + ) + lbs = merge( + local.baseline_lbs, + lookup(local.environment_config, "baseline_lbs", {}) + ) resource_explorer = true - route53_resolvers = module.baseline_presets.route53_resolvers - route53_zones = lookup(local.environment_config, "baseline_route53_zones", {}) - s3_buckets = merge(local.baseline_s3_buckets, module.baseline_presets.s3_buckets, lookup(local.environment_config, "baseline_s3_buckets", {})) - security_groups = local.baseline_security_groups - ssm_parameters = merge(module.baseline_presets.ssm_parameters, lookup(local.environment_config, "baseline_ssm_parameters", {})) - secretsmanager_secrets = merge(local.baseline_secretsmanager_secrets, lookup(local.environment_config, "baseline_secretsmanager_secrets", {})) + route53_resolvers = merge( + module.baseline_presets.route53_resolvers, + local.baseline_route53_resolvers, + lookup(local.environment_config, "baseline_route53_resolvers", {}) + ) + route53_zones = merge( + local.baseline_route53_zones, + lookup(local.environment_config, "baseline_route53_zones", {}) + ) + s3_buckets = merge( + module.baseline_presets.s3_buckets, + local.baseline_s3_buckets, + lookup(local.environment_config, "baseline_s3_buckets", {}) + ) + secretsmanager_secrets = merge( + local.baseline_secretsmanager_secrets, + lookup(local.environment_config, "baseline_secretsmanager_secrets", {}) + ) + security_groups = merge( + local.baseline_security_groups, + lookup(local.environment_config, "baseline_security_groups", {}) + ) + sns_topics = merge( + module.baseline_presets.sns_topics, + local.baseline_sns_topics, + lookup(local.environment_config, "baseline_sns_topics", {}) + ) + ssm_parameters = merge( + module.baseline_presets.ssm_parameters, + local.baseline_ssm_parameters, + lookup(local.environment_config, "baseline_ssm_parameters", {}), + ) } diff --git a/terraform/environments/planetfm/locals_defaults.tf b/terraform/environments/planetfm/locals_defaults.tf index f119e847a2b..b8e8e4f9fcf 100644 --- a/terraform/environments/planetfm/locals_defaults.tf +++ b/terraform/environments/planetfm/locals_defaults.tf @@ -6,9 +6,6 @@ locals { ebs_volumes_copy_all_from_ami = false }) instance = merge(module.baseline_presets.ec2_instance.instance.default, { - disable_api_termination = true - disable_api_stop = true - monitoring = true tags = { backup-plan = "daily-and-weekly" instance-scheduling = "skip-scheduling" diff --git a/terraform/environments/planetfm/locals_preproduction.tf b/terraform/environments/planetfm/locals_preproduction.tf index 345103ac54a..7695007e632 100644 --- a/terraform/environments/planetfm/locals_preproduction.tf +++ b/terraform/environments/planetfm/locals_preproduction.tf @@ -11,6 +11,10 @@ locals { }) instance = merge(local.defaults_database_ec2.instance, { instance_type = "r6i.xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -36,6 +40,10 @@ locals { }) instance = merge(local.defaults_app_ec2.instance, { instance_type = "t3.large" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -54,6 +62,10 @@ locals { }) instance = merge(local.defaults_app_ec2.instance, { instance_type = "t3.large" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -73,6 +85,10 @@ locals { }) instance = merge(local.defaults_web_ec2.instance, { instance_type = "t3.large" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -91,6 +107,10 @@ locals { }) instance = merge(local.defaults_web_ec2.instance, { instance_type = "t3.large" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume diff --git a/terraform/environments/planetfm/locals_production.tf b/terraform/environments/planetfm/locals_production.tf index 08ee8f687ae..8de92a4a920 100644 --- a/terraform/environments/planetfm/locals_production.tf +++ b/terraform/environments/planetfm/locals_production.tf @@ -12,6 +12,10 @@ locals { }) instance = merge(local.defaults_database_ec2.instance, { instance_type = "r6i.4xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -21,6 +25,8 @@ locals { "/dev/sde" = { type = "gp3", size = 500 } "/dev/sdf" = { type = "gp3", size = 100 } "/dev/sdg" = { type = "gp3", size = 85 } + "/dev/sdh" = { type = "gp3", size = 150 } # T: drive + "/dev/sdi" = { type = "gp3", size = 250 } # U: drive } tags = merge(local.defaults_database_ec2.tags, { description = "Copy of PDFDW0030 SQL Server" @@ -35,6 +41,10 @@ locals { }) instance = merge(local.defaults_database_ec2.instance, { instance_type = "r6i.4xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -44,6 +54,8 @@ locals { "/dev/sde" = { type = "gp3", size = 50 } "/dev/sdf" = { type = "gp3", size = 85 } "/dev/sdg" = { type = "gp3", size = 100 } + "/dev/sdh" = { type = "gp3", size = 150 } # T: drive + "/dev/sdi" = { type = "gp3", size = 250 } # U: drive } tags = merge(local.defaults_database_ec2.tags, { description = "copy of PDFDW0031 SQL resilient Server" @@ -60,6 +72,10 @@ locals { }) instance = merge(local.defaults_app_ec2.instance, { instance_type = "t3.xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -84,6 +100,10 @@ locals { }) instance = merge(local.defaults_app_ec2.instance, { instance_type = "t3.xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -108,6 +128,10 @@ locals { }) instance = merge(local.defaults_app_ec2.instance, { instance_type = "t3.xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -132,6 +156,10 @@ locals { }) instance = merge(local.defaults_app_ec2.instance, { instance_type = "t3.xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -149,131 +177,8 @@ locals { create_external_record = true } }) - pd-cafm-a-14-b = merge(local.defaults_app_ec2, { - config = merge(local.defaults_app_ec2.config, { - ami_name = "pd-cafm-a-14-b" - availability_zone = "${local.region}b" - }) - instance = merge(local.defaults_app_ec2.instance, { - instance_type = "t3.xlarge" - }) - ebs_volumes = { - "/dev/sda1" = { type = "gp3", size = 128 } # root volume - "/dev/sdb" = { type = "gp3", size = 200 } - } - tags = { - description = "RDS Session Host and CAFM App Server copy of PDFAW0014" - app-config-status = "pending" - os-type = "Windows" - ami = "pd-cafm-a-14-b" - component = "app" - } - route53_records = { - create_internal_record = true - create_external_record = true - } - }) - pd-cafm-a-15-a = merge(local.defaults_app_ec2, { - config = merge(local.defaults_app_ec2.config, { - ami_name = "pd-cafm-a-15-a" - availability_zone = "${local.region}a" - }) - instance = merge(local.defaults_app_ec2.instance, { - instance_type = "t3.large" - }) - ebs_volumes = { - "/dev/sda1" = { type = "gp3", size = 128 } # root volume - "/dev/sdb" = { type = "gp3", size = 100 } - } - tags = { - description = "RDS Session Broker / RDS Licence Server. Copy of PDFAW0015" - app-config-status = "pending" - os-type = "Windows" - ami = "pd-cafm-a-15-a" - component = "app" - } - route53_records = { - create_internal_record = true - create_external_record = true - } - }) - pd-cafm-a-16-b = merge(local.defaults_app_ec2, { - config = merge(local.defaults_app_ec2.config, { - ami_name = "base_windows_server_2012_r2_release_2024-01-29*" - ami_owner = "374269020027" - availability_zone = "${local.region}b" - user_data_raw = base64encode(file("./templates/user-data.yaml")) - instance_profile_policies = concat(local.defaults_app_ec2.config.instance_profile_policies, ["SSMPolicy"]) - }) - instance = merge(local.defaults_app_ec2.instance, { - instance_type = "t3.large" - }) - ebs_volumes = { - "/dev/sda1" = { type = "gp3", size = 128 } # root volume - } - cloudwatch_metric_alarms = {} # no alarms as this is an RDS test instance - tags = { - description = "RDS Test Instance" - app-config-status = "pending" - os-type = "Windows" - ami = "base_windows_server_2012_r2_release_2024-01-29" - component = "app" - } - route53_records = { - create_internal_record = true - create_external_record = true - } - }) # web servers - pd-cafm-w-5-a = merge(local.defaults_web_ec2, { - config = merge(local.defaults_web_ec2.config, { - ami_name = "pd-cafm-w-5-a" - availability_zone = "${local.region}a" - }) - instance = merge(local.defaults_web_ec2.instance, { - instance_type = "t3.large" - }) - ebs_volumes = { - "/dev/sda1" = { type = "gp3", size = 128 } # root volume - "/dev/sdb" = { type = "gp3", size = 100 } - } - tags = { - description = "CAFM Web Portal Server. Copy of PDFWW0005" - app-config-status = "pending" - os-type = "Windows" - ami = "pd-cafm-w-5-a" - component = "web" - } - route53_records = { - create_internal_record = true - create_external_record = true - } - }) - pd-cafm-w-6-b = merge(local.defaults_web_ec2, { - config = merge(local.defaults_web_ec2.config, { - ami_name = "pd-cafm-w-6-b" - availability_zone = "${local.region}b" - }) - instance = merge(local.defaults_web_ec2.instance, { - instance_type = "t3.large" - }) - ebs_volumes = { - "/dev/sda1" = { type = "gp3", size = 128 } # root volume - "/dev/sdb" = { type = "gp3", size = 100 } - } - tags = { - description = "CAFM Web Portal Server copy of PDFWW0006" - app-config-status = "pending" - os-type = "Windows" - ami = "pd-cafm-w-6-b" - component = "web" - } - route53_records = { - create_internal_record = true - create_external_record = true - } - }) pd-cafm-w-36-b = merge(local.defaults_web_ec2, { config = merge(local.defaults_web_ec2.config, { ami_name = "pd-cafm-w-36-b" @@ -281,6 +186,10 @@ locals { }) instance = merge(local.defaults_web_ec2.instance, { instance_type = "t3.xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -305,6 +214,10 @@ locals { }) instance = merge(local.defaults_web_ec2.instance, { instance_type = "t3.xlarge" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -329,6 +242,10 @@ locals { }) instance = merge(local.defaults_web_ec2.instance, { instance_type = "t3.large" + # set these to false and apply before instance can be deleted + disable_api_termination = true + disable_api_stop = true + monitoring = true }) ebs_volumes = { "/dev/sda1" = { type = "gp3", size = 128 } # root volume @@ -358,28 +275,7 @@ locals { enable_cross_zone_load_balancing = true instance_target_groups = { - web-56-80 = { - port = 80 - protocol = "HTTP" - health_check = { - enabled = true - path = "/" - healthy_threshold = 3 - unhealthy_threshold = 5 - timeout = 5 - interval = 30 - matcher = "200-399" - port = 80 - } - stickiness = { - enabled = true - type = "lb_cookie" - } - attachments = [ - { ec2_instance_name = "pd-cafm-w-5-a" }, - { ec2_instance_name = "pd-cafm-w-6-b" }, - ] - } + web-3637-80 = { port = 80 protocol = "HTTP" @@ -451,21 +347,6 @@ locals { } } rules = { - web-56-80 = { - priority = 5680 - actions = [{ - type = "forward" - target_group_name = "web-56-80" - }] - conditions = [{ - host_header = { - values = [ - "cafmwebx.planetfm.service.justice.gov.uk", - "cafmwebx.az.justice.gov.uk", - ] - } - }] - } web-3637-80 = { priority = 3637 actions = [{ @@ -510,7 +391,6 @@ locals { { name = "cafmtx", type = "CNAME", ttl = 3600, records = ["rdweb1.hmpps-domain.service.justice.gov.uk"] }, ] lb_alias_records = [ - { name = "cafmwebx", type = "A", lbs_map_key = "private" }, { name = "cafmwebx2", type = "A", lbs_map_key = "private" }, { name = "cafmtrainweb", type = "A", lbs_map_key = "private" }, ] diff --git a/terraform/environments/ppud/cloudwatch_windows.tf b/terraform/environments/ppud/cloudwatch_windows.tf index 15cbc7b8927..830a82e7913 100644 --- a/terraform/environments/ppud/cloudwatch_windows.tf +++ b/terraform/environments/ppud/cloudwatch_windows.tf @@ -333,4 +333,116 @@ resource "aws_cloudwatch_log_metric_filter" "MalwareScanFinished" { MalwareScanFinished = "$MalwareScanFinished" } } +} + +resource "aws_cloudwatch_log_metric_filter" "MalwareScanStopped" { + count = local.is-production == true ? 1 : 0 + name = "MalwareScanStopped" + log_group_name = aws_cloudwatch_log_group.Windows-Defender-Logs[count.index].name + pattern = "[date, time, Instance, MalwareScanStopped, status=1002]" + metric_transformation { + name = "MalwareScanStopped" + namespace = "WindowsDefender" + value = "1" + dimensions = { + Instance = "$Instance" + MalwareScanStopped = "$MalwareScanStopped" + } + } +} + +resource "aws_cloudwatch_log_metric_filter" "MalwareScanFailed" { + count = local.is-production == true ? 1 : 0 + name = "MalwareScanFailed" + log_group_name = aws_cloudwatch_log_group.Windows-Defender-Logs[count.index].name + pattern = "[date, time, Instance, MalwareScanFailed, status=1005]" + metric_transformation { + name = "MalwareScanFailed" + namespace = "WindowsDefender" + value = "1" + dimensions = { + Instance = "$Instance" + MalwareScanFailed = "$MalwareScanFailed" + } + } +} + +resource "aws_cloudwatch_log_metric_filter" "MalwareBehaviorDetected" { + count = local.is-production == true ? 1 : 0 + name = "MalwareBehaviorDetected" + log_group_name = aws_cloudwatch_log_group.Windows-Defender-Logs[count.index].name + pattern = "[date, time, Instance, MalwareBehaviorDetected, status=1015]" + metric_transformation { + name = "MalwareBehaviorDetected" + namespace = "WindowsDefender" + value = "1" + dimensions = { + Instance = "$Instance" + MalwareBehaviorDetected = "$MalwareBehaviorDetected" + } + } +} + +resource "aws_cloudwatch_log_metric_filter" "MalwareStateDetected" { + count = local.is-production == true ? 1 : 0 + name = "MalwareStateDetected" + log_group_name = aws_cloudwatch_log_group.Windows-Defender-Logs[count.index].name + pattern = "[date, time, Instance, MalwareStateDetected, status=1116]" + metric_transformation { + name = "MalwareStateDetected" + namespace = "WindowsDefender" + value = "1" + dimensions = { + Instance = "$Instance" + MalwareStateDetected = "$MalwareStateDetected" + } + } +} + +resource "aws_cloudwatch_log_metric_filter" "MalwareSignatureFailed" { + count = local.is-production == true ? 1 : 0 + name = "MalwareSignatureFailed" + log_group_name = aws_cloudwatch_log_group.Windows-Defender-Logs[count.index].name + pattern = "[date, time, Instance, MalwareSignatureFailed, status=2001]" + metric_transformation { + name = "MalwareSignatureFailed" + namespace = "WindowsDefender" + value = "1" + dimensions = { + Instance = "$Instance" + MalwareSignatureFailed = "$MalwareSignatureFailed" + } + } +} + +resource "aws_cloudwatch_log_metric_filter" "MalwareEngineFailed" { + count = local.is-production == true ? 1 : 0 + name = "MalwareEngineFailed" + log_group_name = aws_cloudwatch_log_group.Windows-Defender-Logs[count.index].name + pattern = "[date, time, Instance, MalwareEngineFailed, status=2003]" + metric_transformation { + name = "MalwareEngineFailed" + namespace = "WindowsDefender" + value = "1" + dimensions = { + Instance = "$Instance" + MalwareEngineFailed = "$MalwareEngineFailed" + } + } +} + +resource "aws_cloudwatch_log_metric_filter" "MalwareEngineOutofDate" { + count = local.is-production == true ? 1 : 0 + name = "MalwareEngineOutofDate" + log_group_name = aws_cloudwatch_log_group.Windows-Defender-Logs[count.index].name + pattern = "[date, time, Instance, MalwareEngineOutofDate, status=2005]" + metric_transformation { + name = "MalwareEngineOutofDate" + namespace = "WindowsDefender" + value = "1" + dimensions = { + Instance = "$Instance" + MalwareEngineOutofDate = "$MalwareEngineOutofDate" + } + } } \ No newline at end of file diff --git a/terraform/environments/pra-register/application_variables.json b/terraform/environments/pra-register/application_variables.json index 820b56ce06f..62cb1d6f490 100644 --- a/terraform/environments/pra-register/application_variables.json +++ b/terraform/environments/pra-register/application_variables.json @@ -1,14 +1,13 @@ { "accounts": { "development": { - "moj_ip": "81.134.202.29/32", "db_name": "pra_db_dev", "identifier": "pra-db-dev", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -25,14 +24,13 @@ "example_var": "test-data" }, "preproduction": { - "moj_ip": "81.134.202.29/32", "db_name": "pra_db_pre_prod", "identifier": "pra-db-pre-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -46,14 +44,13 @@ "tactical_products_db_secrets_arn": "t9n3g3" }, "production": { - "moj_ip": "81.134.202.29/32", "db_name": "pra_db_prod", "identifier": "pra-db-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", diff --git a/terraform/environments/pra-register/load_balancer.tf b/terraform/environments/pra-register/load_balancer.tf index 08eb214d4de..4beec3d1c5c 100644 --- a/terraform/environments/pra-register/load_balancer.tf +++ b/terraform/environments/pra-register/load_balancer.tf @@ -3,14 +3,6 @@ resource "aws_security_group" "pra_lb_sc" { description = "control access to the load balancer" vpc_id = data.aws_vpc.shared.id - ingress { - description = "allow access on HTTPS for the MOJ VPN" - from_port = 443 - to_port = 443 - protocol = "tcp" - cidr_blocks = [local.application_data.accounts[local.environment].moj_ip] - } - ingress { description = "allow access on HTTPS for the Dom1 Cisco VPN" from_port = 443 @@ -47,7 +39,10 @@ resource "aws_security_group" "pra_lb_sc" { "89.32.121.144/32", "194.33.192.0/25", "194.33.193.0/25", - "194.33.197.0/25" + "194.33.197.0/25", + "18.169.147.172/32", + "18.130.148.126/32", + "35.176.148.126/32" ] } diff --git a/terraform/environments/pra-register/migrate_db.sh b/terraform/environments/pra-register/migrate_db.sh deleted file mode 100644 index 4fd6845af57..00000000000 --- a/terraform/environments/pra-register/migrate_db.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -export PGPASSWORD=$PRA_DB_PASSWORD; -# if database contains schema dbo then store schema name inside variable. -SCHEMA=$(psql -h ${DB_HOSTNAME} -p 5432 -U $PRA_DB_USERNAME -d $DB_NAME -c "SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'dbo'" | grep -o 'dbo') -echo "Schema = $SCHEMA" - -if [ "$SCHEMA" == "dbo" ]; then - echo "The Schema dbo is already present in the database" -else - export PGPASSWORD=$SOURCE_DB_PASSWORD; - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=pre-data > pre-data.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -t 'dbo.*_seq' > sequences.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=data > data.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=post-data > post-data.sql - - export PGPASSWORD=$PRA_DB_PASSWORD; - psql -U $PRA_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f pre-data.sql - psql -U $PRA_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f sequences.sql - psql -U $PRA_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f data.sql - psql -U $PRA_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f post-data.sql - -fi \ No newline at end of file diff --git a/terraform/environments/pra-register/rds.tf b/terraform/environments/pra-register/rds.tf index 8c6b4afa0c5..4dc7775c9ab 100644 --- a/terraform/environments/pra-register/rds.tf +++ b/terraform/environments/pra-register/rds.tf @@ -20,28 +20,6 @@ resource "aws_db_subnet_group" "dbsubnetgroup" { subnet_ids = data.aws_subnets.shared-public.ids } -//SG for accessing the tacticalproducts source DB: -resource "aws_security_group" "modernisation_pra_access" { - provider = aws.tacticalproducts - name = "modernisation_pra_access-${local.environment}" - description = "Allow pra on modernisation platform to access the source database" - - ingress { - from_port = 5432 - to_port = 5432 - protocol = "tcp" - description = "Allow pra on modernisation platform to connect to source database" - cidr_blocks = ["${jsondecode(data.http.myip.response_body)["ip"]}/32"] - } - - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } -} - resource "aws_security_group" "postgresql_db_sc" { name = "postgres_security_group" description = "control access to the database" @@ -86,49 +64,6 @@ data "http" "myip" { url = "http://ipinfo.io/json" } -resource "null_resource" "setup_db" { - count = local.is-development ? 0 : 1 - - depends_on = [aws_db_instance.pra_db] - - provisioner "local-exec" { - interpreter = ["bash", "-c"] - command = "chmod +x ./migrate_db.sh; ./migrate_db.sh" - - environment = { - SOURCE_DB_HOSTNAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_HOSTNAME"] - SOURCE_DB_NAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_NAME"] - SOURCE_DB_USERNAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_USERNAME"] - SOURCE_DB_PASSWORD = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_PASSWORD"] - DB_HOSTNAME = aws_db_instance.pra_db.address - DB_NAME = aws_db_instance.pra_db.db_name - PRA_DB_USERNAME = local.application_data.accounts[local.environment].db_username - PRA_DB_PASSWORD = random_password.password.result - } - } - triggers = { - always_run = "${timestamp()}" - } -} - -// executes a local script to set up the security group for the source RDS instance. -resource "null_resource" "setup_source_rds_security_group" { - provisioner "local-exec" { - interpreter = ["bash", "-c"] - command = "chmod +x ./setup-security-group-${local.environment}.sh; ./setup-security-group-${local.environment}.sh" - - environment = { - RDS_SECURITY_GROUP = aws_security_group.modernisation_pra_access.id - RDS_SOURCE_ACCOUNT_ACCESS_KEY = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["ACCESS_KEY"] - RDS_SOURCE_ACCOUNT_SECRET_KEY = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SECRET_KEY"] - RDS_SOURCE_ACCOUNT_REGION = "eu-west-2" - } - } - triggers = { - always_run = "${timestamp()}" - } -} - // Sets up empty database for Development environment resource "null_resource" "setup_dev_db" { count = local.is-development ? 1 : 0 diff --git a/terraform/environments/pra-register/setup-security-group-development.sh b/terraform/environments/pra-register/setup-security-group-development.sh deleted file mode 100644 index aa0b2708f28..00000000000 --- a/terraform/environments/pra-register/setup-security-group-development.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -# To change the source DB, uncomment the line below and change the values of SOURCE_DB_HOSTNAME and SOURCE_DB_NAME in secrets manager -# aws rds modify-db-instance --db-instance-identifier postgresql-dev --vpc-security-group-ids sg-08244ba362f922899 sg-0e0f5cf0883f81945 sg-02938dce60af69c14 sg-05ea046c ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user -aws rds modify-db-instance --db-instance-identifier postgresql-staging --vpc-security-group-ids sg-08244ba362f922899 sg-0e0f5cf0883f81945 sg-04e9fe073afcc6b65 ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user \ No newline at end of file diff --git a/terraform/environments/pra-register/setup-security-group-preproduction.sh b/terraform/environments/pra-register/setup-security-group-preproduction.sh deleted file mode 100644 index 706e2cb30e7..00000000000 --- a/terraform/environments/pra-register/setup-security-group-preproduction.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier postgresql-staging --vpc-security-group-ids sg-08244ba362f922899 sg-0e0f5cf0883f81945 sg-04e9fe073afcc6b65 ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user \ No newline at end of file diff --git a/terraform/environments/pra-register/setup-security-group-production.sh b/terraform/environments/pra-register/setup-security-group-production.sh deleted file mode 100644 index 3d690b6266e..00000000000 --- a/terraform/environments/pra-register/setup-security-group-production.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier pra --vpc-security-group-ids sg-08244ba362f922899 sg-0f8613911f156df98 ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user \ No newline at end of file diff --git a/terraform/environments/tipstaff/application_variables.json b/terraform/environments/tipstaff/application_variables.json index 4d3bf4db25b..152153d98f8 100644 --- a/terraform/environments/tipstaff/application_variables.json +++ b/terraform/environments/tipstaff/application_variables.json @@ -1,14 +1,13 @@ { "accounts": { "development": { - "moj_ip": "81.134.202.29/32", "db_name": "tipstaff_db_dev", "identifier": "tipstaff-db-dev", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -26,14 +25,13 @@ "example_var": "test-data" }, "preproduction": { - "moj_ip": "81.134.202.29/32", "db_name": "tipstaff_db_pre_prod", "identifier": "tipstaff-db-pre-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -48,14 +46,13 @@ "tactical_products_db_secrets_arn": "vhUrZe" }, "production": { - "moj_ip": "81.134.202.29/32", "db_name": "tipstaff_db_prod", "identifier": "tipstaff-db-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", diff --git a/terraform/environments/tipstaff/load_balancer.tf b/terraform/environments/tipstaff/load_balancer.tf index c9dca80b0ab..ed86fa39cc3 100644 --- a/terraform/environments/tipstaff/load_balancer.tf +++ b/terraform/environments/tipstaff/load_balancer.tf @@ -4,14 +4,22 @@ resource "aws_security_group" "tipstaff_lb_sc" { vpc_id = data.aws_vpc.shared.id ingress { - description = "allow access on HTTPS for the MOJ VPN" + description = "allow access on HTTPS for the Dom1 Cisco VPN" from_port = 443 to_port = 443 protocol = "tcp" - cidr_blocks = [local.application_data.accounts[local.environment].moj_ip] + cidr_blocks = ["194.33.192.1/32"] } - // Allow all IP addresses that had load balancer access in the Tactical Products environment + ingress { + description = "allow access on HTTPS for the Global Protect VPN" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["35.176.93.186/32"] + } + + // Allow user IP addresses ingress { from_port = 443 to_port = 443 @@ -41,7 +49,10 @@ resource "aws_security_group" "tipstaff_lb_sc" { "185.191.249.100/32", "54.94.206.111/32", "194.33.193.0/25", - "178.248.34.42/32" + "178.248.34.42/32", + "18.169.147.172/32", + "18.130.148.126/32", + "35.176.148.126/32" ] } diff --git a/terraform/environments/wardship/application_variables.json b/terraform/environments/wardship/application_variables.json index 209d5c6d2a9..88627eca359 100644 --- a/terraform/environments/wardship/application_variables.json +++ b/terraform/environments/wardship/application_variables.json @@ -1,14 +1,13 @@ { "accounts": { "development": { - "moj_ip": "81.134.202.29/32", "db_name": "wardship_db_dev", "identifier": "wardship-db-dev", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -23,14 +22,13 @@ "tactical_products_db_secrets_arn": "tspb4H" }, "preproduction": { - "moj_ip": "81.134.202.29/32", "db_name": "wardship_db_pre_prod", "identifier": "wardship-db-pre-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", @@ -45,14 +43,13 @@ "tactical_products_db_secrets_arn": "kVCGj1" }, "production": { - "moj_ip": "81.134.202.29/32", "db_name": "wardship_db_prod", "identifier": "wardship-db-prod", "db_username": "dbadmin", "allocated_storage": "20", "storage_type": "gp2", "engine": "postgres", - "engine_version": "14.7", + "engine_version": "14.10", "instance_class": "db.t3.micro", "server_port_1": "80", "lb_listener_protocol_1": "HTTP", diff --git a/terraform/environments/wardship/load_balancer.tf b/terraform/environments/wardship/load_balancer.tf index 294756dbac8..4c1434cf7e5 100644 --- a/terraform/environments/wardship/load_balancer.tf +++ b/terraform/environments/wardship/load_balancer.tf @@ -4,11 +4,19 @@ resource "aws_security_group" "wardship_lb_sc" { vpc_id = data.aws_vpc.shared.id ingress { - description = "allow access on HTTPS for the MOJ VPN" + description = "allow access on HTTPS for the Dom1 Cisco VPN" from_port = 443 to_port = 443 protocol = "tcp" - cidr_blocks = [local.application_data.accounts[local.environment].moj_ip] + cidr_blocks = ["194.33.192.1/32"] + } + + ingress { + description = "allow access on HTTPS for the Global Protect VPN" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["35.176.93.186/32"] } // Allow all User IPs @@ -30,7 +38,10 @@ resource "aws_security_group" "wardship_lb_sc" { "194.33.192.0/25", "157.203.176.0/25", "201.33.21.5/32", - "54.94.206.111/32" + "54.94.206.111/32", + "18.169.147.172/32", + "18.130.148.126/32", + "35.176.148.126/32" ] } diff --git a/terraform/environments/wardship/migrate_db.sh b/terraform/environments/wardship/migrate_db.sh deleted file mode 100644 index 5632c9bd981..00000000000 --- a/terraform/environments/wardship/migrate_db.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -export PGPASSWORD=$WARDSHIP_DB_PASSWORD; -# if database contains schema dbo then store schema name inside variable. -SCHEMA=$(psql -h ${DB_HOSTNAME} -p 5432 -U $WARDSHIP_DB_USERNAME -d $DB_NAME -c "SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'dbo'" | grep -o 'dbo') -echo "Schema = $SCHEMA" - -if [ "$SCHEMA" == "dbo" ]; then - echo "The Schema dbo is already present in the database" -else - export PGPASSWORD=$SOURCE_DB_PASSWORD; - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=pre-data > pre-data.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -t 'dbo.*_seq' > sequences.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=data > data.sql - pg_dump -U $SOURCE_DB_USERNAME -h $SOURCE_DB_HOSTNAME -d $SOURCE_DB_NAME -O --section=post-data > post-data.sql - - export PGPASSWORD=$WARDSHIP_DB_PASSWORD; - psql -U $WARDSHIP_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f pre-data.sql - psql -U $WARDSHIP_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f sequences.sql - psql -U $WARDSHIP_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f data.sql - psql -U $WARDSHIP_DB_USERNAME -h $DB_HOSTNAME -d $DB_NAME -f post-data.sql - -fi \ No newline at end of file diff --git a/terraform/environments/wardship/rds.tf b/terraform/environments/wardship/rds.tf index 51c93cb3771..cbaff95582a 100644 --- a/terraform/environments/wardship/rds.tf +++ b/terraform/environments/wardship/rds.tf @@ -84,48 +84,6 @@ data "http" "myip" { url = "http://ipinfo.io/json" } -resource "null_resource" "setup_db" { - count = local.is-development ? 0 : 1 - depends_on = [aws_db_instance.wardship_db] - - provisioner "local-exec" { - interpreter = ["bash", "-c"] - command = "chmod +x ./migrate_db.sh; ./migrate_db.sh" - - environment = { - SOURCE_DB_HOSTNAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_HOSTNAME"] - SOURCE_DB_NAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_NAME"] - SOURCE_DB_USERNAME = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_USERNAME"] - SOURCE_DB_PASSWORD = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SOURCE_DB_PASSWORD"] - DB_HOSTNAME = aws_db_instance.wardship_db.address - DB_NAME = aws_db_instance.wardship_db.db_name - WARDSHIP_DB_USERNAME = local.application_data.accounts[local.environment].db_username - WARDSHIP_DB_PASSWORD = random_password.password.result - } - } - triggers = { - always_run = "${timestamp()}" - } -} - -// executes a local script to set up the security group for the source RDS instance. -resource "null_resource" "setup_source_rds_security_group" { - provisioner "local-exec" { - interpreter = ["bash", "-c"] - command = "chmod +x ./setup-security-group-${local.environment}.sh; ./setup-security-group-${local.environment}.sh" - - environment = { - RDS_SECURITY_GROUP = aws_security_group.modernisation_wardship_access.id - RDS_SOURCE_ACCOUNT_ACCESS_KEY = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["ACCESS_KEY"] - RDS_SOURCE_ACCOUNT_SECRET_KEY = jsondecode(data.aws_secretsmanager_secret_version.get_tactical_products_rds_credentials.secret_string)["SECRET_KEY"] - RDS_SOURCE_ACCOUNT_REGION = "eu-west-2" - } - } - triggers = { - always_run = "${timestamp()}" - } -} - // Sets up empty database for Development environment resource "null_resource" "setup_dev_db" { count = local.is-development ? 1 : 0 diff --git a/terraform/environments/wardship/setup-security-group-development.sh b/terraform/environments/wardship/setup-security-group-development.sh deleted file mode 100644 index 63fc5957c97..00000000000 --- a/terraform/environments/wardship/setup-security-group-development.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier postgresql-dev --vpc-security-group-ids sg-08244ba362f922899 sg-0e0f5cf0883f81945 sg-02938dce60af69c14 sg-05ea046c ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user diff --git a/terraform/environments/wardship/setup-security-group-preproduction.sh b/terraform/environments/wardship/setup-security-group-preproduction.sh deleted file mode 100644 index 706e2cb30e7..00000000000 --- a/terraform/environments/wardship/setup-security-group-preproduction.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier postgresql-staging --vpc-security-group-ids sg-08244ba362f922899 sg-0e0f5cf0883f81945 sg-04e9fe073afcc6b65 ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user \ No newline at end of file diff --git a/terraform/environments/wardship/setup-security-group-production.sh b/terraform/environments/wardship/setup-security-group-production.sh deleted file mode 100644 index 1ce01e59be2..00000000000 --- a/terraform/environments/wardship/setup-security-group-production.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/bash - -export AWS_ACCESS_KEY_ID=$RDS_SOURCE_ACCOUNT_ACCESS_KEY -export AWS_SECRET_ACCESS_KEY=$RDS_SOURCE_ACCOUNT_SECRET_KEY -export AWS_DEFAULT_REGION=$RDS_SOURCE_ACCOUNT_REGION - -aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile dts-legacy-apps-user && -aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile dts-legacy-apps-user && -aws configure set region "$AWS_DEFAULT_REGION" --profile dts-legacy-apps-user && -aws configure set output "json" --profile dts-legacy-apps-user - -aws rds modify-db-instance --db-instance-identifier Wardship --vpc-security-group-ids sg-08244ba362f922899 sg-05f6c8bdbb26422d0 ${RDS_SECURITY_GROUP} --profile dts-legacy-apps-user \ No newline at end of file diff --git a/terraform/modules/baseline_presets/cloudwatch_metric_alarms.tf b/terraform/modules/baseline_presets/cloudwatch_metric_alarms.tf index ec0e5286613..4545a6f7c4f 100644 --- a/terraform/modules/baseline_presets/cloudwatch_metric_alarms.tf +++ b/terraform/modules/baseline_presets/cloudwatch_metric_alarms.tf @@ -222,7 +222,8 @@ locals { statistic = "Maximum" threshold = "1" alarm_description = "Triggers if an oracle database defined in oracle-sids tag is disconnected. See https://dsdmoj.atlassian.net/wiki/spaces/DSTT/pages/4294246698" - alarm_actions = var.options.cloudwatch_metric_alarms_default_actions + # Slack integration is via Oracle Enterprise Management rather than cloudwatch + # alarm_actions = var.options.cloudwatch_metric_alarms_default_actions } } ec2_instance_cwagent_collectd_oracle_db_backup = { @@ -296,5 +297,19 @@ locals { alarm_actions = var.options.cloudwatch_metric_alarms_default_actions } } + network_lb = { + unhealthy-network-load-balancer-host = { + comparison_operator = "GreaterThanOrEqualToThreshold" + evaluation_periods = "3" + datapoints_to_alarm = "3" + metric_name = "UnHealthyHostCount" + namespace = "AWS/NetworkELB" + period = "60" + statistic = "Average" + threshold = "1" + alarm_description = "Triggers if the number of unhealthy network loadbalancer hosts in the target table group is at least one for 3 minutes. See https://dsdmoj.atlassian.net/wiki/spaces/DSTT/pages/4615340278" + alarm_actions = var.options.cloudwatch_metric_alarms_default_actions + } + } } }