diff --git a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/metadata.json b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/metadata.json index 770e9fd3be0..22b4eeaaeea 100644 --- a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/metadata.json +++ b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/metadata.json @@ -10,4 +10,4 @@ "cloudProvider": "azure", "cwe": "311", "riskScore": "5.5" -} \ No newline at end of file +} diff --git a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/query.rego b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/query.rego index bd7260c3a01..deb4a586507 100644 --- a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/query.rego +++ b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/query.rego @@ -4,42 +4,55 @@ import data.generic.common as common_lib import data.generic.terraform as tf_lib CxPolicy[result] { - resource := input.document[i].resource - encryption := resource.azurerm_managed_disk[name] - not common_lib.valid_key(encryption, "encryption_settings") + resource := input.document[i].resource.azurerm_managed_disk[name] + + results := undefined_or_empty(resource, name) result := { "documentId": input.document[i].id, "resourceType": "azurerm_managed_disk", "resourceName": tf_lib.get_resource_name(resource, name), - "searchKey": sprintf("azurerm_managed_disk[%s]", [name]), - "issueType": "MissingAttribute", - "keyExpectedValue": sprintf("azurerm_managed_disk[%s].encryption_settings should be defined and not null", [name]), - "keyActualValue": sprintf("azurerm_managed_disk[%s].encryption_settings is undefined or null", [name]), - "searchLine": common_lib.build_search_line(["resource","azurerm_managed_disk" ,name], []), - "remediation": "encryption_settings = {\n\t\t enabled= true\n\t}\n", - "remediationType": "addition", + "searchKey": results.searchKey, + "issueType": results.issueType, + "keyExpectedValue": results.keyExpectedValue, + "keyActualValue": results.keyActualValue, + "searchLine": results.searchLine, + "remediation": results.remediation, + "remediationType": results.remediationType } } -CxPolicy[result] { - resource := input.document[i].resource - encryption := resource.azurerm_managed_disk[name] - encryption.encryption_settings.enabled == false - - result := { - "documentId": input.document[i].id, - "resourceType": "azurerm_managed_disk", - "resourceName": tf_lib.get_resource_name(resource, name), +undefined_or_empty(resource, name) = results { + not common_lib.valid_key(resource, "encryption_settings") + results := { + "searchKey": sprintf("azurerm_managed_disk[%s]", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'azurerm_managed_disk[%s].encryption_settings' should be defined and not null", [name]), + "keyActualValue": sprintf("'azurerm_managed_disk[%s].encryption_settings' is undefined or null", [name]), + "searchLine": common_lib.build_search_line(["resource", "azurerm_managed_disk", name], []), + "remediation": null, + "remediationType": null + } +} else = results { + resource.encryption_settings == [[],{}][_] # [] for tfplan support + results := { + "searchKey": sprintf("azurerm_managed_disk[%s].encryption_settings", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'azurerm_managed_disk[%s].encryption_settings' should be defined and not null", [name]), + "keyActualValue": sprintf("'azurerm_managed_disk[%s].encryption_settings' is set to '%v", [name, resource.encryption_settings]), + "searchLine": common_lib.build_search_line(["resource", "azurerm_managed_disk", name, "encryption_settings"], []), + "remediation": null, + "remediationType": null + } +} else = results { + resource.encryption_settings.enabled == false + results := { "searchKey": sprintf("azurerm_managed_disk[%s].encryption_settings.enabled", [name]), "issueType": "IncorrectValue", - "keyExpectedValue": sprintf("azurerm_managed_disk[%s].encryption_settings.enabled should be true ", [name]), - "keyActualValue": sprintf("azurerm_managed_disk[%s].encryption_settings.enabled is false", [name]), - "searchLine": common_lib.build_search_line(["resource","azurerm_managed_disk" ,name ,"encryption_settings", "enabled"], []), - "remediation": json.marshal({ - "before": "false", - "after": "true" - }), - "remediationType": "replacement", + "keyExpectedValue": sprintf("'azurerm_managed_disk[%s].encryption_settings.enabled' should be set to true", [name]), + "keyActualValue": sprintf("'azurerm_managed_disk[%s].encryption_settings.enabled' is set to false", [name]), + "searchLine": common_lib.build_search_line(["resource", "azurerm_managed_disk", name, "encryption_settings", "enabled"], []), + "remediation": json.marshal({"before": "false", "after": "true"}), + "remediationType": "replacement" } } diff --git a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/negative.tf b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/negative.tf index 119c4cc2df0..a41be3c9c32 100644 --- a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/negative.tf +++ b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/negative.tf @@ -6,11 +6,63 @@ resource "azurerm_managed_disk" "negative1" { storage_account_type = "Standard_LRS" create_option = "Empty" disk_size_gb = "1" - - encryption_settings = { - enabled = true + + encryption_settings { + enabled = true # legacy + } +} + +resource "azurerm_managed_disk" "negative2" { + name = "acctestmd" + location = "West US 2" + resource_group_name = azurerm_resource_group.example.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + encryption_settings { + + disk_encryption_key { + secret_url = "sample_url" + source_vault_id = "sample_id" + } + + key_encryption_key { + secret_url = "sample_url" + source_vault_id = "sample_id" + } + + } +} + +resource "azurerm_managed_disk" "negative3" { + name = "acctestmd" + location = "West US 2" + resource_group_name = azurerm_resource_group.example.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + encryption_settings { + disk_encryption_key { + secret_url = "sample_url" + source_vault_id = "sample_id" + } } - tags = { - environment = "staging" +} + +resource "azurerm_managed_disk" "negative4" { + name = "acctestmd" + location = "West US 2" + resource_group_name = azurerm_resource_group.example.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + encryption_settings { + key_encryption_key { + secret_url = "sample_url" + source_vault_id = "sample_id" + } } -} \ No newline at end of file +} diff --git a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive.tf b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive.tf index 78d461a632b..85b116ae07b 100644 --- a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive.tf +++ b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive.tf @@ -6,12 +6,8 @@ resource "azurerm_managed_disk" "positive1" { create_option = "Empty" disk_size_gb = "1" - encryption_settings = { - enabled = false - } - - tags = { - environment = "staging" + encryption_settings { + enabled = false # legacy } } @@ -22,9 +18,28 @@ resource "azurerm_managed_disk" "positive2" { storage_account_type = "Standard_LRS" create_option = "Empty" disk_size_gb = "1" - - tags = { - environment = "staging" - } -} \ No newline at end of file + # missing "encryption_settings" +} + +resource "azurerm_managed_disk" "positive3" { + name = "acctestmd" + location = "West US 2" + resource_group_name = azurerm_resource_group.example.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + encryption_settings {} +} + +resource "azurerm_managed_disk" "positive4" { + name = "acctestmd" + location = "West US 2" + resource_group_name = azurerm_resource_group.example.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + encryption_settings = [] # simulates "tfplan" +} diff --git a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive_expected_result.json b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive_expected_result.json index 9cef2f7f43c..22ca038752f 100644 --- a/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive_expected_result.json +++ b/assets/queries/terraform/azure/encryption_on_managed_disk_disabled/test/positive_expected_result.json @@ -7,6 +7,16 @@ { "queryName": "Encryption On Managed Disk Disabled", "severity": "MEDIUM", - "line": 18 + "line": 14 + }, + { + "queryName": "Encryption On Managed Disk Disabled", + "severity": "MEDIUM", + "line": 33 + }, + { + "queryName": "Encryption On Managed Disk Disabled", + "severity": "MEDIUM", + "line": 44 } ] diff --git a/pkg/parser/json/tfplan.go b/pkg/parser/json/tfplan.go index 23f2a8aa5fa..4dc110995b1 100644 --- a/pkg/parser/json/tfplan.go +++ b/pkg/parser/json/tfplan.go @@ -62,14 +62,12 @@ func readPlan(plan *hcl_plan.Plan) model.Document { // readModule will iterate over all planned_value getting the information required func (kp *KicsPlan) readModule(module *hcl_plan.StateModule) { - // initialize all the types interfaces + // initialize all the types interfaces and fill in all the types interfaces for _, resource := range module.Resources { - convNamedRes := make(map[string]KicsPlanNamedResource) - kp.Resource[resource.Type] = convNamedRes - } - // fill in all the types interfaces - for _, resource := range module.Resources { - kp.Resource[resource.Type][resource.Name] = resource.AttributeValues + if _, type_map := kp.Resource[resource.Type]; !type_map { + kp.Resource[resource.Type] = make(map[string]KicsPlanNamedResource) + } + kp.Resource[resource.Type][resource.Address] = resource.AttributeValues } for _, childModule := range module.ChildModules { diff --git a/pkg/parser/json/tfplan_test.go b/pkg/parser/json/tfplan_test.go index 46bff92cc41..6b17a679e6e 100644 --- a/pkg/parser/json/tfplan_test.go +++ b/pkg/parser/json/tfplan_test.go @@ -51,7 +51,7 @@ func TestJson_parseTFPlan(t *testing.T) { want: model.Document{ "resource": map[string]interface{}{ "fakewebservices_database": map[string]interface{}{ - "prod_db": map[string]interface{}{ + "fakewebservices_database.prod_db": map[string]interface{}{ "name": "Production DB", "size": (float64)(256), }, @@ -72,6 +72,54 @@ func TestJson_parseTFPlan(t *testing.T) { want: model.Document{}, wantErr: true, }, + { + name: "test - parse tfplan with duplicate resource names (different addresses)", + args: args{ + doc: model.Document{ + "format_version": "0.2", + "terraform_version": "1.0.5", + "planned_values": map[string]interface{}{ + "root_module": map[string]interface{}{ + "resources": []map[string]interface{}{ + { + "address": "fakewebservices_database.prod_db[0]", + "type": "fakewebservices_database", + "name": "prod_db", + "values": map[string]interface{}{ + "name": "Production DB A", + "size": 256, + }, + }, + { + "address": "fakewebservices_database.prod_db[1]", + "type": "fakewebservices_database", + "name": "prod_db", + "values": map[string]interface{}{ + "name": "Production DB B", + "size": 512, + }, + }, + }, + }, + }, + }, + }, + want: model.Document{ + "resource": map[string]interface{}{ + "fakewebservices_database": map[string]interface{}{ + "fakewebservices_database.prod_db[0]": map[string]interface{}{ + "name": "Production DB A", + "size": (float64)(256), + }, + "fakewebservices_database.prod_db[1]": map[string]interface{}{ + "name": "Production DB B", + "size": (float64)(512), + }, + }, + }, + }, + wantErr: false, + }, } for _, tt := range tests {