Repository: bridgecrewio/checkov

Issue:
Azure NSG Security rule loop error
I got the following error when I execute to scan Azure NSG terraform file.

_ERROR:checkov.terraform.checks.resource.azure.NSGRuleSSHAccessRestricted:Failed to run check: Ensure that SSH access is restricted from the internet for configuration: {'name': ['${var.nsg_name}'], 'resource_group_name': ['${azurerm_resource_group.rg.name}'], 'location': ['${var.location}'], 'security_rule': ['${[for rule in var.security_rules : {\'name\': \'${rule.name}\', \'priority\': \'${rule.priority}\', \'source_address_prefix\': \'${lookup(rule,"source_address_prefixes",[]) == [] ? lookup(rule,"source_address_prefix",var.nsg_default_source_address_prefix) : ""}\', \'source_address_prefixes\': \'${lookup(rule,"source_address_prefixes",[])}\', \'access\': \'${lookup(rule,"access",var.nsg_default_access)}\', \'destination_port_range\': \'${lookup(rule,"destination_port_ranges",[]) == [] ? lookup(rule,"destination_port_range",var.nsg_default_destination_port_range) : ""}\', \'destination_port_ranges\': \'${lookup(rule,"destination_port_ranges",[])}\', \'direction\': \'${lookup(rule,"direction",var.nsg_default_direction)}\', \'protocol\': \'${lookup(rule,"protocol",var.nsg_default_protocol)}\', \'source_port_range\': \'${lookup(rule,"source_port_range",var.nsg_default_source_port_range)}\', \'description\': \'\', \'destination_address_prefix\': \'*\', \'destination_address_prefixes\': [], \'destination_application_security_group_ids\': [], \'source_application_security_group_ids\': [], \'source_port_ranges\': []}]}'], 'tags': ['${var.tags}']} at file: /aaa.tf
2020-09-11 11:23:01,213 [MainThread  ] [ERROR]  Failed to run check: Ensure that SSH access is restricted from the internet for configuration: {'name': ['${var.nsg_name}'], 'resource_group_name': ['${azurerm_resource_group.rg.name}'], 'location': ['${var.location}'], 'security_rule': ['${[for rule in var.security_rules : {\'name\': \'${rule.name}\', \'priority\': \'${rule.priority}\', \'source_address_prefix\': \'${lookup(rule,"source_address_prefixes",[]) == [] ? lookup(rule,"source_address_prefix",var.nsg_default_source_address_prefix) : ""}\', \'source_address_prefixes\': \'${lookup(rule,"source_address_prefixes",[])}\', \'access\': \'${lookup(rule,"access",var.nsg_default_access)}\', \'destination_port_range\': \'${lookup(rule,"destination_port_ranges",[]) == [] ? lookup(rule,"destination_port_range",var.nsg_default_destination_port_range) : ""}\', \'destination_port_ranges\': \'${lookup(rule,"destination_port_ranges",[])}\', \'direction\': \'${lookup(rule,"direction",var.nsg_default_direction)}\', \'protocol\': \'${lookup(rule,"protocol",var.nsg_default_protocol)}\', \'source_port_range\': \'${lookup(rule,"source_port_range",var.nsg_default_source_port_range)}\', \'description\': \'\', \'destination_address_prefix\': \'*\', \'destination_address_prefixes\': [], \'destination_application_security_group_ids\': [], \'source_application_security_group_ids\': [], \'source_port_ranges\': []}]}'], 'tags': ['${var.tags}']} at file: /aaa.tf
Traceback (most recent call last):
  File "/usr/local/bin/checkov", line 5, in <module>
    run()
  File "/usr/local/lib/python3.8/site-packages/checkov/main.py", line 65, in run
    scan_reports = runner_registry.run(root_folder=root_folder, external_checks_dir=external_checks_dir,
  File "/usr/local/lib/python3.8/site-packages/checkov/common/runners/runner_registry.py", line 27, in run
    scan_report = runner.run(root_folder, external_checks_dir=external_checks_dir, files=files,
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/runner.py", line 52, in run
    self.check_tf_definition(report, root_folder, runner_filter)
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/runner.py", line 94, in check_tf_definition
    self.run_block(definition[block_type], definitions_context, full_file_path, report, scanned_file,
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/runner.py", line 117, in run_block
    results = registry.scan(scanned_file, entity, skipped_checks, runner_filter)
  File "/usr/local/lib/python3.8/site-packages/checkov/common/checks/base_check_registry.py", line 104, in scan
    result = self.run_check(check, entity_configuration, entity_name, entity_type, scanned_file, skip_info)
  File "/usr/local/lib/python3.8/site-packages/checkov/common/checks/base_check_registry.py", line 110, in run_check
    result = check.run(scanned_file=scanned_file, entity_configuration=entity_configuration,
  File "/usr/local/lib/python3.8/site-packages/checkov/common/checks/base_check.py", line 58, in run
    raise e
  File "/usr/local/lib/python3.8/site-packages/checkov/common/checks/base_check.py", line 39, in run
    check_result['result'] = self.scan_entity_conf(entity_configuration, entity_type)
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/checks/resource/base_resource_check.py", line 16, in scan_entity_conf
    return self.scan_resource_conf(conf, entity_type)
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/checks/resource/base_resource_check.py", line 28, in wrapper
    return wrapped(self, conf)
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/checks/resource/azure/NSGRulePortAccessRestricted.py", line 37, in scan_resource_conf
    if 'access' in rule_conf and rule_conf['access'][0] == "Allow":
TypeError: string indices must be integers_

**Scanned NSG:**

resource "azurerm_network_security_group" "mynsg" {
  name                = var.nsg_name
  resource_group_name = azurerm_resource_group.rg.name
  location            = var.location

  security_rule = [for rule in var.security_rules : {
    name     = rule.name
    priority = rule.priority
    source_address_prefix                      = lookup(rule, "source_address_prefixes", []) == [] ? lookup(rule, "source_address_prefix", var.nsg_default_source_address_prefix) : ""
    source_address_prefixes                    = lookup(rule, "source_address_prefixes", [])
    access                                     = lookup(rule, "access", var.nsg_default_access)
    destination_port_range                     = lookup(rule, "destination_port_ranges", []) == [] ? lookup(rule, "destination_port_range", var.nsg_default_destination_port_range) : ""
    destination_port_ranges                    = lookup(rule, "destination_port_ranges", [])
    direction                                  = lookup(rule, "direction", var.nsg_default_direction)
    protocol                                   = lookup(rule, "protocol", var.nsg_default_protocol)
    source_port_range                          = lookup(rule, "source_port_range", var.nsg_default_source_port_range)
    description                                = ""
    destination_address_prefix                 = "*"
    destination_address_prefixes               = []
    destination_application_security_group_ids = []
    source_application_security_group_ids      = []
    source_port_ranges                         = []
    }
  ]
}



Discussion:

Resolving patch:
diff --git a/checkov/terraform/checks/resource/azure/NSGRulePortAccessRestricted.py b/checkov/terraform/checks/resource/azure/NSGRulePortAccessRestricted.py
--- a/checkov/terraform/checks/resource/azure/NSGRulePortAccessRestricted.py
+++ b/checkov/terraform/checks/resource/azure/NSGRulePortAccessRestricted.py
@@ -34,6 +34,8 @@ def scan_resource_conf(self, conf):
             rule_confs = conf['security_rule']
 
         for rule_conf in rule_confs:
+            if not isinstance(rule_conf, dict):
+                return CheckResult.UNKNOWN
             if 'access' in rule_conf and rule_conf['access'][0] == "Allow":
                 if 'direction' in rule_conf and rule_conf['direction'][0] == "Inbound":
                     if 'protocol' in rule_conf and rule_conf['protocol'][0].upper() == 'TCP':


Test patch:
diff --git a/tests/terraform/checks/resource/azure/test_NSGRuleSSHAccessRestricted.py b/tests/terraform/checks/resource/azure/test_NSGRuleSSHAccessRestricted.py
--- a/tests/terraform/checks/resource/azure/test_NSGRuleSSHAccessRestricted.py
+++ b/tests/terraform/checks/resource/azure/test_NSGRuleSSHAccessRestricted.py
@@ -48,6 +48,37 @@ def test_success(self):
         scan_result = check.scan_resource_conf(conf=resource_conf)
         self.assertEqual(CheckResult.PASSED, scan_result)
 
+    def test_unknown(self):
+        hcl_res = hcl2.loads("""
+resource "azurerm_network_security_group" "mynsg" {
+    name = var.nsg_name
+    resource_group_name = azurerm_resource_group.rg.name
+    location = var.location
+
+    security_rule = [for rule in var.security_rules : {
+        name = rule.name
+        priority = rule.priority
+        source_address_prefix = lookup(rule, "source_address_prefixes", []) == [] ? lookup(rule, "source_address_prefix", var.nsg_default_source_address_prefix) : ""
+        source_address_prefixes = lookup(rule, "source_address_prefixes", [])
+        access = lookup(rule, "access", var.nsg_default_access)
+        destination_port_range = lookup(rule, "destination_port_ranges", []) == [] ? lookup(rule, "destination_port_range", var.nsg_default_destination_port_range) : ""
+        destination_port_ranges = lookup(rule, "destination_port_ranges", [])
+        direction = lookup(rule, "direction", var.nsg_default_direction)
+        protocol = lookup(rule, "protocol", var.nsg_default_protocol)
+        source_port_range = lookup(rule, "source_port_range", var.nsg_default_source_port_range)
+        description = ""
+        destination_address_prefix = "*"
+        destination_address_prefixes = []
+        destination_application_security_group_ids = []
+        source_application_security_group_ids = []
+        source_port_ranges = []
+    }]
+}
+        """)
+
+        resource_conf = hcl_res['resource'][0]['azurerm_network_security_group']['mynsg']
+        scan_result = check.scan_resource_conf(conf=resource_conf)
+        self.assertEqual(CheckResult.UNKNOWN, scan_result)
 
 
 if __name__ == '__main__':