diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/query.rego b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/query.rego index 020029b2dab..1c38672b753 100644 --- a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/query.rego +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/query.rego @@ -1,25 +1,70 @@ package Cx +import data.generic.common as common_lib import data.generic.terraform as tf_lib CxPolicy[result] { - resource := input.document[i].resource.aws_api_gateway_stage[name] - not haveLogs(resource.stage_name) + doc := input.document[i] + resource := doc.resource.aws_api_gateway_stage[name] + + results := get_results(resource,doc,name) + results != "" result := { "documentId": input.document[i].id, "resourceType": "aws_api_gateway_stage", "resourceName": tf_lib.get_resource_name(resource, name), - "searchKey": sprintf("aws_api_gateway_stage[%s]", [name]), + "searchKey": results.searchKey, "issueType": "MissingAttribute", - "keyExpectedValue": "'aws_cloudwatch_log_group' should be defined and use the correct naming convention", - "keyActualValue": "'aws_cloudwatch_log_group' for the stage is not undefined or not using the correct naming convention", + "keyExpectedValue": results.keyExpectedValue, + "keyActualValue": results.keyActualValue, + "searchLine": results.searchLine, } } -haveLogs(stageName) { - log := input.document[i].resource.aws_cloudwatch_log_group[_] - stageName_escaped := replace(replace(stageName, "$", "\\$"), ".", "\\.") +get_results(resource,doc,name) = results { + not resource.access_log_settings.destination_arn + results := does_not_have_valid_stage_name(resource,doc,name) +} else = results { + r2 := does_not_have_valid_stage_name(resource,doc,name) + r2 != "" + results := does_not_have_valid_destination_arn(resource,doc,name) +} else = "" + +does_not_have_valid_destination_arn(resource,doc,name) = results { + not haveLogs_destination_arn(resource,doc) + results := { + "searchKey": sprintf("aws_api_gateway_stage[%s].access_log_settings.destination_arn", [name]), + "keyExpectedValue": sprintf("'aws_api_gateway_stage[%s].access_log_settings.destination_arn' should reference a valid 'aws_cloudwatch_log_group' arn",[name]), + "keyActualValue": sprintf("'aws_api_gateway_stage[%s].access_log_settings.destination_arn' does not reference a valid 'aws_cloudwatch_log_group' arn",[name]), + "searchLine": common_lib.build_search_line(["resource","aws_api_gateway_stage", name, "access_log_settings", "destination_arn"],[]) + } +} else = "" + +does_not_have_valid_stage_name(resource,doc,name) = results { + not haveLogs_stageName(resource,doc) + results := { + "searchKey": sprintf("aws_api_gateway_stage[%s]", [name]), + "keyExpectedValue": sprintf("'aws_cloudwatch_log_group' for 'aws_api_gateway_stage[%s]' should be defined and use the correct naming convention",[name]), + "keyActualValue": sprintf("'aws_cloudwatch_log_group' for 'aws_api_gateway_stage[%s]' is undefined or is not using the correct naming convention",[name]), + "searchLine": common_lib.build_search_line(["resource","aws_api_gateway_stage", name],[]) + } +} else = "" + +haveLogs_stageName(resource,doc) { + log := doc.resource.aws_cloudwatch_log_group[_] + stageName_escaped := replace(replace(resource.stage_name, "$", "\\$"), ".", "\\.") regexPattern := sprintf("API-Gateway-Execution-Logs_\\${aws_api_gateway_rest_api\\.\\w+\\.id}/%s$", [stageName_escaped]) regex.match(regexPattern, log.name) -} +} + +haveLogs_destination_arn(resource,doc) { + common_lib.valid_key(resource.access_log_settings,"destination_arn") + + destination_arn := resource.access_log_settings.destination_arn + + log_group := doc.resource.aws_cloudwatch_log_group[name] + regexPattern := sprintf("aws_cloudwatch_log_group.%s.arn", [name]) + regex.match(regexPattern, destination_arn) + common_lib.valid_key(log_group,"name") +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative1.tf similarity index 100% rename from assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative.tf rename to assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative1.tf diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative3.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative3.tf new file mode 100644 index 00000000000..633c77a4aea --- /dev/null +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative3.tf @@ -0,0 +1,18 @@ +resource "aws_api_gateway_rest_api" "apiLambda" { + # ... other configuration ... +} + +resource "aws_api_gateway_stage" "api_stage_environment" { + depends_on = [aws_api_gateway_deployment.api_http_method_deployment] + stage_name = "qa" + access_log_settings { + destination_arn = aws_cloudwatch_log_group.sample_name.arn + # ... + } +} + +resource "aws_cloudwatch_log_group" "sample_name" { + name = "/aws/api-gateway/apigw-name-app" + retention_in_days = 14 + # ... potentially other configuration ... +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative4.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative4.tf new file mode 100644 index 00000000000..bfa1c40d7bc --- /dev/null +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative4.tf @@ -0,0 +1,29 @@ +variable "stage_name" { + default = "example" + type = string +} +variable "stage_names" { + default = "examples" + type = string +} + +resource "aws_api_gateway_rest_api" "example" { + # ... other configuration ... +} + +resource "aws_api_gateway_stage" "example" { + depends_on = [aws_cloudwatch_log_group.example] + + stage_name = var.stage_name + access_log_settings { + destination_arn = null + # ... + } + # ... other configuration ... +} + +resource "aws_cloudwatch_log_group" "example" { + name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.example.id}/${var.stage_name}" + retention_in_days = 7 + # ... potentially other configuration ... +} diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative5.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative5.tf new file mode 100644 index 00000000000..e8ceb346838 --- /dev/null +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/negative5.tf @@ -0,0 +1,30 @@ +module "env" { + source = "./env" +} + +resource "aws_api_gateway_rest_api" "example" { + # ... other configuration ... +} + +resource "aws_api_gateway_stage" "example" { + depends_on = [aws_cloudwatch_log_group.example] + + stage_name = module.env.vars.stage_name + access_log_settings { + destination_arn = aws_cloudwatch_log_group.sample_name.arn + # ... + } + # ... other configuration ... +} + +resource "aws_cloudwatch_log_group" "example" { + name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.example.id}/${module.env.vars.stage_name}" + retention_in_days = 7 + # ... potentially other configuration ... +} + +resource "aws_cloudwatch_log_group" "sample_name" { + name = "/aws/api-gateway/apigw-name-app" + retention_in_days = 14 + # ... potentially other configuration ... +} diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive1.tf similarity index 92% rename from assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive.tf rename to assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive1.tf index 596991032f3..fe586919b5a 100644 --- a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive.tf +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive1.tf @@ -11,7 +11,7 @@ resource "aws_api_gateway_rest_api" "example" { # ... other configuration ... } -resource "aws_api_gateway_stage" "example" { +resource "aws_api_gateway_stage" "positive1" { depends_on = [aws_cloudwatch_log_group.example] stage_name = var.stage_name diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive2.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive2.tf new file mode 100644 index 00000000000..b7d779caa21 --- /dev/null +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive2.tf @@ -0,0 +1,18 @@ +resource "aws_api_gateway_rest_api" "apiLambda" { + # ... other configuration ... +} + +resource "aws_api_gateway_stage" "positive2" { + depends_on = [aws_api_gateway_deployment.api_http_method_deployment] + stage_name = "qa" + access_log_settings { + destination_arn = aws_cloudwatch_log_group.wrong_sample_name.arn + # ... + } +} + +resource "aws_cloudwatch_log_group" "sample_name" { + name = "/aws/api-gateway/apigw-name-app" + retention_in_days = 14 + # ... potentially other configuration ... +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive3.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive3.tf new file mode 100644 index 00000000000..835fad8493e --- /dev/null +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive3.tf @@ -0,0 +1,18 @@ +resource "aws_api_gateway_rest_api" "apiLambda" { + # ... other configuration ... +} + +resource "aws_api_gateway_stage" "positive3" { + depends_on = [aws_api_gateway_deployment.api_http_method_deployment] + stage_name = "qa" + access_log_settings { + destination_arn = null + # ... + } +} + +resource "aws_cloudwatch_log_group" "sample_name" { + name = "/aws/api-gateway/apigw-name-app" + retention_in_days = 14 + # ... potentially other configuration ... +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive4.tf b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive4.tf new file mode 100644 index 00000000000..290ee315d9a --- /dev/null +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive4.tf @@ -0,0 +1,14 @@ +resource "aws_api_gateway_rest_api" "apiLambda" { + # ... other configuration ... +} + +resource "aws_api_gateway_stage" "positive4" { + depends_on = [aws_api_gateway_deployment.api_http_method_deployment] + stage_name = "qa" +} + +resource "aws_cloudwatch_log_group" "sample_name" { + name = "/aws/api-gateway/apigw-name-app" + retention_in_days = 14 + # ... potentially other configuration ... +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive_expected_result.json b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive_expected_result.json index 4eb5e15356b..4b6ad1bccab 100644 --- a/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive_expected_result.json +++ b/assets/queries/terraform/aws/api_gateway_with_cloudwatch_logging_disabled/test/positive_expected_result.json @@ -2,6 +2,25 @@ { "queryName": "API Gateway With CloudWatch Logging Disabled", "severity": "MEDIUM", - "line": 14 + "line": 14, + "fileName": "positive1.tf" + }, + { + "queryName": "API Gateway With CloudWatch Logging Disabled", + "severity": "MEDIUM", + "line": 9, + "fileName": "positive2.tf" + }, + { + "queryName": "API Gateway With CloudWatch Logging Disabled", + "severity": "MEDIUM", + "line": 9, + "fileName": "positive3.tf" + }, + { + "queryName": "API Gateway With CloudWatch Logging Disabled", + "severity": "MEDIUM", + "line": 5, + "fileName": "positive4.tf" } ]