Repository: tfsec/tfsec
Pull request #456 (2020-10-21 19:48:45)

Extract open cidr checks into util function
Extracted the repeated open CIDR checks into a separate utility function.

I realize this was "_unasked for_" and "_not discussed yet_" according to the contributing guide, though I figured it's the only way to move forward with even more of these checks planned.

Consider this a proposal, and open for discussion.

I'm not sure what to do with the similar checks for *azure*, as in that case, there also seems to be `"*"` possible as an open CIDR.

owenrumney: I'm wondering if we could pass the provider into the check and fan out from there?

Have the isOpenCidr(cidr, provider)

Then switch on the provider to handle azure vs aws approach

What do you think?
particleflux: The `Provider` field of the `Check` struct? Might be an idea, hadn't realized this is already available to the check func.

It's basically only the innermost condition which is different. Otherwise it's always a `ValueSlice()`, and always checked against `lengthInt()` and `IsNull()`

So something like this should work:

```
cidrStr := cidr.AsString()
switch provider {
case GCPProvider:
case AWSProvider:
    if strings.HasSuffix(cidrStr, "/0") {
        return true
case AzureProvider:
    if strings.HasSuffix(cidrStr, "/0") || cidrStr == "*" {
        return true
}
```

No default case, it'll fallback to `false` anyway.

owenrumney: Yup, that's what I was thinking might work. 
particleflux: Yes, I will try that.
particleflux: Extended it to be compatible with Azure and GCP as well.

There is one downside to Azure though: With these changes, it'll loose information on the output. Azure used to show the actual affecting prefix in the error message as well, in case it was a list.

I could possibly re-add that, along with adding it to the other providers as well, by returning 2 values from the `isOpenCidr` function. Not sure if it is really relevant though.

Patch:
diff --git a/internal/app/tfsec/checks/aws006.go b/internal/app/tfsec/checks/aws006.go
index 541dbe9c9..41e27c02a 100644
--- a/internal/app/tfsec/checks/aws006.go
+++ b/internal/app/tfsec/checks/aws006.go
@@ -2,8 +2,6 @@ package checks
 
 import (
 	"fmt"
-	"strings"
-
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 
 	"github.com/zclconf/go-cty/cty"
@@ -57,24 +55,13 @@ func init() {
 
 			if cidrBlocksAttr := block.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil {
 
-				if cidrBlocksAttr.Value().IsNull() || cidrBlocksAttr.Value().LengthInt() == 0 {
-					return nil
-				}
-
-				for _, cidr := range cidrBlocksAttr.Value().AsValueSlice() {
-
-					if cidr.Type() != cty.String {
-						continue
-					}
-
-					if strings.HasSuffix(cidr.AsString(), "/0") {
-						return []scanner.Result{
-							check.NewResult(
-								fmt.Sprintf("Resource '%s' defines a fully open ingress security group rule.", block.FullName()),
-								cidrBlocksAttr.Range(),
-								scanner.SeverityWarning,
-							),
-						}
+				if isOpenCidr(cidrBlocksAttr, check.Provider) {
+					return []scanner.Result{
+						check.NewResult(
+							fmt.Sprintf("Resource '%s' defines a fully open ingress security group rule.", block.FullName()),
+							cidrBlocksAttr.Range(),
+							scanner.SeverityWarning,
+						),
 					}
 				}
 
@@ -82,25 +69,14 @@ func init() {
 
 			if ipv6CidrBlocksAttr := block.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr != nil {
 
-				if ipv6CidrBlocksAttr.Value().IsNull() || ipv6CidrBlocksAttr.Value().LengthInt() == 0 {
-					return nil
-				}
-
-				for _, cidr := range ipv6CidrBlocksAttr.Value().AsValueSlice() {
-
-					if cidr.Type() != cty.String {
-						continue
-					}
-
-					if strings.HasSuffix(cidr.AsString(), "/0") {
-						return []scanner.Result{
-							check.NewResultWithValueAnnotation(
-								fmt.Sprintf("Resource '%s' defines a fully open ingress security group rule.", block.FullName()),
-								ipv6CidrBlocksAttr.Range(),
-								ipv6CidrBlocksAttr,
-								scanner.SeverityWarning,
-							),
-						}
+				if isOpenCidr(ipv6CidrBlocksAttr, check.Provider) {
+					return []scanner.Result{
+						check.NewResultWithValueAnnotation(
+							fmt.Sprintf("Resource '%s' defines a fully open ingress security group rule.", block.FullName()),
+							ipv6CidrBlocksAttr.Range(),
+							ipv6CidrBlocksAttr,
+							scanner.SeverityWarning,
+						),
 					}
 				}
 
diff --git a/internal/app/tfsec/checks/aws007.go b/internal/app/tfsec/checks/aws007.go
index cf10b6f16..f061f2f22 100644
--- a/internal/app/tfsec/checks/aws007.go
+++ b/internal/app/tfsec/checks/aws007.go
@@ -2,8 +2,6 @@ package checks
 
 import (
 	"fmt"
-	"strings"
-
 	"github.com/zclconf/go-cty/cty"
 
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
@@ -56,50 +54,30 @@ func init() {
 
 			if cidrBlocksAttr := block.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil {
 
-				if cidrBlocksAttr.Value().IsNull() || cidrBlocksAttr.Value().LengthInt() == 0 {
-					return nil
-				}
-
-				for _, cidr := range cidrBlocksAttr.Value().AsValueSlice() {
-					if cidr.Type() != cty.String {
-						continue
-					}
-					if strings.HasSuffix(cidr.AsString(), "/0") {
-						return []scanner.Result{
-							check.NewResultWithValueAnnotation(
-								fmt.Sprintf("Resource '%s' defines a fully open egress security group rule.", block.FullName()),
-								cidrBlocksAttr.Range(),
-								cidrBlocksAttr,
-								scanner.SeverityWarning,
-							),
-						}
+				if isOpenCidr(cidrBlocksAttr, check.Provider) {
+					return []scanner.Result{
+						check.NewResultWithValueAnnotation(
+							fmt.Sprintf("Resource '%s' defines a fully open egress security group rule.", block.FullName()),
+							cidrBlocksAttr.Range(),
+							cidrBlocksAttr,
+							scanner.SeverityWarning,
+						),
 					}
 				}
-
 			}
 
 			if ipv6CidrBlocksAttr := block.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr != nil {
 
-				if ipv6CidrBlocksAttr.Value().IsNull() || ipv6CidrBlocksAttr.Value().LengthInt() == 0 {
-					return nil
-				}
-
-				for _, cidr := range ipv6CidrBlocksAttr.Value().AsValueSlice() {
-					if cidr.Type() != cty.String {
-						continue
-					}
-					if strings.HasSuffix(cidr.AsString(), "/0") {
-						return []scanner.Result{
-							check.NewResultWithValueAnnotation(
-								fmt.Sprintf("Resource '%s' defines a fully open egress security group rule.", block.FullName()),
-								ipv6CidrBlocksAttr.Range(),
-								ipv6CidrBlocksAttr,
-								scanner.SeverityWarning,
-							),
-						}
+				if isOpenCidr(ipv6CidrBlocksAttr, check.Provider) {
+					return []scanner.Result{
+						check.NewResultWithValueAnnotation(
+							fmt.Sprintf("Resource '%s' defines a fully open egress security group rule.", block.FullName()),
+							ipv6CidrBlocksAttr.Range(),
+							ipv6CidrBlocksAttr,
+							scanner.SeverityWarning,
+						),
 					}
 				}
-
 			}
 
 			return nil
diff --git a/internal/app/tfsec/checks/aws008.go b/internal/app/tfsec/checks/aws008.go
index 7c2f5949b..f898e9fa8 100644
--- a/internal/app/tfsec/checks/aws008.go
+++ b/internal/app/tfsec/checks/aws008.go
@@ -2,10 +2,6 @@ package checks
 
 import (
 	"fmt"
-	"strings"
-
-	"github.com/zclconf/go-cty/cty"
-
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
@@ -53,41 +49,27 @@ func init() {
 			for _, directionBlock := range block.GetBlocks("ingress") {
 				if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil {
 
-					if cidrBlocksAttr.Value().IsNull() || cidrBlocksAttr.Value().LengthInt() == 0 {
-						return nil
-					}
-
-					for _, cidr := range cidrBlocksAttr.Value().AsValueSlice() {
-						if cidr.Type() != cty.String {
-							continue
-						}
-						if strings.HasSuffix(cidr.AsString(), "/0") {
-							results = append(results,
-								check.NewResult(
-									fmt.Sprintf("Resource '%s' defines a fully open ingress security group.", block.FullName()),
-									cidrBlocksAttr.Range(),
-									scanner.SeverityWarning,
-								),
-							)
-						}
+					if isOpenCidr(cidrBlocksAttr, check.Provider) {
+						results = append(results,
+							check.NewResult(
+								fmt.Sprintf("Resource '%s' defines a fully open ingress security group.", block.FullName()),
+								cidrBlocksAttr.Range(),
+								scanner.SeverityWarning,
+							),
+						)
 					}
 				}
-				if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr != nil {
 
-					if cidrBlocksAttr.Value().IsNull() || cidrBlocksAttr.Value().LengthInt() == 0 {
-						return nil
-					}
+				if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr != nil {
 
-					for _, cidr := range cidrBlocksAttr.Value().AsValueSlice() {
-						if strings.HasSuffix(cidr.AsString(), "/0") {
-							results = append(results,
-								check.NewResult(
-									fmt.Sprintf("Resource '%s' defines a fully open ingress security group.", block.FullName()),
-									cidrBlocksAttr.Range(),
-									scanner.SeverityWarning,
-								),
-							)
-						}
+					if isOpenCidr(cidrBlocksAttr, check.Provider) {
+						results = append(results,
+							check.NewResult(
+								fmt.Sprintf("Resource '%s' defines a fully open ingress security group.", block.FullName()),
+								cidrBlocksAttr.Range(),
+								scanner.SeverityWarning,
+							),
+						)
 					}
 				}
 			}
diff --git a/internal/app/tfsec/checks/aws009.go b/internal/app/tfsec/checks/aws009.go
index e4f75083d..f4676b82d 100644
--- a/internal/app/tfsec/checks/aws009.go
+++ b/internal/app/tfsec/checks/aws009.go
@@ -2,8 +2,6 @@ package checks
 
 import (
 	"fmt"
-	"strings"
-
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 )
@@ -50,40 +48,29 @@ func init() {
 			for _, directionBlock := range block.GetBlocks("egress") {
 				if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil {
 
-					if cidrBlocksAttr.Value().IsNull() || cidrBlocksAttr.Value().LengthInt() == 0 {
-						return nil
-					}
-
-					for _, cidr := range cidrBlocksAttr.Value().AsValueSlice() {
-						if strings.HasSuffix(cidr.AsString(), "/0") {
-							results = append(results,
-								check.NewResultWithValueAnnotation(
-									fmt.Sprintf("Resource '%s' defines a fully open egress security group.", block.FullName()),
-									cidrBlocksAttr.Range(),
-									cidrBlocksAttr,
-									scanner.SeverityWarning,
-								),
-							)
-						}
+					if isOpenCidr(cidrBlocksAttr, check.Provider) {
+						results = append(results,
+							check.NewResultWithValueAnnotation(
+								fmt.Sprintf("Resource '%s' defines a fully open egress security group.", block.FullName()),
+								cidrBlocksAttr.Range(),
+								cidrBlocksAttr,
+								scanner.SeverityWarning,
+							),
+						)
 					}
 				}
-				if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr != nil {
 
-					if cidrBlocksAttr.Value().IsNull() || cidrBlocksAttr.Value().LengthInt() == 0 {
-						return nil
-					}
+				if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr != nil {
 
-					for _, cidr := range cidrBlocksAttr.Value().AsValueSlice() {
-						if strings.HasSuffix(cidr.AsString(), "/0") {
-							results = append(results,
-								check.NewResultWithValueAnnotation(
-									fmt.Sprintf("Resource '%s' defines a fully open egress security group.", block.FullName()),
-									cidrBlocksAttr.Range(),
-									cidrBlocksAttr,
-									scanner.SeverityWarning,
-								),
-							)
-						}
+					if isOpenCidr(cidrBlocksAttr, check.Provider) {
+						results = append(results,
+							check.NewResultWithValueAnnotation(
+								fmt.Sprintf("Resource '%s' defines a fully open egress security group.", block.FullName()),
+								cidrBlocksAttr.Range(),
+								cidrBlocksAttr,
+								scanner.SeverityWarning,
+							),
+						)
 					}
 				}
 			}
diff --git a/internal/app/tfsec/checks/azu001.go b/internal/app/tfsec/checks/azu001.go
index 25b18f22d..caa4fe12e 100644
--- a/internal/app/tfsec/checks/azu001.go
+++ b/internal/app/tfsec/checks/azu001.go
@@ -56,7 +56,7 @@ func init() {
 			}
 
 			if prefixAttr := block.GetAttribute("source_address_prefix"); prefixAttr != nil && prefixAttr.Type() == cty.String {
-				if strings.HasSuffix(prefixAttr.Value().AsString(), "/0") || prefixAttr.Value().AsString() == "*" {
+				if isOpenCidr(prefixAttr, check.Provider) {
 					if accessAttr := block.GetAttribute("access"); accessAttr != nil && accessAttr.Value().AsString() == "Allow" {
 						return []scanner.Result{
 							check.NewResultWithValueAnnotation(
@@ -77,21 +77,18 @@ func init() {
 			var results []scanner.Result
 
 			if prefixesAttr := block.GetAttribute("source_address_prefixes"); prefixesAttr != nil && prefixesAttr.Value().LengthInt() > 0 {
-				for _, prefix := range prefixesAttr.Value().AsValueSlice() {
-					if strings.HasSuffix(prefix.AsString(), "/0") || prefix.AsString() == "*" {
-						if accessAttr := block.GetAttribute("access"); accessAttr != nil && accessAttr.Value().AsString() == "Allow" {
-							results = append(results,
-								check.NewResultWithValueAnnotation(
-									fmt.Sprintf("Resource '%s' defines a fully open %s security group rule.", block.FullName(), prefix.AsString()),
-									prefixesAttr.Range(),
-									prefixesAttr,
-									scanner.SeverityWarning,
-								),
-							)
-						}
+				if isOpenCidr(prefixesAttr, check.Provider) {
+					if accessAttr := block.GetAttribute("access"); accessAttr != nil && accessAttr.Value().AsString() == "Allow" {
+						results = append(results,
+							check.NewResultWithValueAnnotation(
+								fmt.Sprintf("Resource '%s' defines a fully open security group rule.", block.FullName()),
+								prefixesAttr.Range(),
+								prefixesAttr,
+								scanner.SeverityWarning,
+							),
+						)
 					}
 				}
-
 			}
 
 			return results
diff --git a/internal/app/tfsec/checks/azu002.go b/internal/app/tfsec/checks/azu002.go
index 9d03da4dc..2f2b8b48c 100644
--- a/internal/app/tfsec/checks/azu002.go
+++ b/internal/app/tfsec/checks/azu002.go
@@ -54,7 +54,7 @@ func init() {
 			}
 
 			if prefixAttr := block.GetAttribute("destination_address_prefix"); prefixAttr != nil && prefixAttr.Type() == cty.String {
-				if strings.HasSuffix(prefixAttr.Value().AsString(), "/0") || prefixAttr.Value().AsString() == "*" {
+				if isOpenCidr(prefixAttr, check.Provider) {
 					if accessAttr := block.GetAttribute("access"); accessAttr != nil && accessAttr.Value().AsString() == "Allow" {
 						return []scanner.Result{
 							check.NewResultWithValueAnnotation(
@@ -75,21 +75,18 @@ func init() {
 			var results []scanner.Result
 
 			if prefixesAttr := block.GetAttribute("destination_address_prefixes"); prefixesAttr != nil && prefixesAttr.Value().LengthInt() > 0 {
-				for _, prefix := range prefixesAttr.Value().AsValueSlice() {
-					if strings.HasSuffix(prefix.AsString(), "/0") || prefix.AsString() == "*" {
-						if accessAttr := block.GetAttribute("access"); accessAttr != nil && accessAttr.Value().AsString() == "Allow" {
-							results = append(results,
-								check.NewResultWithValueAnnotation(
-									fmt.Sprintf("Resource '%s' defines a fully open %s security group rule.", block.FullName(), prefix.AsString()),
-									prefixesAttr.Range(),
-									prefixesAttr,
-									scanner.SeverityWarning,
-								),
-							)
-						}
+				if isOpenCidr(prefixesAttr, check.Provider) {
+					if accessAttr := block.GetAttribute("access"); accessAttr != nil && accessAttr.Value().AsString() == "Allow" {
+						results = append(results,
+							check.NewResultWithValueAnnotation(
+								fmt.Sprintf("Resource '%s' defines a fully open security group rule.", block.FullName()),
+								prefixesAttr.Range(),
+								prefixesAttr,
+								scanner.SeverityWarning,
+							),
+						)
 					}
 				}
-
 			}
 
 			return results
diff --git a/internal/app/tfsec/checks/gcp003.go b/internal/app/tfsec/checks/gcp003.go
index 48738a33b..c3da982a3 100644
--- a/internal/app/tfsec/checks/gcp003.go
+++ b/internal/app/tfsec/checks/gcp003.go
@@ -2,8 +2,6 @@ package checks
 
 import (
 	"fmt"
-	"strings"
-
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
@@ -45,23 +43,15 @@ func init() {
 		CheckFunc: func(check *scanner.Check, block *parser.Block, _ *scanner.Context) []scanner.Result {
 
 			if sourceRanges := block.GetAttribute("source_ranges"); sourceRanges != nil {
-
-				if sourceRanges.Value().LengthInt() == 0 {
-					return nil
-				}
-
-				for _, cidr := range sourceRanges.Value().AsValueSlice() {
-					if strings.HasSuffix(cidr.AsString(), "/0") {
-						return []scanner.Result{
-							check.NewResult(
-								fmt.Sprintf("Resource '%s' defines a fully open inbound firewall rule.", block.FullName()),
-								sourceRanges.Range(),
-								scanner.SeverityWarning,
-							),
-						}
+				if isOpenCidr(sourceRanges, check.Provider) {
+					return []scanner.Result{
+						check.NewResult(
+							fmt.Sprintf("Resource '%s' defines a fully open inbound firewall rule.", block.FullName()),
+							sourceRanges.Range(),
+							scanner.SeverityWarning,
+						),
 					}
 				}
-
 			}
 
 			return nil
diff --git a/internal/app/tfsec/checks/gcp004.go b/internal/app/tfsec/checks/gcp004.go
index 5cdf241de..3f38cc68c 100644
--- a/internal/app/tfsec/checks/gcp004.go
+++ b/internal/app/tfsec/checks/gcp004.go
@@ -2,8 +2,6 @@ package checks
 
 import (
 	"fmt"
-	"strings"
-
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 )
@@ -45,22 +43,15 @@ func init() {
 
 			if destinationRanges := block.GetAttribute("destination_ranges"); destinationRanges != nil {
 
-				if destinationRanges.Value().LengthInt() == 0 {
-					return nil
-				}
-
-				for _, cidr := range destinationRanges.Value().AsValueSlice() {
-					if strings.HasSuffix(cidr.AsString(), "/0") {
-						return []scanner.Result{
-							check.NewResult(
-								fmt.Sprintf("Resource '%s' defines a fully open outbound firewall rule.", block.FullName()),
-								destinationRanges.Range(),
-								scanner.SeverityWarning,
-							),
-						}
+				if isOpenCidr(destinationRanges, check.Provider) {
+					return []scanner.Result{
+						check.NewResult(
+							fmt.Sprintf("Resource '%s' defines a fully open outbound firewall rule.", block.FullName()),
+							destinationRanges.Range(),
+							scanner.SeverityWarning,
+						),
 					}
 				}
-
 			}
 
 			return nil
diff --git a/internal/app/tfsec/checks/utils.go b/internal/app/tfsec/checks/utils.go
index 7404d8410..518646fca 100644
--- a/internal/app/tfsec/checks/utils.go
+++ b/internal/app/tfsec/checks/utils.go
@@ -2,7 +2,9 @@ package checks
 
 import (
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 	"github.com/zclconf/go-cty/cty"
+	"strings"
 )
 
 // isBooleanOrStringTrue returns true if the attribute is a boolean and is
@@ -17,3 +19,30 @@ func isBooleanOrStringTrue(val *parser.Attribute) bool {
 		return false
 	}
 }
+
+// isOpenCidr returns true if given attribute is an open CIDR block
+func isOpenCidr(attr *parser.Attribute, provider scanner.RuleProvider) bool {
+	if attr.Value().IsNull() {
+		return false
+	}
+
+	var cidrList []cty.Value
+	if attr.Type() == cty.String {
+		cidrList = []cty.Value{attr.Value()}
+	} else {
+		cidrList = attr.Value().AsValueSlice()
+	}
+
+	for _, cidr := range cidrList {
+		if cidr.Type() != cty.String {
+			continue
+		}
+
+		cidrStr := cidr.AsString()
+		if strings.HasSuffix(cidrStr, "/0") || cidrStr == "*" {
+			return true
+		}
+	}
+
+	return false
+}


Test patch:
diff --git a/internal/app/tfsec/checks/utils_test.go b/internal/app/tfsec/checks/utils_test.go
index 4728c3e0f..c86b6e609 100644
--- a/internal/app/tfsec/checks/utils_test.go
+++ b/internal/app/tfsec/checks/utils_test.go
@@ -1,6 +1,7 @@
 package checks
 
 import (
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 	"testing"
 
 	hcl "github.com/hashicorp/hcl/v2"
@@ -53,3 +54,115 @@ func Test_isBooleanOrStringTrue(t *testing.T) {
 		}
 	}
 }
+
+func Test_isOpenCidr(t *testing.T) {
+	var tests = []struct {
+		val      *parser.Attribute
+		rawExpr  string
+		provider scanner.RuleProvider
+		result   bool
+	}{
+		{
+			rawExpr:  `["0.0.0.0/0"]`,
+			provider: scanner.AWSProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `["1.2.3.4/0"]`,
+			provider: scanner.AWSProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `["2620:0:2d0:200::7/0"]`,
+			provider: scanner.AWSProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `["::/0"]`,
+			provider: scanner.AWSProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `["1.2.3.5/32"]`,
+			provider: scanner.AWSProvider,
+			result:   false,
+		},
+		{
+			rawExpr:  `["10.0.0.0/16"]`,
+			provider: scanner.AWSProvider,
+			result:   false,
+		},
+		{
+			rawExpr:  `["2620:0:2d0:200::7/32"]`,
+			provider: scanner.AWSProvider,
+			result:   false,
+		},
+		{
+			rawExpr:  `["172.16.32.0/20", "172.16.16.0/20", "172.16.0.0/20"]`,
+			provider: scanner.AWSProvider,
+			result:   false,
+		},
+		{
+			rawExpr:  `["172.16.32.0/20", "172.16.16.0/20", "172.16.0.0/20", "0.0.0.0/0"]`,
+			provider: scanner.AWSProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `["*"]`,
+			provider: scanner.AWSProvider,
+			result:   true,
+		},
+
+		// Azure
+		{
+			rawExpr:  `["10.0.0.0/16"]`,
+			provider: scanner.AzureProvider,
+			result:   false,
+		},
+		{
+			rawExpr:  `["10.0.0.0/0"]`,
+			provider: scanner.AzureProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `["*"]`,
+			provider: scanner.AzureProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `"*"`,
+			provider: scanner.AzureProvider,
+			result:   true,
+		},
+
+		// GCP
+		{
+			rawExpr:  `["10.0.0.0/16"]`,
+			provider: scanner.GCPProvider,
+			result:   false,
+		},
+		{
+			rawExpr:  `["10.0.0.0/0"]`,
+			provider: scanner.GCPProvider,
+			result:   true,
+		},
+		{
+			rawExpr:  `["*"]`,
+			provider: scanner.GCPProvider,
+			result:   true,
+		},
+	}
+
+	for _, test := range tests {
+		expr, _ := hclsyntax.ParseExpression([]byte(test.rawExpr), "", hcl.Pos{0, 0, 0})
+		attr := parser.NewAttribute(
+			&hclsyntax.Attribute{
+				Expr: expr,
+			},
+			nil,
+		)
+		if result := isOpenCidr(attr, test.provider); result != test.result {
+			t.Errorf("expected %v got %v\n", test.result, result)
+		}
+	}
+}