Repository: bridgecrewio/checkov

Issue:
GCP: crash running CKV_GCP_2 and CKV_GCP_3 (unrestricted ingress)
**Describe the bug**

Checkov crashes while scanning a firewall rule block such as the one generated by [terraform-google-lb-http](https://github.com/terraform-google-modules/terraform-google-lb-http/blob/ca8a56700f0b03f8bf4353fde182ff72673a2a5d/main.tf#L197-L216).

 - Checkov Version 1.0.369

```console
cadams@Ganymede ~/Project/myproject (master)> docker run --rm --volume "$PWD":/tf bridgecrew/checkov -d /tf
ERROR:checkov.terraform.checks.resource.gcp.GoogleComputeFirewallUnrestrictedIngress22:Failed to run check: Ensure Google compute firewall ingress does not allow unrestricted ssh access for configuration: {'count': ['${length(var.firewall_networks)}'], 'project': ['${length(var.firewall_networks) == 1 && var.firewall_projects[0] == "default" ? var.project : var.firewall_projects[count.index]}'], 'name': ['${var.name}-hc-${count.index}'], 'network': ['${var.firewall_networks[count.index]}'], 'source_ranges': [['130.211.0.0/22', '35.191.0.0/16']], 'target_tags': ['${length(var.target_tags) > 0 ? var.target_tags : None}'], 'target_service_accounts': ['${length(var.target_service_accounts) > 0 ? var.target_service_accounts : None}'], 'dynamic': [{'allow': {'for_each': ['${var.backends}'], 'content': [{'protocol': ['tcp'], 'ports': [['${allow.value.port}']]}]}}], 'allow': ['${var.backends}']} at file: /.terraform/modules/gce-lb-http/terraform-google-lb-http-4.0.0/main.tf
Traceback (most recent call last):
  File "/usr/local/bin/checkov", line 5, in <module>
    2020-06-12 18:36:49,936 [MainThread  ] [ERROR]  Failed to run check: Ensure Google compute firewall ingress does not allow unrestricted ssh access for configuration: {'count': ['${length(var.firewall_networks)}'], 'project': ['${length(var.firewall_networks) == 1 && var.firewall_projects[0] == "default" ? var.project : var.firewall_projects[count.index]}'], 'name': ['${var.name}-hc-${count.index}'], 'network': ['${var.firewall_networks[count.index]}'], 'source_ranges': [['130.211.0.0/22', '35.191.0.0/16']], 'target_tags': ['${length(var.target_tags) > 0 ? var.target_tags : None}'], 'target_service_accounts': ['${length(var.target_service_accounts) > 0 ? var.target_service_accounts : None}'], 'dynamic': [{'allow': {'for_each': ['${var.backends}'], 'content': [{'protocol': ['tcp'], 'ports': [['${allow.value.port}']]}]}}], 'allow': ['${var.backends}']} at file: /.terraform/modules/gce-lb-http/terraform-google-lb-http-4.0.0/main.tf
run()
  File "/usr/local/lib/python3.8/site-packages/checkov/main.py", line 75, in run
    scan_reports = runner_registry.run(root_folder=root_folder, external_checks_dir=args.external_checks_dir,
  File "/usr/local/lib/python3.8/site-packages/checkov/common/runners/runner_registry.py", line 25, 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 50, in run
    self.check_tf_definition(report, root_folder, runner_filter)
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/runner.py", line 90, 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 113, 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 64, 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 70, 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 44, in run
    raise e
  File "/usr/local/lib/python3.8/site-packages/checkov/common/checks/base_check.py", line 33, in run
    check_result['result'] = self.scan_entity_conf(entity_configuration)
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/checks/resource/base_resource_check.py", line 20, in scan_entity_conf
    return self.scan_resource_conf(conf)
  File "/usr/local/lib/python3.8/site-packages/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress22.py", line 25, in scan_resource_conf
    if 'ports' in block.keys():
AttributeError: 'str' object has no attribute 'keys'
```



Discussion:
A quick look in pdb shows that the data format has changed from what's expected and an extra step is needed to resolve variable references:

```
(Pdb) l
 20  	        :return: <CheckResult>
 21  	        """
 22  	        if 'allow' in conf:
 23  	            allow_blocks = conf['allow']
 24  	            for block in allow_blocks:
 25  ->	                if 'ports' in block.keys():
 26  	                    if PORT in block['ports'][0]:
 27  	                        if 'source_ranges' in conf.keys():
 28  	                            source_ranges = conf['source_ranges'][0]
 29  	                            if "0.0.0.0/0" in source_ranges:
 30  	                                return CheckResult.FAILED
(Pdb) p allow_blocks
['${var.backends}']
(Pdb) p conf
{'count': ['${length(var.firewall_networks)}'], 'project': ['${length(var.firewall_networks) == 1 && var.firewall_projects[0] == "default" ? var.project : var.firewall_projects[count.index]}'], 'name': ['${var.name}-hc-${count.index}'], 'network': ['${var.firewall_networks[count.index]}'], 'source_ranges': [['130.211.0.0/22', '35.191.0.0/16']], 'target_tags': ['${length(var.target_tags) > 0 ? var.target_tags : None}'], 'target_service_accounts': ['${length(var.target_service_accounts) > 0 ? var.target_service_accounts : None}'], 'dynamic': [{'allow': {'for_each': ['${var.backends}'], 'content': [{'protocol': ['tcp'], 'ports': [['${allow.value.port}']]}]}}], 'allow': ['${var.backends}']}
```

Resolving patch:
diff --git a/checkov/terraform/checks/resource/gcp/AbsGoogleComputeFirewallUnrestrictedIngress.py b/checkov/terraform/checks/resource/gcp/AbsGoogleComputeFirewallUnrestrictedIngress.py
new file mode 100644
--- /dev/null
+++ b/checkov/terraform/checks/resource/gcp/AbsGoogleComputeFirewallUnrestrictedIngress.py
@@ -0,0 +1,22 @@
+from checkov.common.models.enums import CheckResult
+from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
+
+
+class AbsGoogleComputeFirewallUnrestrictedIngress(BaseResourceCheck):
+    def __init__(self, name, id, categories, supported_resources, port):
+        super().__init__(name, id, categories, supported_resources)
+        self.port = port
+
+    def scan_resource_conf(self, conf):
+        if 'allow' in conf:
+            allow_blocks = conf['allow']
+            for block in allow_blocks:
+                if isinstance(block, str):
+                    return CheckResult.UNKNOWN
+                if 'ports' in block.keys():
+                    if self.port in block['ports'][0]:
+                        if 'source_ranges' in conf.keys():
+                            source_ranges = conf['source_ranges'][0]
+                            if "0.0.0.0/0" in source_ranges:
+                                return CheckResult.FAILED
+        return CheckResult.PASSED
diff --git a/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress22.py b/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress22.py
--- a/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress22.py
+++ b/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress22.py
@@ -1,34 +1,16 @@
-from checkov.common.models.enums import CheckResult, CheckCategories
-from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
+from checkov.common.models.enums import CheckCategories
+from checkov.terraform.checks.resource.gcp.AbsGoogleComputeFirewallUnrestrictedIngress import AbsGoogleComputeFirewallUnrestrictedIngress
 
 PORT = '22'
 
 
-class GoogleComputeFirewallUnrestrictedIngress22(BaseResourceCheck):
+class GoogleComputeFirewallUnrestrictedIngress22(AbsGoogleComputeFirewallUnrestrictedIngress):
     def __init__(self):
         name = "Ensure Google compute firewall ingress does not allow unrestricted ssh access"
         id = "CKV_GCP_2"
         supported_resources = ['google_compute_firewall']
         categories = [CheckCategories.NETWORKING]
-        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
-
-    def scan_resource_conf(self, conf):
-        """
-            Looks for password configuration at google_compute_firewall:
-            https://www.terraform.io/docs/providers/google/r/compute_firewall.html
-        :param conf: azure_instance configuration
-        :return: <CheckResult>
-        """
-        if 'allow' in conf:
-            allow_blocks = conf['allow']
-            for block in allow_blocks:
-                if 'ports' in block.keys():
-                    if PORT in block['ports'][0]:
-                        if 'source_ranges' in conf.keys():
-                            source_ranges = conf['source_ranges'][0]
-                            if "0.0.0.0/0" in source_ranges:
-                                return CheckResult.FAILED
-        return CheckResult.PASSED
+        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources, port=PORT)
 
 
 check = GoogleComputeFirewallUnrestrictedIngress22()
diff --git a/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress3389.py b/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress3389.py
--- a/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress3389.py
+++ b/checkov/terraform/checks/resource/gcp/GoogleComputeFirewallUnrestrictedIngress3389.py
@@ -1,34 +1,16 @@
-from checkov.common.models.enums import CheckResult, CheckCategories
-from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
+from checkov.common.models.enums import CheckCategories
+from checkov.terraform.checks.resource.gcp.AbsGoogleComputeFirewallUnrestrictedIngress import AbsGoogleComputeFirewallUnrestrictedIngress
 
 PORT = '3389'
 
 
-class GoogleComputeFirewallUnrestrictedIngress3389(BaseResourceCheck):
+class GoogleComputeFirewallUnrestrictedIngress3389(AbsGoogleComputeFirewallUnrestrictedIngress):
     def __init__(self):
         name = "Ensure Google compute firewall ingress does not allow unrestricted rdp access"
         id = "CKV_GCP_3"
         supported_resources = ['google_compute_firewall']
         categories = [CheckCategories.NETWORKING]
-        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
-
-    def scan_resource_conf(self, conf):
-        """
-            Looks for password configuration at google_compute_firewall:
-            https://www.terraform.io/docs/providers/google/r/compute_firewall.html
-        :param conf: azure_instance configuration
-        :return: <CheckResult>
-        """
-        if 'allow' in conf:
-            allow_blocks = conf['allow']
-            for block in allow_blocks:
-                if 'ports' in block.keys():
-                    if PORT in block['ports'][0]:
-                        if 'source_ranges' in conf.keys():
-                            source_ranges = conf['source_ranges'][0]
-                            if "0.0.0.0/0" in source_ranges:
-                                return CheckResult.FAILED
-        return CheckResult.PASSED
+        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources, port=PORT)
 
 
 check = GoogleComputeFirewallUnrestrictedIngress3389()


Test patch:
diff --git a/tests/terraform/checks/resource/gcp/test_TestGoogleComputeFirewallUnrestrictedIngress22.py b/tests/terraform/checks/resource/gcp/test_TestGoogleComputeFirewallUnrestrictedIngress22.py
--- a/tests/terraform/checks/resource/gcp/test_TestGoogleComputeFirewallUnrestrictedIngress22.py
+++ b/tests/terraform/checks/resource/gcp/test_TestGoogleComputeFirewallUnrestrictedIngress22.py
@@ -23,6 +23,11 @@ def test_success(self):
         scan_result = check.scan_resource_conf(conf=resource_conf)
         self.assertEqual(CheckResult.PASSED, scan_result)
 
+    def test_unknown(self):
+        conf = {'count': ['${length(var.firewall_networks)}'], 'project': ['${length(var.firewall_networks) == 1 && var.firewall_projects[0] == "default" ? var.project : var.firewall_projects[count.index]}'], 'name': ['${var.name}-hc-${count.index}'], 'network': ['${var.firewall_networks[count.index]}'], 'source_ranges': [['130.211.0.0/22', '35.191.0.0/16']], 'target_tags': ['${length(var.target_tags) > 0 ? var.target_tags : None}'], 'target_service_accounts': ['${length(var.target_service_accounts) > 0 ? var.target_service_accounts : None}'], 'dynamic': [{'allow': {'for_each': ['${var.backends}'], 'content': [{'protocol': ['tcp'], 'ports': [['${allow.value.port}']]}]}}], 'allow': ['${var.backends}']}
+        scan_result = check.scan_resource_conf(conf)
+        self.assertEqual(scan_result, CheckResult.UNKNOWN)
+
 
 if __name__ == '__main__':
     unittest.main()