diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/metadata.json b/assets/queries/terraform/azure/storage_account_without_cmk/metadata.json new file mode 100644 index 00000000000..c6c8f4f2013 --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/metadata.json @@ -0,0 +1,14 @@ +{ + "id": "9bf1568d-4cd2-4581-81ef-d2efabee1178", + "queryName": "Beta - Storage Account Without CMK", + "severity": "MEDIUM", + "category": "Encryption", + "descriptionText": "The 'azurerm_storage_account' resource should enable CMK encryption", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account", + "platform": "Terraform", + "descriptionID": "9bf1568d", + "cloudProvider": "azure", + "cwe": "522", + "riskScore": "3.0", + "experimental": "true" +} diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/query.rego b/assets/queries/terraform/azure/storage_account_without_cmk/query.rego new file mode 100644 index 00000000000..55ded9847c6 --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/query.rego @@ -0,0 +1,32 @@ +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] + id_reference := sprintf("${azurerm_storage_account.%s.id}", [name]) + + not common_lib.valid_key(resource, "customer_managed_key") # assumes valid configuration if cmk is defined + + diagnostic_settings := {x | x := input.document[_].resource.azurerm_monitor_diagnostic_setting[_]} # must be associated with diagnostic_setting + diagnostic_settings[_].storage_account_id == id_reference + + custom_managed_keys := {x | x := input.document[_].resource.azurerm_storage_account_customer_managed_key[_]} + not is_associated_with_cmk_resource(custom_managed_keys, id_reference) + + result := { + "documentId": input.document[i].id, + "resourceType": "azurerm_storage_account", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey" : sprintf("azurerm_storage_account[%s]", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue" : sprintf("'azurerm_storage_account[%s].customer_managed_key' should be set", [name]), + "keyActualValue" : sprintf("'azurerm_storage_account[%s].customer_managed_key' is undefined or null", [name]), + "searchLine" : common_lib.build_search_line(["resource", "azurerm_storage_account", name], []) + } +} + +is_associated_with_cmk_resource(custom_managed_keys, id_reference) { + custom_managed_keys[_].storage_account_id == id_reference +} diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/test/negative1.tf b/assets/queries/terraform/azure/storage_account_without_cmk/test/negative1.tf new file mode 100644 index 00000000000..b0658c8621c --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/test/negative1.tf @@ -0,0 +1,20 @@ +resource "azurerm_storage_account" "negative1" { # associated with "azurerm_storage_account_customer_managed_key" resource + name = "storageaccountname" + resource_group_name = azurerm_resource_group.negative1.name + location = azurerm_resource_group.negative1.location + account_tier = "Standard" + account_replication_type = "GRS" +} + +resource "azurerm_monitor_diagnostic_setting" "negative1" { + name = "negative1" + target_resource_id = azurerm_subscription.negative1.id + + storage_account_id = azurerm_storage_account.negative1.id +} + +resource "azurerm_storage_account_customer_managed_key" "negative1" { + storage_account_id = azurerm_storage_account.negative1.id + key_vault_id = azurerm_key_vault.negative1.id + key_name = azurerm_key_vault_key.negative1.name +} diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/test/negative2.tf b/assets/queries/terraform/azure/storage_account_without_cmk/test/negative2.tf new file mode 100644 index 00000000000..d8f8baee7bd --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/test/negative2.tf @@ -0,0 +1,39 @@ +resource "azurerm_storage_account" "negative2_1" { # sets "customer_managed_key" field + name = "storageaccountname" + resource_group_name = azurerm_resource_group.negative2_1.name + location = azurerm_resource_group.negative2_1.location + account_tier = "Standard" + account_replication_type = "GRS" + + customer_managed_key { + key_vault_key_id = azurerm_key_vault_key.example.id + user_assigned_identity_id = azurerm_user_assigned_identity.example.id + } +} + +resource "azurerm_monitor_diagnostic_setting" "negative2_1" { + name = "negative2_1" + target_resource_id = azurerm_subscription.negative2_1.id + + storage_account_id = azurerm_storage_account.negative2_1.id +} + +resource "azurerm_storage_account" "negative2_2" { # sets "customer_managed_key" field + name = "storageaccountname" + resource_group_name = azurerm_resource_group.negative2_2.name + location = azurerm_resource_group.negative2_2.location + account_tier = "Standard" + account_replication_type = "GRS" + + customer_managed_key { + managed_hsm_key_id = azurerm_managed_hsm_key.example.id + user_assigned_identity_id = azurerm_user_assigned_identity.example.id + } +} + +resource "azurerm_monitor_diagnostic_setting" "negative2_2" { + name = "negative2_2" + target_resource_id = azurerm_subscription.negative2_2.id + + storage_account_id = azurerm_storage_account.negative2_2.id +} diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/test/negative3.tf b/assets/queries/terraform/azure/storage_account_without_cmk/test/negative3.tf new file mode 100644 index 00000000000..7a49a4afec1 --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/test/negative3.tf @@ -0,0 +1,7 @@ +resource "azurerm_storage_account" "negative3" { # missing associated "azurerm_monitor_diagnostic_setting" + name = "storageaccountname" + resource_group_name = azurerm_resource_group.negative3.name + location = azurerm_resource_group.negative3.location + account_tier = "Standard" + account_replication_type = "GRS" +} diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/test/positive1.tf b/assets/queries/terraform/azure/storage_account_without_cmk/test/positive1.tf new file mode 100644 index 00000000000..05ddb233607 --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/test/positive1.tf @@ -0,0 +1,16 @@ +resource "azurerm_storage_account" "positive1_1" { + name = "storageaccountname" + resource_group_name = azurerm_resource_group.positive1_1.name + location = azurerm_resource_group.positive1_1.location + account_tier = "Standard" + account_replication_type = "GRS" + + # missing "customer_managed_key" block +} + +resource "azurerm_monitor_diagnostic_setting" "positive1_1" { + name = "positive1_1" + target_resource_id = azurerm_subscription.positive1_1.id + + storage_account_id = azurerm_storage_account.positive1_1.id +} diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/test/positive2.tf b/assets/queries/terraform/azure/storage_account_without_cmk/test/positive2.tf new file mode 100644 index 00000000000..2880b744eca --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/test/positive2.tf @@ -0,0 +1,16 @@ +resource "azurerm_storage_account" "positive2_1" { + name = "storageaccountname" + resource_group_name = azurerm_resource_group.positive2_1.name + location = azurerm_resource_group.positive2_1.location + account_tier = "Standard" + account_replication_type = "GRS" +} + +resource "azurerm_monitor_diagnostic_setting" "positive2_1" { + name = "positive2_1" + target_resource_id = azurerm_subscription.positive2_1.id + + storage_account_id = azurerm_storage_account.positive2_1.id +} + +# missing "azurerm_storage_account_customer_managed_key" association diff --git a/assets/queries/terraform/azure/storage_account_without_cmk/test/positive_expected_result.json b/assets/queries/terraform/azure/storage_account_without_cmk/test/positive_expected_result.json new file mode 100644 index 00000000000..a98b4556f9d --- /dev/null +++ b/assets/queries/terraform/azure/storage_account_without_cmk/test/positive_expected_result.json @@ -0,0 +1,14 @@ +[ + { + "queryName": "Beta - Storage Account Without CMK", + "severity": "MEDIUM", + "line": 1, + "fileName": "positive1.tf" + }, + { + "queryName": "Beta - Storage Account Without CMK", + "severity": "MEDIUM", + "line": 1, + "fileName": "positive2.tf" + } +] diff --git a/assets/similarityID_transition/terraform_azure.yaml b/assets/similarityID_transition/terraform_azure.yaml index f01407cc4c6..2229c298d37 100644 --- a/assets/similarityID_transition/terraform_azure.yaml +++ b/assets/similarityID_transition/terraform_azure.yaml @@ -3,6 +3,10 @@ similarityIDChangeList: queryName: Sensitive Port Is Exposed To Wide Private Network observations: "" change: 5 + - queryId: 9bf1568d-4cd2-4581-81ef-d2efabee1178 + queryName: Beta - Storage Account Without CMK + observations: "" + change: 2 - queryId: 05d6b52e-11ca-453d-bb3a-21c7c853ee92 queryName: Beta - Databricks Workspace Using Default Virtual Network observations: ""