From 66aafd9764b86061590ae60de5cddfca0c79b063 Mon Sep 17 00:00:00 2001 From: Andre Pereira <219305055+cx-andre-pereira@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:34:09 +0000 Subject: [PATCH 1/2] initial implementation --- .../azure/query_template/metadata.json | 14 +++++++ .../terraform/azure/query_template/query.rego | 37 +++++++++++++++++++ .../azure/query_template/test/negative.tf | 27 ++++++++++++++ .../azure/query_template/test/positive.tf | 21 +++++++++++ .../test/positive_expected_result.json | 12 ++++++ .../terraform_azure.yaml | 4 ++ 6 files changed, 115 insertions(+) create mode 100644 assets/queries/terraform/azure/query_template/metadata.json create mode 100644 assets/queries/terraform/azure/query_template/query.rego create mode 100644 assets/queries/terraform/azure/query_template/test/negative.tf create mode 100644 assets/queries/terraform/azure/query_template/test/positive.tf create mode 100644 assets/queries/terraform/azure/query_template/test/positive_expected_result.json diff --git a/assets/queries/terraform/azure/query_template/metadata.json b/assets/queries/terraform/azure/query_template/metadata.json new file mode 100644 index 00000000000..352ab564719 --- /dev/null +++ b/assets/queries/terraform/azure/query_template/metadata.json @@ -0,0 +1,14 @@ +{ + "id": "12ecec8a-7961-48db-b644-86be8845d8fd", + "queryName": "Beta - Containers Without Soft Delete", + "severity": "HIGH", + "category": "Backup", + "descriptionText": "All 'azurerm_storage_account' resources should define a 'container_delete_retention_policy' block for their 'blob_properties' to allow data recovery", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account#container_delete_retention_policy-1", + "platform": "Terraform", + "descriptionID": "12ecec8a", + "cloudProvider": "azure", + "cwe": "754", + "riskScore": "6.0", + "experimental": "true" +} diff --git a/assets/queries/terraform/azure/query_template/query.rego b/assets/queries/terraform/azure/query_template/query.rego new file mode 100644 index 00000000000..a651112529f --- /dev/null +++ b/assets/queries/terraform/azure/query_template/query.rego @@ -0,0 +1,37 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.azurerm_storage_account[name] + + results := get_results(resource, name) + + result := { + "documentId": input.document[i].id, + "resourceType": "azurerm_storage_account", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": results.searchKey, + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'azurerm_storage_account[%s].blob_properties.container_delete_retention_policy' should be defined and not null", [name]), + "keyActualValue": results.keyActualValue, + "searchLine": results.searchLine + } +} + +get_results(resource, name) = results { + not common_lib.valid_key(resource, "blob_properties") + results := { + "searchKey" : sprintf("azurerm_storage_account[%s]", [name]), + "keyActualValue" : sprintf("'azurerm_storage_account[%s].blob_properties' is undefined or null", [name]), + "searchLine" : common_lib.build_search_line(["resource", "azurerm_storage_account", name], []) + } +} else = results { + not common_lib.valid_key(resource.blob_properties, "container_delete_retention_policy") + results := { + "searchKey" : sprintf("azurerm_storage_account[%s].blob_properties", [name]), + "keyActualValue" : sprintf("'azurerm_storage_account[%s].blob_properties.container_delete_retention_policy' is undefined or null", [name]), + "searchLine" : common_lib.build_search_line(["resource", "azurerm_storage_account", name, "blob_properties"], []) + } +} diff --git a/assets/queries/terraform/azure/query_template/test/negative.tf b/assets/queries/terraform/azure/query_template/test/negative.tf new file mode 100644 index 00000000000..0e7933644ea --- /dev/null +++ b/assets/queries/terraform/azure/query_template/test/negative.tf @@ -0,0 +1,27 @@ +resource "azurerm_storage_account" "negative1" { + name = "negative1" + resource_group_name = "testRG" + location = "northeurope" + account_tier = "Premium" + account_replication_type = "LRS" + account_kind = "FileStorage" + + blob_properties { + container_delete_retention_policy { + days = 5 + } + } +} + +resource "azurerm_storage_account" "negative2" { + name = "negative2" + resource_group_name = "testRG" + location = "northeurope" + account_tier = "Premium" + account_replication_type = "LRS" + account_kind = "FileStorage" + + blob_properties { + container_delete_retention_policy {} # defaults to 7 days + } +} diff --git a/assets/queries/terraform/azure/query_template/test/positive.tf b/assets/queries/terraform/azure/query_template/test/positive.tf new file mode 100644 index 00000000000..a7b42b57091 --- /dev/null +++ b/assets/queries/terraform/azure/query_template/test/positive.tf @@ -0,0 +1,21 @@ +resource "azurerm_storage_account" "positive1" { + name = "positive1" + resource_group_name = azurerm_resource_group.positive1.name + location = azurerm_resource_group.positive1.location + account_tier = "Standard" + account_replication_type = "GRS" + + # missing "blob_properties" +} + +resource "azurerm_storage_account" "positive2" { + name = "positive2" + resource_group_name = azurerm_resource_group.positive2.name + location = azurerm_resource_group.positive2.location + account_tier = "Standard" + account_replication_type = "GRS" + + blob_properties { + # missing "container_delete_retention_policy" + } +} diff --git a/assets/queries/terraform/azure/query_template/test/positive_expected_result.json b/assets/queries/terraform/azure/query_template/test/positive_expected_result.json new file mode 100644 index 00000000000..9b8ad749d89 --- /dev/null +++ b/assets/queries/terraform/azure/query_template/test/positive_expected_result.json @@ -0,0 +1,12 @@ +[ + { + "queryName": "Beta - Containers Without Soft Delete", + "severity": "HIGH", + "line": 1 + }, + { + "queryName": "Beta - Containers Without Soft Delete", + "severity": "HIGH", + "line": 18 + } +] diff --git a/assets/similarityID_transition/terraform_azure.yaml b/assets/similarityID_transition/terraform_azure.yaml index 407c810f4d1..d224cf319ba 100644 --- a/assets/similarityID_transition/terraform_azure.yaml +++ b/assets/similarityID_transition/terraform_azure.yaml @@ -3,3 +3,7 @@ similarityIDChangeList: queryName: Sensitive Port Is Exposed To Wide Private Network observations: "" change: 5 + - queryId: 12ecec8a-7961-48db-b644-86be8845d8fd + queryName: Beta - Containers Without Soft Delete + observations: "" + change: 2 From daf074b1f71c1d41af4f3c7aa27adc3a8e15c90c Mon Sep 17 00:00:00 2001 From: Andre Pereira <219305055+cx-andre-pereira@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:43:53 +0000 Subject: [PATCH 2/2] query folder name fix --- .../metadata.json | 0 .../{query_template => containers_without_soft_delete}/query.rego | 0 .../test/negative.tf | 0 .../test/positive.tf | 0 .../test/positive_expected_result.json | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename assets/queries/terraform/azure/{query_template => containers_without_soft_delete}/metadata.json (100%) rename assets/queries/terraform/azure/{query_template => containers_without_soft_delete}/query.rego (100%) rename assets/queries/terraform/azure/{query_template => containers_without_soft_delete}/test/negative.tf (100%) rename assets/queries/terraform/azure/{query_template => containers_without_soft_delete}/test/positive.tf (100%) rename assets/queries/terraform/azure/{query_template => containers_without_soft_delete}/test/positive_expected_result.json (100%) diff --git a/assets/queries/terraform/azure/query_template/metadata.json b/assets/queries/terraform/azure/containers_without_soft_delete/metadata.json similarity index 100% rename from assets/queries/terraform/azure/query_template/metadata.json rename to assets/queries/terraform/azure/containers_without_soft_delete/metadata.json diff --git a/assets/queries/terraform/azure/query_template/query.rego b/assets/queries/terraform/azure/containers_without_soft_delete/query.rego similarity index 100% rename from assets/queries/terraform/azure/query_template/query.rego rename to assets/queries/terraform/azure/containers_without_soft_delete/query.rego diff --git a/assets/queries/terraform/azure/query_template/test/negative.tf b/assets/queries/terraform/azure/containers_without_soft_delete/test/negative.tf similarity index 100% rename from assets/queries/terraform/azure/query_template/test/negative.tf rename to assets/queries/terraform/azure/containers_without_soft_delete/test/negative.tf diff --git a/assets/queries/terraform/azure/query_template/test/positive.tf b/assets/queries/terraform/azure/containers_without_soft_delete/test/positive.tf similarity index 100% rename from assets/queries/terraform/azure/query_template/test/positive.tf rename to assets/queries/terraform/azure/containers_without_soft_delete/test/positive.tf diff --git a/assets/queries/terraform/azure/query_template/test/positive_expected_result.json b/assets/queries/terraform/azure/containers_without_soft_delete/test/positive_expected_result.json similarity index 100% rename from assets/queries/terraform/azure/query_template/test/positive_expected_result.json rename to assets/queries/terraform/azure/containers_without_soft_delete/test/positive_expected_result.json