From 15642606a89adc2ef9a9c9df7fc9b55bf61f951e Mon Sep 17 00:00:00 2001 From: Mike Ramplin Date: Mon, 19 Aug 2024 10:23:09 +0100 Subject: [PATCH] fix: DBTP-972 Ignored by Checkov baseline (#190) Co-authored-by: Gabe Naughton --- .checkov.baseline | 337 -------------------- application-load-balancer/main.tf | 19 +- domain/main.tf | 2 + elasticache-redis/e2e-tests/setup/main.tf | 3 + elasticache-redis/main.tf | 41 +++ elasticache-redis/tests/unit.tftest.hcl | 17 + environment-pipelines/codebuild.tf | 26 +- environment-pipelines/iam.tf | 2 + environment-pipelines/tests/unit.tftest.hcl | 18 ++ extensions/main.tf | 2 + opensearch/e2e-tests/setup/main.tf | 2 + opensearch/main.tf | 44 ++- opensearch/tests/unit.tftest.hcl | 13 +- postgres/lambda.tf | 24 +- postgres/rds.tf | 22 +- postgres/secrets.tf | 1 + postgres/tests/unit.tftest.hcl | 9 +- s3/main.tf | 29 ++ statefile-backend/main.tf | 28 ++ vpc/main.tf | 2 + 20 files changed, 284 insertions(+), 357 deletions(-) diff --git a/.checkov.baseline b/.checkov.baseline index 09a28e1e2..86d74e2ab 100644 --- a/.checkov.baseline +++ b/.checkov.baseline @@ -1,341 +1,4 @@ { "failed_checks": [ - { - "file": "/application-load-balancer/main.tf", - "findings": [ - { - "resource": "module.extensions-staging.module.alb.aws_lb.this", - "check_ids": [ - "CKV2_AWS_28", - "CKV_AWS_131", - "CKV_AWS_150" - ] - }, - { - "resource": "module.extensions-staging.module.alb.aws_lb_listener.alb-listener", - "check_ids": [ - "CKV_AWS_103", - "CKV_AWS_2" - ] - }, - { - "resource": "module.extensions-staging.module.alb.aws_lb_target_group.http-target-group", - "check_ids": [ - "CKV_AWS_261" - ] - }, - { - "resource": "module.extensions-staging.module.alb.aws_security_group.alb-security-group", - "check_ids": [ - "CKV_AWS_23", - "CKV2_AWS_5" - ] - } - ] - }, - { - "file": "/domain/main.tf", - "findings": [ - { - "resource": "aws_route53_zone.new-zone", - "check_ids": [ - "CKV2_AWS_38", - "CKV2_AWS_39" - ] - } - ] - }, - { - "file": "/elasticache-redis/e2e-tests/setup/main.tf", - "findings": [ - { - "resource": "aws_security_group.vpc-core-sg", - "check_ids": [ - "CKV2_AWS_5" - ] - }, - { - "resource": "aws_vpc.main", - "check_ids": [ - "CKV2_AWS_11", - "CKV2_AWS_12" - ] - } - ] - }, - { - "file": "/elasticache-redis/main.tf", - "findings": [ - { - "resource": "module.extensions-staging.module.elasticache-redis.aws_cloudwatch_log_group.redis-engine-log-group", - "check_ids": [ - "CKV_AWS_158", - "CKV_AWS_338" - ] - }, - { - "resource": "module.extensions-staging.module.elasticache-redis.aws_cloudwatch_log_group.redis-slow-log-group", - "check_ids": [ - "CKV_AWS_158", - "CKV_AWS_338" - ] - }, - { - "resource": "module.extensions-staging.module.elasticache-redis.aws_elasticache_replication_group.redis", - "check_ids": [ - "CKV_AWS_191", - "CKV_AWS_31" - ] - }, - { - "resource": "module.extensions-staging.module.elasticache-redis.aws_security_group.redis", - "check_ids": [ - "CKV_AWS_23" - ] - }, - { - "resource": "module.extensions-staging.module.elasticache-redis.aws_ssm_parameter.endpoint", - "check_ids": [ - "CKV_AWS_337" - ] - } - ] - }, - { - "file": "/environment-pipelines/codebuild.tf", - "findings": [ - { - "resource": "aws_cloudwatch_log_group.environment_pipeline_codebuild", - "check_ids": [ - "CKV_AWS_158" - ] - } - ] - }, - { - "file": "/environment-pipelines/iam.tf", - "findings": [ - { - "resource": "aws_iam_policy_document.access_artifact_store", - "check_ids": [ - "CKV_AWS_111", - "CKV_AWS_356" - ] - } - ] - }, - { - "file": "/extensions/main.tf", - "findings": [ - { - "resource": "module.extensions-staging.aws_ssm_parameter.addons", - "check_ids": [ - "CKV2_AWS_34", - "CKV_AWS_337" - ] - } - ] - }, - { - "file": "/opensearch/e2e-tests/setup/main.tf", - "findings": [ - { - "resource": "aws_vpc.main", - "check_ids": [ - "CKV2_AWS_11", - "CKV2_AWS_12" - ] - } - ] - }, - { - "file": "/opensearch/main.tf", - "findings": [ - { - "resource": "module.extensions-staging.module.opensearch.aws_cloudwatch_log_group.opensearch_log_group_audit_logs", - "check_ids": [ - "CKV_AWS_158" - ] - }, - { - "resource": "module.extensions-staging.module.opensearch.aws_cloudwatch_log_group.opensearch_log_group_es_application_logs", - "check_ids": [ - "CKV_AWS_158" - ] - }, - { - "resource": "module.extensions-staging.module.opensearch.aws_cloudwatch_log_group.opensearch_log_group_index_slow_logs", - "check_ids": [ - "CKV_AWS_158" - ] - }, - { - "resource": "module.extensions-staging.module.opensearch.aws_cloudwatch_log_group.opensearch_log_group_search_slow_logs", - "check_ids": [ - "CKV_AWS_158" - ] - }, - { - "resource": "module.extensions-staging.module.opensearch.aws_opensearch_domain.this", - "check_ids": [ - "CKV2_AWS_59", - "CKV_AWS_247", - "CKV_AWS_317", - "CKV_AWS_318" - ] - }, - { - "resource": "module.extensions-staging.module.opensearch.aws_security_group.opensearch-security-group", - "check_ids": [ - "CKV2_AWS_5" - ] - }, - { - "resource": "module.extensions-staging.module.opensearch.aws_ssm_parameter.opensearch_endpoint", - "check_ids": [ - "CKV_AWS_337" - ] - } - ] - }, - { - "file": "/postgres/lambda.tf", - "findings": [ - { - "resource": "module.extensions-staging.module.postgres.aws_iam_policy_document.lambda-execution-policy", - "check_ids": [ - "CKV_AWS_108", - "CKV_AWS_111", - "CKV_AWS_356" - ] - }, - { - "resource": "module.extensions-staging.module.postgres.aws_lambda_function.lambda", - "check_ids": [ - "CKV_AWS_115", - "CKV_AWS_116", - "CKV_AWS_272", - "CKV_AWS_50" - ] - } - ] - }, - { - "file": "/postgres/rds.tf", - "findings": [ - { - "resource": "module.extensions-staging.module.postgres.aws_db_instance.default", - "check_ids": [ - "CKV_AWS_161", - "CKV_AWS_293", - "CKV_AWS_354" - ] - }, - { - "resource": "module.extensions-staging.module.postgres.aws_kms_key.default", - "check_ids": [ - "CKV2_AWS_64", - "CKV_AWS_7" - ] - } - ] - }, - { - "file": "/postgres/secrets.tf", - "findings": [ - { - "resource": "module.extensions-staging.module.postgres.aws_ssm_parameter.master-secret-arn", - "check_ids": [ - "CKV_AWS_337" - ] - } - ] - }, - { - "file": "/s3/main.tf", - "findings": [ - { - "resource": "module.artifact_store.aws_kms_key.kms-key", - "check_ids": [ - "CKV2_AWS_64", - "CKV_AWS_7" - ] - }, - { - "resource": "module.artifact_store.aws_s3_bucket.this", - "check_ids": [ - "CKV2_AWS_6", - "CKV2_AWS_61", - "CKV2_AWS_62", - "CKV_AWS_144", - "CKV_AWS_18" - ] - }, - { - "resource": "module.extensions-staging.module.s3.aws_kms_key.kms-key", - "check_ids": [ - "CKV2_AWS_64", - "CKV_AWS_7" - ] - }, - { - "resource": "module.extensions-staging.module.s3.aws_s3_bucket.this", - "check_ids": [ - "CKV2_AWS_6", - "CKV2_AWS_61", - "CKV2_AWS_62", - "CKV_AWS_144", - "CKV_AWS_18" - ] - } - ] - }, - { - "file": "/statefile-backend/main.tf", - "findings": [ - { - "resource": "aws_dynamodb_table.terraform-state", - "check_ids": [ - "CKV2_AWS_16", - "CKV_AWS_119", - "CKV_AWS_28" - ] - }, - { - "resource": "aws_kms_key.terraform-bucket-key", - "check_ids": [ - "CKV2_AWS_64", - "CKV_AWS_7" - ] - }, - { - "resource": "aws_s3_bucket.terraform-state", - "check_ids": [ - "CKV2_AWS_61", - "CKV2_AWS_62", - "CKV_AWS_144", - "CKV_AWS_18" - ] - }, - { - "resource": "aws_s3_bucket_ownership_controls.terraform-state-ownership", - "check_ids": [ - "CKV2_AWS_65" - ] - } - ] - }, - { - "file": "/vpc/main.tf", - "findings": [ - { - "resource": "aws_vpc.vpc", - "check_ids": [ - "CKV2_AWS_11", - "CKV2_AWS_12" - ] - } - ] - } ] } diff --git a/application-load-balancer/main.tf b/application-load-balancer/main.tf index f49f2ea05..3227cfcee 100644 --- a/application-load-balancer/main.tf +++ b/application-load-balancer/main.tf @@ -13,6 +13,7 @@ data "aws_subnets" "public-subnets" { } resource "aws_lb" "this" { + # checkov:skip=CKV2_AWS_28: WAF is outside of terraform-platform-modules name = "${var.application}-${var.environment}" load_balancer_type = "application" subnets = tolist(data.aws_subnets.public-subnets.ids) @@ -25,10 +26,16 @@ resource "aws_lb" "this" { prefix = "${var.application}/${var.environment}" enabled = true } + tags = local.tags + + drop_invalid_header_fields = true + enable_deletion_protection = true } resource "aws_lb_listener" "alb-listener" { + # checkov:skip=CKV_AWS_2:Checkov Looking for Hard Coded HTTPS but we use a variable. + # checkov:skip=CKV_AWS_103:Checkov Looking for Hard Coded TLS1.2 but we use a variable. depends_on = [aws_acm_certificate_validation.cert_validate] for_each = local.protocols @@ -45,11 +52,12 @@ resource "aws_lb_listener" "alb-listener" { } resource "aws_security_group" "alb-security-group" { - # checkov:skip=CKV2_AWS_5:Security group is used by VPC. Ticket to investigate: https://uktrade.atlassian.net/browse/DBTP-1039 - for_each = local.protocols - name = "${var.application}-${var.environment}-alb-${each.key}" - vpc_id = data.aws_vpc.vpc.id - tags = local.tags + # checkov:skip=CKV2_AWS_5: False Positive in Checkov - https://github.com/bridgecrewio/checkov/issues/3010 + for_each = local.protocols + name = "${var.application}-${var.environment}-alb-${each.key}" + description = "Managed by Terraform" + vpc_id = data.aws_vpc.vpc.id + tags = local.tags ingress { description = "Allow from anyone on port ${each.value.port}" from_port = each.value.port @@ -67,6 +75,7 @@ resource "aws_security_group" "alb-security-group" { } resource "aws_lb_target_group" "http-target-group" { + # checkov:skip=CKV_AWS_261:Health Check is Defined by copilot name = "${var.application}-${var.environment}-http" port = 80 protocol = "HTTP" diff --git a/domain/main.tf b/domain/main.tf index 3afbadf14..49ecfe6c5 100644 --- a/domain/main.tf +++ b/domain/main.tf @@ -3,6 +3,8 @@ data "aws_route53_zone" "root-zone" { } resource "aws_route53_zone" "new-zone" { + # checkov:skip=CKV2_AWS_39: Requires wider discussion around log/event ingestion before implementing. To be picked up on conclusion of DBTP-974 + # checkov:skip=CKV2_AWS_38: Requires wider discussion around implementation of DNSSEC - DBTP-1220 for_each = toset(var.zones) name = "${each.key}.${data.aws_route53_zone.root-zone.name}" tags = local.tags diff --git a/elasticache-redis/e2e-tests/setup/main.tf b/elasticache-redis/e2e-tests/setup/main.tf index 18e554c7a..c499d407f 100644 --- a/elasticache-redis/e2e-tests/setup/main.tf +++ b/elasticache-redis/e2e-tests/setup/main.tf @@ -9,6 +9,8 @@ terraform { } resource "aws_vpc" "main" { + # checkov:skip=CKV2_AWS_11: As this VPC is used for E2E testing and torn down. No flow logging required + # checkov:skip=CKV2_AWS_12: As this VPC is used for E2E testing and torn down. Not required cidr_block = "10.0.0.0/16" tags = { Name = "sandbox-elasticache-redis" @@ -24,6 +26,7 @@ resource "aws_subnet" "primary" { } resource "aws_security_group" "vpc-core-sg" { + # checkov:skip=CKV2_AWS_5: False Positive in Checkov - https://github.com/bridgecrewio/checkov/issues/3010 name = "sandbox-elasticache-redis-base-sg" description = "Base security group for VPC" vpc_id = aws_vpc.main.id diff --git a/elasticache-redis/main.tf b/elasticache-redis/main.tf index 5bb7d424e..3f91024f2 100644 --- a/elasticache-redis/main.tf +++ b/elasticache-redis/main.tf @@ -14,9 +14,12 @@ data "aws_subnets" "private-subnets" { } data "aws_caller_identity" "current" {} +data "aws_region" "current" {} resource "aws_elasticache_replication_group" "redis" { + # checkov:skip=CKV_AWS_31:Potential cascading impact on Celery. Requires further analysis - DBTP-1216 + # checkov:skip=CKV_AWS_191:Potential cascading impact on Celery. Requires further analysis - DBTP-1216 replication_group_id = "${var.name}-${var.environment}" description = "${var.name}-${var.environment}-redis-cluster" engine = "redis" @@ -57,12 +60,14 @@ resource "aws_security_group" "redis" { description = "Allow ingress from VPC for Redis" ingress { + description = "Allow from VPC on port 6379" from_port = 6379 to_port = 6379 protocol = "tcp" cidr_blocks = [data.aws_vpc.vpc.cidr_block] } egress { + description = "Allow all traffic" from_port = 0 to_port = 0 protocol = -1 @@ -168,16 +173,52 @@ resource "aws_elasticache_subnet_group" "es-subnet-group" { ) } +resource "aws_kms_key" "redis-log-group-kms-key" { + description = "KMS Key for ${var.name}-${var.environment} Redis Log encryption" + enable_key_rotation = true + tags = local.tags +} + +resource "aws_kms_key_policy" "redis-to-cloudwatch" { + key_id = aws_kms_key.redis-log-group-kms-key.key_id + policy = jsonencode({ + Id = "RedisToCloudWatch" + Statement = [ + { + "Sid" : "Enable IAM User Permissions", + "Effect" : "Allow", + "Principal" : { + "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + "Action" : "kms:*", + "Resource" : "*" + }, + { + "Effect" : "Allow", + "Principal" : { + "Service" : "logs.${data.aws_region.current.name}.amazonaws.com" + }, + "Action" : "kms:*", + "Resource" : "*" + } + ] + Version = "2012-10-17" + }) +} resource "aws_cloudwatch_log_group" "redis-slow-log-group" { + # checkov:skip=CKV_AWS_338:Retains logs for 7 days instead of 1 year name = "/aws/elasticache/${var.name}/${var.environment}/${var.name}Redis/slow" retention_in_days = 7 tags = local.tags + kms_key_id = aws_kms_key.redis-log-group-kms-key.arn } resource "aws_cloudwatch_log_group" "redis-engine-log-group" { + # checkov:skip=CKV_AWS_338:Retains logs for 7 days instead of 1 year name = "/aws/elasticache/${var.name}/${var.environment}/${var.name}Redis/engine" retention_in_days = 7 tags = local.tags + kms_key_id = aws_kms_key.redis-log-group-kms-key.arn } resource "aws_cloudwatch_log_subscription_filter" "redis-subscription-filter-engine" { diff --git a/elasticache-redis/tests/unit.tftest.hcl b/elasticache-redis/tests/unit.tftest.hcl index 94eab12a9..cb1c9c9b7 100644 --- a/elasticache-redis/tests/unit.tftest.hcl +++ b/elasticache-redis/tests/unit.tftest.hcl @@ -278,6 +278,23 @@ run "aws_kms_key_unit_test" { condition = jsonencode(aws_kms_key.ssm_redis_endpoint.tags) == jsonencode(var.expected_tags) error_message = "Should be: ${jsonencode(var.expected_tags)}" } + + assert { + condition = aws_kms_key.redis-log-group-kms-key.description == "KMS Key for test-redis-test-environment Redis Log encryption" + error_message = "Should be: KMS key for test-redis-test-environment Redis Log encryption" + } + + assert { + condition = aws_kms_key.redis-log-group-kms-key.enable_key_rotation == true + error_message = "Should be: true" + } + + assert { + condition = jsonencode(aws_kms_key.redis-log-group-kms-key.tags) == jsonencode(var.expected_tags) + error_message = "Should be: ${jsonencode(var.expected_tags)}" + } + + } run "aws_cloudwatch_log_group_unit_test" { diff --git a/environment-pipelines/codebuild.tf b/environment-pipelines/codebuild.tf index 421426019..22666ffd2 100644 --- a/environment-pipelines/codebuild.tf +++ b/environment-pipelines/codebuild.tf @@ -36,10 +36,34 @@ resource "aws_codebuild_project" "environment_pipeline_build" { tags = local.tags } +resource "aws_kms_key" "codebuild_kms_key" { + description = "KMS Key for ${var.application}-${var.pipeline_name} CodeBuild encryption" + enable_key_rotation = true + + policy = jsonencode({ + Id = "key-default-1" + Statement = [ + { + "Sid" : "Enable IAM User Permissions", + "Effect" : "Allow", + "Principal" : { + "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + "Action" : "kms:*", + "Resource" : "*" + } + ] + Version = "2012-10-17" + }) + + tags = local.tags +} + resource "aws_cloudwatch_log_group" "environment_pipeline_codebuild" { - name = "codebuild/${var.application}-${var.pipeline_name}-environment-terraform/log-group" # checkov:skip=CKV_AWS_338:Retains logs for 3 months instead of 1 year + name = "codebuild/${var.application}-${var.pipeline_name}-environment-terraform/log-group" retention_in_days = 90 + kms_key_id = aws_kms_key.codebuild_kms_key.arn } resource "aws_cloudwatch_log_stream" "environment_pipeline_codebuild" { diff --git a/environment-pipelines/iam.tf b/environment-pipelines/iam.tf index 804de28ee..38d966155 100644 --- a/environment-pipelines/iam.tf +++ b/environment-pipelines/iam.tf @@ -15,6 +15,8 @@ data "aws_iam_policy_document" "assume_codepipeline_role" { } data "aws_iam_policy_document" "access_artifact_store" { + # checkov:skip=CKV_AWS_111:Permissions required to change ACLs on uploaded artifacts + # checkov:skip=CKV_AWS_356:Permissions required to upload artifacts statement { effect = "Allow" diff --git a/environment-pipelines/tests/unit.tftest.hcl b/environment-pipelines/tests/unit.tftest.hcl index 6aabc9a5c..d4972a24c 100644 --- a/environment-pipelines/tests/unit.tftest.hcl +++ b/environment-pipelines/tests/unit.tftest.hcl @@ -1258,6 +1258,24 @@ run "test_stages" { } } +run "aws_kms_key_unit_test" { + command = plan + + assert { + condition = aws_kms_key.codebuild_kms_key.description == "KMS Key for my-app-my-pipeline CodeBuild encryption" + error_message = "Should be: KMS Key for my-app-my-pipeline CodeBuild encryption" + } + + assert { + condition = aws_kms_key.codebuild_kms_key.enable_key_rotation == true + error_message = "Should be: true" + } + + assert { + condition = jsonencode(aws_kms_key.codebuild_kms_key.tags) == jsonencode(var.expected_tags) + error_message = "Should be: ${jsonencode(var.expected_tags)}" + } +} diff --git a/extensions/main.tf b/extensions/main.tf index 53e652bac..90063e879 100644 --- a/extensions/main.tf +++ b/extensions/main.tf @@ -90,6 +90,8 @@ module "monitoring" { } resource "aws_ssm_parameter" "addons" { + # checkov:skip=CKV_AWS_337: Used by copilot needs further analysis to ensure doesn't create similar issue to DBTP-1128 - raised as DBTP-1217 + # checkov:skip=CKV2_AWS_34: Used by copilot needs further analysis to ensure doesn't create similar issue to DBTP-1128 - raised as DBTP-1217 name = "/copilot/applications/${var.args.application}/environments/${var.environment}/addons" tier = "Intelligent-Tiering" type = "String" diff --git a/opensearch/e2e-tests/setup/main.tf b/opensearch/e2e-tests/setup/main.tf index 73da4b2f9..c860f28e6 100644 --- a/opensearch/e2e-tests/setup/main.tf +++ b/opensearch/e2e-tests/setup/main.tf @@ -9,6 +9,8 @@ terraform { } resource "aws_vpc" "main" { + # checkov:skip=CKV2_AWS_11: As this VPC is used for E2E testing and torn down. No flow logging required + # checkov:skip=CKV2_AWS_12: As this VPC is used for E2E testing and torn down. Not required cidr_block = "10.0.0.0/16" tags = { Name = "sandbox-opensearch" diff --git a/opensearch/main.tf b/opensearch/main.tf index 95ba3cccc..32e645fbd 100644 --- a/opensearch/main.tf +++ b/opensearch/main.tf @@ -1,27 +1,65 @@ data "aws_caller_identity" "current" {} data "aws_region" "current" {} +resource "aws_kms_key" "cloudwatch_log_group_kms_key" { + description = "KMS Key for ${var.name}-${var.environment} CloudWatch Log encryption" + enable_key_rotation = true + tags = local.tags +} + +resource "aws_kms_key_policy" "opensearch_to_cloudwatch" { + key_id = aws_kms_key.cloudwatch_log_group_kms_key.key_id + policy = jsonencode({ + Id = "OpenSearchToCloudWatch" + Statement = [ + { + "Sid" : "Enable IAM User Permissions", + "Effect" : "Allow", + "Principal" : { + "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + "Action" : "kms:*", + "Resource" : "*" + }, + { + "Effect" : "Allow", + "Principal" : { + "Service" : "logs.${data.aws_region.current.name}.amazonaws.com" + }, + "Action" : "kms:*", + "Resource" : "*" + } + ] + Version = "2012-10-17" + }) +} + resource "aws_cloudwatch_log_group" "opensearch_log_group_index_slow_logs" { name = "/aws/opensearch/${local.domain_name}/index-slow" retention_in_days = coalesce(var.config.index_slow_log_retention_in_days, 7) + kms_key_id = aws_kms_key.cloudwatch_log_group_kms_key.arn } resource "aws_cloudwatch_log_group" "opensearch_log_group_search_slow_logs" { name = "/aws/opensearch/${local.domain_name}/search-slow" retention_in_days = coalesce(var.config.search_slow_log_retention_in_days, 7) + kms_key_id = aws_kms_key.cloudwatch_log_group_kms_key.arn } resource "aws_cloudwatch_log_group" "opensearch_log_group_es_application_logs" { name = "/aws/opensearch/${local.domain_name}/es-application" retention_in_days = coalesce(var.config.es_app_log_retention_in_days, 7) + kms_key_id = aws_kms_key.cloudwatch_log_group_kms_key.arn } resource "aws_cloudwatch_log_group" "opensearch_log_group_audit_logs" { name = "/aws/opensearch/${local.domain_name}/audit" retention_in_days = coalesce(var.config.audit_log_retention_in_days, 7) + kms_key_id = aws_kms_key.cloudwatch_log_group_kms_key.arn } resource "aws_security_group" "opensearch-security-group" { + # checkov:skip=CKV2_AWS_5: False Positive in Checkov - https://github.com/bridgecrewio/checkov/issues/3010 name = local.domain_name vpc_id = data.aws_vpc.vpc.id description = "Allow inbound HTTP traffic" @@ -61,8 +99,9 @@ resource "random_password" "password" { min_lower = 1 min_numeric = 1 } - resource "aws_opensearch_domain" "this" { + # checkov:skip=CKV_AWS_247: Enabling CMK Forces Cluster Recreation. To be implemented as a separate breaking change + # checkov:skip=CKV2_AWS_59: This is a configurable option not picked up by Checkov as it's variablised domain_name = local.domain_name engine_version = "OpenSearch_${var.config.engine}" @@ -74,7 +113,7 @@ resource "aws_opensearch_domain" "this" { ] cluster_config { - dedicated_master_count = 1 + dedicated_master_count = 3 dedicated_master_type = var.config.master ? var.config.instance : null dedicated_master_enabled = var.config.master instance_type = var.config.instance @@ -137,6 +176,7 @@ resource "aws_opensearch_domain" "this" { log_publishing_options { cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_log_group_audit_logs.arn log_type = "AUDIT_LOGS" + enabled = true } node_to_node_encryption { diff --git a/opensearch/tests/unit.tftest.hcl b/opensearch/tests/unit.tftest.hcl index e3efd136b..cf9f22cbb 100644 --- a/opensearch/tests/unit.tftest.hcl +++ b/opensearch/tests/unit.tftest.hcl @@ -371,7 +371,8 @@ run "test_create_cloudwatch_subscription_filters" { } } -run "test_create_conduit_iam_role" { +run "aws_kms_key_unit_test" { + command = plan variables { @@ -389,6 +390,16 @@ run "test_create_conduit_iam_role" { } } + assert { + condition = aws_kms_key.cloudwatch_log_group_kms_key.description == "KMS Key for my_name-my_env CloudWatch Log encryption" + error_message = "Should be: KMS Key for my_name-my_env CloudWatch Log encryption" + } + + assert { + condition = aws_kms_key.cloudwatch_log_group_kms_key.enable_key_rotation == true + error_message = "Should be: true" + } + assert { condition = aws_iam_role.conduit_ecs_task_role.name == "my_name-my_app-my_env-conduitEcsTask" error_message = "Should be: my_name-my_app-my_env-conduitEcsTask" diff --git a/postgres/lambda.tf b/postgres/lambda.tf index 7cd45c4ee..227d64a20 100644 --- a/postgres/lambda.tf +++ b/postgres/lambda.tf @@ -10,6 +10,9 @@ data "aws_iam_policy_document" "lambda-assume-role-policy" { } data "aws_iam_policy_document" "lambda-execution-policy" { + # checkov:skip=CKV_AWS_108:Permissions required to perform Lambda role + # checkov:skip=CKV_AWS_111:Permissions required to perform Lambda role + # checkov:skip=CKV_AWS_356:Permissions required to perform Lambda role statement { effect = "Allow" actions = [ @@ -64,13 +67,16 @@ data "archive_file" "lambda" { } resource "aws_lambda_function" "lambda" { - filename = "${path.module}/manage_users.zip" - function_name = "${local.name}-rds-create-user" - role = aws_iam_role.lambda-execution-role.arn - handler = "manage_users.handler" - runtime = "python3.11" - memory_size = 128 - timeout = 10 + # checkov:skip=CKV_AWS_272:Code signing is not currently in use + # checkov:skip=CKV_AWS_116:Dead letter queue not required due to the nature of this function + filename = "${path.module}/manage_users.zip" + function_name = "${local.name}-rds-create-user" + role = aws_iam_role.lambda-execution-role.arn + handler = "manage_users.handler" + runtime = "python3.11" + memory_size = 128 + timeout = 10 + reserved_concurrent_executions = -1 layers = ["arn:aws:lambda:eu-west-2:763451185160:layer:python-postgres:1"] @@ -80,6 +86,10 @@ resource "aws_lambda_function" "lambda" { security_group_ids = [aws_security_group.default.id, data.aws_security_group.rds-endpoint.id] subnet_ids = data.aws_subnets.private-subnets.ids } + + tracing_config { + mode = "Active" + } } resource "aws_lambda_invocation" "create-application-user" { diff --git a/postgres/rds.tf b/postgres/rds.tf index 9f0a19964..c8c82dc16 100644 --- a/postgres/rds.tf +++ b/postgres/rds.tf @@ -32,11 +32,29 @@ resource "aws_db_subnet_group" "default" { } resource "aws_kms_key" "default" { - description = "${local.name} KMS key" + description = "${local.name} KMS key" + enable_key_rotation = true + + policy = jsonencode({ + Id = "key-default-1" + Statement = [ + { + "Sid" : "Enable IAM User Permissions", + "Effect" : "Allow", + "Principal" : { + "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + "Action" : "kms:*", + "Resource" : "*" + } + ] + Version = "2012-10-17" + }) } resource "aws_db_instance" "default" { - + # checkov:skip=CKV_AWS_354:Performance Insights key cannot be changed once the database has been created. (https://github.com/hashicorp/terraform-provider-aws/issues/9399) + # checkov:skip=CKV_AWS_161:Significant upstream impact to other components identifier = local.name db_name = "main" diff --git a/postgres/secrets.tf b/postgres/secrets.tf index 3b7e8e6dd..7d54accd1 100644 --- a/postgres/secrets.tf +++ b/postgres/secrets.tf @@ -1,4 +1,5 @@ resource "aws_ssm_parameter" "master-secret-arn" { + # checkov:skip=CKV_AWS_337: Need to determine downstream impact before moving to CMK - raised as DBTP-1217 name = "/copilot/${var.application}/${var.environment}/secrets/${local.rds_master_secret_name}" type = "SecureString" value = aws_db_instance.default.master_user_secret[0].secret_arn diff --git a/postgres/tests/unit.tftest.hcl b/postgres/tests/unit.tftest.hcl index f44f07ac3..098d214d4 100644 --- a/postgres/tests/unit.tftest.hcl +++ b/postgres/tests/unit.tftest.hcl @@ -135,8 +135,8 @@ run "aws_kms_key_unit_test" { } assert { - condition = aws_kms_key.default.enable_key_rotation == false - error_message = "Should be: false" + condition = aws_kms_key.default.enable_key_rotation == true + error_message = "Should be: true" } assert { @@ -523,6 +523,11 @@ run "aws_lambda_invocation_unit_test" { condition = aws_lambda_invocation.create-readonly-user.terraform_key == "tf" error_message = "Should be: tf" } + + assert { + condition = aws_lambda_function.lambda.reserved_concurrent_executions == -1 + error_message = "Should be: -1" + } } run "aws_ssm_parameter_master_secret_arn_unit_test" { diff --git a/s3/main.tf b/s3/main.tf index 7b878f79e..9b42ddba3 100644 --- a/s3/main.tf +++ b/s3/main.tf @@ -1,4 +1,8 @@ +data "aws_caller_identity" "current" {} resource "aws_s3_bucket" "this" { + # checkov:skip=CKV_AWS_144: Cross Region Replication not Required + # checkov:skip=CKV2_AWS_62: Requires wider discussion around log/event ingestion before implementing. To be picked up on conclusion of DBTP-974 + # checkov:skip=CKV_AWS_18: Requires wider discussion around log/event ingestion before implementing. To be picked up on conclusion of DBTP-974 bucket = var.config.bucket_name tags = local.tags @@ -71,8 +75,25 @@ resource "aws_s3_bucket_lifecycle_configuration" "lifecycle-configuration" { } resource "aws_kms_key" "kms-key" { + # checkov:skip=CKV_AWS_7:We are not currently rotating the keys description = "KMS Key for S3 encryption" tags = local.tags + + policy = jsonencode({ + Id = "key-default-1" + Statement = [ + { + "Sid" : "Enable IAM User Permissions", + "Effect" : "Allow", + "Principal" : { + "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + "Action" : "kms:*", + "Resource" : "*" + } + ] + Version = "2012-10-17" + }) } resource "aws_kms_alias" "s3-bucket" { @@ -119,3 +140,11 @@ resource "aws_s3_object" "object" { kms_key_id = aws_kms_key.kms-key.arn server_side_encryption = "aws:kms" } + +resource "aws_s3_bucket_public_access_block" "public_access_block" { + bucket = aws_s3_bucket.this.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} diff --git a/statefile-backend/main.tf b/statefile-backend/main.tf index 908ff4bb6..f2f1ab341 100644 --- a/statefile-backend/main.tf +++ b/statefile-backend/main.tf @@ -1,5 +1,11 @@ +data "aws_caller_identity" "current" {} resource "aws_s3_bucket" "terraform-state" { + # checkov:skip=CKV_AWS_144: Cross Region Replication not Required + # checkov:skip=CKV2_AWS_62: Requires wider discussion around log/event ingestion before implementing. To be picked up on conclusion of DBTP-974 + # checkov:skip=CKV2_AWS_61: This bucket is only used for the TF state, so no requirement for lifecycle configuration + # checkov:skip=CKV_AWS_18: Requires wider discussion around log/event ingestion before implementing. To be picked up on conclusion of DBTP-974 bucket = "terraform-platform-state-${var.aws_account_name}" + tags = merge( local.tags, { @@ -22,6 +28,7 @@ resource "aws_s3_bucket_versioning" "terraform-state-versioning" { } resource "aws_s3_bucket_ownership_controls" "terraform-state-ownership" { + # checkov:skip=CKV2_AWS_65: Finding is negated by aws_s3_bucket_acl.terraform-state-acl bucket = aws_s3_bucket.terraform-state.id rule { object_ownership = "BucketOwnerPreferred" @@ -38,7 +45,25 @@ resource "aws_s3_bucket_public_access_block" "block" { } resource "aws_kms_key" "terraform-bucket-key" { + # checkov:skip=CKV_AWS_7:We are not currently rotating the keys description = "This key is used to encrypt bucket objects" + + policy = jsonencode({ + Id = "key-default-1" + Statement = [ + { + "Sid" : "Enable IAM User Permissions", + "Effect" : "Allow", + "Principal" : { + "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + "Action" : "kms:*", + "Resource" : "*" + } + ] + Version = "2012-10-17" + }) + tags = merge( local.tags, { @@ -65,6 +90,9 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "terraform-state-s } resource "aws_dynamodb_table" "terraform-state" { + # checkov:skip=CKV_AWS_28: No requirement for point in time backups of the Terraform state lock database + # checkov:skip=CKV_AWS_119: No requirement for CMK for the Terraform state lock database + # checkov:skip=CKV2_AWS_16: No requirement for scaling for the Terraform state lock database name = "terraform-platform-lockdb-${var.aws_account_name}" read_capacity = 20 write_capacity = 20 diff --git a/vpc/main.tf b/vpc/main.tf index d8740178c..0117a3656 100644 --- a/vpc/main.tf +++ b/vpc/main.tf @@ -1,5 +1,7 @@ # VPC resource "aws_vpc" "vpc" { + # checkov:skip=CKV2_AWS_11: Requires wider discussion around log/event ingestion before implementing. To be picked up on conclusion of DBTP-974 + # checkov:skip=CKV2_AWS_12: Functionality provided via default_acl rather than default_security_group cidr_block = "${var.arg_config.cidr}${local.vpc_cidr_mask}" enable_dns_hostnames = true tags = merge(