Repository: aquasecurity/tfsec
Pull request #1002 (2021-08-06 12:00:30)

Add more GKE rules


Patch:
diff --git a/internal/app/tfsec/cidr/cidr.go b/internal/app/tfsec/cidr/cidr.go
index dd3af7801..67f8051f7 100644
--- a/internal/app/tfsec/cidr/cidr.go
+++ b/internal/app/tfsec/cidr/cidr.go
@@ -7,7 +7,7 @@ import (
 	"github.com/zclconf/go-cty/cty"
 )
 
-func IsOpen(attr block.Attribute) bool {
+func IsAttributeOpen(attr block.Attribute) bool {
 	if attr.IsNil() || attr.Value().IsNull() {
 		return false
 	}
@@ -29,10 +29,14 @@ func IsOpen(attr block.Attribute) bool {
 		}
 
 		cidrStr := cidr.AsString()
-		if strings.HasSuffix(cidrStr, "/0") || cidrStr == "*" {
+		if IsOpen(cidrStr) {
 			return true
 		}
 	}
 
 	return false
 }
+
+func IsOpen(cidrStr string) bool {
+	return strings.HasSuffix(cidrStr, "/0") || cidrStr == "*"
+}
diff --git a/internal/app/tfsec/rules/aws/eks/no_public_cluster_access_to_cidr_rule.go b/internal/app/tfsec/rules/aws/eks/no_public_cluster_access_to_cidr_rule.go
index 0509340e5..903e39818 100644
--- a/internal/app/tfsec/rules/aws/eks/no_public_cluster_access_to_cidr_rule.go
+++ b/internal/app/tfsec/rules/aws/eks/no_public_cluster_access_to_cidr_rule.go
@@ -79,7 +79,7 @@ resource "aws_eks_cluster" "good_example" {
 					WithDescription("Resource '%s' uses the default public access cidr of 0.0.0.0/0", resourceBlock.FullName()).
 					WithBlock(vpcConfig)
 
-			} else if cidr.IsOpen(publicAccessCidrsAttr) {
+			} else if cidr.IsAttributeOpen(publicAccessCidrsAttr) {
 				set.AddResult().
 					WithDescription("Resource '%s' has public access cidr explicitly set to wide open", resourceBlock.FullName()).
 					WithAttribute(publicAccessCidrsAttr)
diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go
index d363e9973..d6f27a01c 100644
--- a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go
+++ b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go
@@ -56,7 +56,7 @@ resource "aws_security_group" "good_example" {
 			for _, directionBlock := range resourceBlock.GetBlocks("egress") {
 				if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() {
 
-					if cidr.IsOpen(cidrBlocksAttr) {
+					if cidr.IsAttributeOpen(cidrBlocksAttr) {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open egress security group.", resourceBlock.FullName()).
 							WithAttribute(cidrBlocksAttr)
@@ -65,7 +65,7 @@ resource "aws_security_group" "good_example" {
 
 				if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr.IsNotNil() {
 
-					if cidr.IsOpen(cidrBlocksAttr) {
+					if cidr.IsAttributeOpen(cidrBlocksAttr) {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open egress security group.", resourceBlock.FullName()).
 							WithAttribute(cidrBlocksAttr)
diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go
index b2eb95ec0..b67d76909 100644
--- a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go
+++ b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go
@@ -58,7 +58,7 @@ resource "aws_security_group_rule" "good_example" {
 
 			if cidrBlocksAttr := resourceBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() {
 
-				if cidr.IsOpen(cidrBlocksAttr) {
+				if cidr.IsAttributeOpen(cidrBlocksAttr) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open egress security group rule.", resourceBlock.FullName()).
 						WithAttribute(cidrBlocksAttr)
@@ -67,7 +67,7 @@ resource "aws_security_group_rule" "good_example" {
 
 			if ipv6CidrBlocksAttr := resourceBlock.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr.IsNotNil() {
 
-				if cidr.IsOpen(ipv6CidrBlocksAttr) {
+				if cidr.IsAttributeOpen(ipv6CidrBlocksAttr) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open egress security group rule.", resourceBlock.FullName()).
 						WithAttribute(ipv6CidrBlocksAttr)
diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go
index fc9ef51fd..c4c30b64a 100644
--- a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go
+++ b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go
@@ -75,7 +75,7 @@ resource "aws_network_acl_rule" "good_example" {
 
 			if cidrBlockAttr := resourceBlock.GetAttribute("cidr_block"); cidrBlockAttr.IsNotNil() {
 
-				if cidr.IsOpen(cidrBlockAttr) {
+				if cidr.IsAttributeOpen(cidrBlockAttr) {
 					if protoAttr.Value().AsString() == "all" || protoAttr.Value().AsString() == "-1" {
 						return
 					} else {
@@ -88,7 +88,7 @@ resource "aws_network_acl_rule" "good_example" {
 
 			if ipv6CidrBlockAttr := resourceBlock.GetAttribute("ipv6_cidr_block"); ipv6CidrBlockAttr.IsNotNil() {
 
-				if cidr.IsOpen(ipv6CidrBlockAttr) {
+				if cidr.IsAttributeOpen(ipv6CidrBlockAttr) {
 					if protoAttr.Value().AsString() == "all" || protoAttr.Value().AsString() == "-1" {
 						return
 					} else {
diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go
index 5c9c5d82d..e7b9c1464 100644
--- a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go
+++ b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go
@@ -56,7 +56,7 @@ resource "aws_security_group" "good_example" {
 			for _, directionBlock := range resourceBlock.GetBlocks("ingress") {
 				if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() {
 
-					if cidr.IsOpen(cidrBlocksAttr) {
+					if cidr.IsAttributeOpen(cidrBlocksAttr) {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open ingress security group.", resourceBlock.FullName()).
 							WithAttribute(cidrBlocksAttr)
@@ -65,7 +65,7 @@ resource "aws_security_group" "good_example" {
 
 				if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr.IsNotNil() {
 
-					if cidr.IsOpen(cidrBlocksAttr) {
+					if cidr.IsAttributeOpen(cidrBlocksAttr) {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open ingress security group.", resourceBlock.FullName())
 					}
diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go
index 47926961f..88107ef14 100644
--- a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go
+++ b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go
@@ -58,7 +58,7 @@ resource "aws_security_group_rule" "good_example" {
 			}
 
 			if cidrBlocksAttr := resourceBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() {
-				if cidr.IsOpen(cidrBlocksAttr) {
+				if cidr.IsAttributeOpen(cidrBlocksAttr) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open ingress security group rule.", resourceBlock.FullName()).
 						WithAttribute(cidrBlocksAttr)
@@ -66,7 +66,7 @@ resource "aws_security_group_rule" "good_example" {
 			}
 
 			if ipv6CidrBlocksAttr := resourceBlock.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr.IsNotNil() {
-				if cidr.IsOpen(ipv6CidrBlocksAttr) {
+				if cidr.IsAttributeOpen(ipv6CidrBlocksAttr) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open ingress security group rule.", resourceBlock.FullName()).
 						WithAttribute(ipv6CidrBlocksAttr)
diff --git a/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go b/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go
index 145b47742..b4f8dc08d 100644
--- a/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go
+++ b/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go
@@ -64,7 +64,7 @@ resource "azurerm_network_security_rule" "good_example" {
 			}
 
 			if prefixAttr := resourceBlock.GetAttribute("destination_address_prefix"); prefixAttr.IsString() {
-				if cidr.IsOpen(prefixAttr) {
+				if cidr.IsAttributeOpen(prefixAttr) {
 					if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.IsNotNil() && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open %s network security group rule.", resourceBlock.FullName(), strings.ToLower(directionAttr.Value().AsString())).
@@ -74,7 +74,7 @@ resource "azurerm_network_security_rule" "good_example" {
 			}
 
 			if prefixesAttr := resourceBlock.GetAttribute("destination_address_prefixes"); !prefixesAttr.IsEmpty() {
-				if cidr.IsOpen(prefixesAttr) {
+				if cidr.IsAttributeOpen(prefixesAttr) {
 					if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.IsNotNil() && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open security group rule.", resourceBlock.FullName()).
diff --git a/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go b/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go
index 75fa6d52a..03d4d3377 100644
--- a/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go
+++ b/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go
@@ -62,7 +62,7 @@ resource "azurerm_network_security_rule" "good_example" {
 			}
 
 			if prefixAttr := resourceBlock.GetAttribute("source_address_prefix"); prefixAttr.IsString() {
-				if cidr.IsOpen(prefixAttr) {
+				if cidr.IsAttributeOpen(prefixAttr) {
 					if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.Equals("ALLOW", block.IgnoreCase) {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open %s network security group rule.", resourceBlock.FullName(), strings.ToLower(directionAttr.Value().AsString())).
@@ -72,7 +72,7 @@ resource "azurerm_network_security_rule" "good_example" {
 			}
 
 			if prefixesAttr := resourceBlock.GetAttribute("source_address_prefixes"); !prefixesAttr.IsEmpty() {
-				if cidr.IsOpen(prefixesAttr) {
+				if cidr.IsAttributeOpen(prefixesAttr) {
 					if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.Equals("ALLOW", block.IgnoreCase) {
 						set.AddResult().
 							WithDescription("Resource '%s' defines a fully open security group rule.", resourceBlock.FullName()).
diff --git a/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go b/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go
index 356f05a81..0c17107a8 100644
--- a/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go
+++ b/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go
@@ -67,7 +67,7 @@ resource "digitalocean_firewall" "good_example" {
 					continue
 				}
 				destinationAddressesAttr := inboundRuleBlock.GetAttribute("destination_addresses")
-				if cidr.IsOpen(destinationAddressesAttr) {
+				if cidr.IsAttributeOpen(destinationAddressesAttr) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open outbound_rule.", resourceBlock.FullName()).
 						WithAttribute(destinationAddressesAttr)
diff --git a/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go b/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go
index 27bc913f6..abbc6d6f0 100644
--- a/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go
+++ b/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go
@@ -68,7 +68,7 @@ resource "digitalocean_firewall" "good_example" {
 					continue
 				}
 				sourceAddressesAttr := inboundRuleBlock.GetAttribute("source_addresses")
-				if cidr.IsOpen(sourceAddressesAttr) {
+				if cidr.IsAttributeOpen(sourceAddressesAttr) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open inbound_rule.", resourceBlock.FullName()).
 						WithAttribute(sourceAddressesAttr)
diff --git a/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go b/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go
index 88a4f1044..4229da8d6 100644
--- a/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go
+++ b/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go
@@ -52,7 +52,7 @@ resource "google_compute_firewall" "good_example" {
 
 			if destinationRanges := resourceBlock.GetAttribute("destination_ranges"); destinationRanges.IsNotNil() {
 
-				if cidr.IsOpen(destinationRanges) {
+				if cidr.IsAttributeOpen(destinationRanges) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open outbound firewall rule.", resourceBlock.FullName()).
 						WithAttribute(destinationRanges)
diff --git a/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go b/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go
index c1ca650b1..fa87ee88a 100644
--- a/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go
+++ b/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go
@@ -52,7 +52,7 @@ resource "google_compute_firewall" "good_example" {
 		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
 
 			if sourceRanges := resourceBlock.GetAttribute("source_ranges"); sourceRanges.IsNotNil() {
-				if cidr.IsOpen(sourceRanges) {
+				if cidr.IsAttributeOpen(sourceRanges) {
 					set.AddResult().
 						WithDescription("Resource '%s' defines a fully open inbound firewall rule.", resourceBlock.FullName()).
 						WithAttribute(sourceRanges)
diff --git a/internal/app/tfsec/rules/google/gke/enable_ip_aliasing_rule.go b/internal/app/tfsec/rules/google/gke/enable_ip_aliasing_rule.go
new file mode 100644
index 000000000..dd8bf76c8
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_ip_aliasing_rule.go
@@ -0,0 +1,116 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "enable-ip-aliasing",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Clusters should have IP aliasing enabled",
+			Explanation: `IP aliasing allows the reuse of public IPs internally, removing the need for a NAT gateway.`,
+			Impact:      "Nodes need a NAT gateway to access local services",
+			Resolution:  "Enable IP aliasing",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "bad_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "good_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  ip_allocation_policy = {}
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#ip_allocation_policy",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if ipAllocationPolicyAttr := resourceBlock.GetAttribute("ip_allocation_policy"); ipAllocationPolicyAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' has IP aliasing disabled.", resourceBlock.FullName())
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_master_networks_rule.go b/internal/app/tfsec/rules/google/gke/enable_master_networks_rule.go
new file mode 100644
index 000000000..d563ecc76
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_master_networks_rule.go
@@ -0,0 +1,121 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "enable-master-networks",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Master authorized networks should be configured on GKE clusters",
+			Explanation: `Enabling authorized networks means you can restrict master access to a fixed set of CIDR ranges`,
+			Impact:      "Unrestricted network access to the master",
+			Resolution:  "Enable master authorized networks",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "primary" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "primary" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  master_authorized_networks_config = [{
+    cidr_blocks = [{
+      cidr_block = "10.10.128.0/24"
+      display_name = "internal"
+    }]
+  }]
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if resourceBlock.MissingChild("master_authorized_networks_config") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have master authorized networks enabled.", resourceBlock)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_network_policy_rule.go b/internal/app/tfsec/rules/google/gke/enable_network_policy_rule.go
new file mode 100644
index 000000000..23f0d5c72
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_network_policy_rule.go
@@ -0,0 +1,125 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:       provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "enable-network-policy",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Network Policy should be enabled on GKE clusters",
+			Explanation: `Enabling a network policy allows the segregation of network traffic by namespace`,
+			Impact:      "Unrestricted inter-cluster communication",
+			Resolution:  "Enable network policy",
+			BadExample: []string{  `
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "bad_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  network_policy {
+    enabled = false
+  }
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{ `
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "good_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  network_policy {
+    enabled = true
+  }
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#enabled",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.Medium, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if enabledAttr := resourceBlock.GetBlock("network_policy").GetAttribute("enabled"); enabledAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for network_policy.enabled", resourceBlock.FullName())
+			} else if enabledAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have network_policy.enabled set to true", resourceBlock.FullName()).
+					WithAttribute(enabledAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_private_cluster_rule.go b/internal/app/tfsec/rules/google/gke/enable_private_cluster_rule.go
new file mode 100644
index 000000000..b4dd226cb
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_private_cluster_rule.go
@@ -0,0 +1,125 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:       provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "enable-private-cluster",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Clusters should be set to private",
+			Explanation: `Enabling private nodes on a cluster ensures the nodes are only available internally as they will only be assigned internal addresses.`,
+			Impact:      "Nodes may be exposed to the public internet",
+			Resolution:  "Enable private cluster",
+			BadExample: []string{  `
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "bad_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  private_cluster_config {
+    enable_private_nodes = false
+  }
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{ `
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "good_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  private_cluster_config {
+    enable_private_nodes = true
+  }
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#enable_private_nodes",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.Medium, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if enablePrivateNodesAttr := resourceBlock.GetBlock("private_cluster_config").GetAttribute("enable_private_nodes"); enablePrivateNodesAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for private_cluster_config.enable_private_nodes", resourceBlock.FullName())
+			} else if enablePrivateNodesAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have private_cluster_config.enable_private_nodes set to true", resourceBlock.FullName()).
+					WithAttribute(enablePrivateNodesAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_stackdriver_logging_rule.go b/internal/app/tfsec/rules/google/gke/enable_stackdriver_logging_rule.go
new file mode 100644
index 000000000..947e0a71a
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_stackdriver_logging_rule.go
@@ -0,0 +1,118 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "enable-stackdriver-logging",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Stackdriver Logging should be enabled",
+			Explanation: `StackDriver logging provides a useful interface to all of stdout/stderr for each container and should be enabled for moitoring, debugging, etc.`,
+			Impact:      "Visibility will be reduced",
+			Resolution:  "Enable StackDriver logging",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "bad_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  logging_service = "logging.googleapis.com"
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "good_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  logging_service = "logging.googleapis.com/kubernetes"
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#logging_service",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if loggingServiceAttr := resourceBlock.GetAttribute("logging_service"); loggingServiceAttr.NotEqual("logging.googleapis.com/kubernetes") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logging_service set to logging.googleapis.com/kubernetes", resourceBlock.FullName()).
+					WithAttribute(loggingServiceAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_stackdriver_monitoring_rule.go b/internal/app/tfsec/rules/google/gke/enable_stackdriver_monitoring_rule.go
new file mode 100644
index 000000000..9d3adff68
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_stackdriver_monitoring_rule.go
@@ -0,0 +1,118 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "enable-stackdriver-monitoring",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Stackdriver Monitoring should be enabled",
+			Explanation: `StackDriver monitoring aggregates logs, events, and metrics from your Kubernetes environment on GKE to help you understand your application's behavior in production. `,
+			Impact:      "Visibility will be reduced",
+			Resolution:  "Enable StackDriver monitoring",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "bad_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  monitoring_service = "monitoring.googleapis.com"
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "good_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  monitoring_service = "monitoring.googleapis.com/kubernetes"
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#monitoring_service",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if monitoringServiceAttr := resourceBlock.GetAttribute("monitoring_service"); monitoringServiceAttr.NotEqual("monitoring.googleapis.com/kubernetes") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have monitoring_service set to monitoring.googleapis.com/kubernetes", resourceBlock.FullName()).
+					WithAttribute(monitoringServiceAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/no_public_control_plane_rule.go b/internal/app/tfsec/rules/google/gke/no_public_control_plane_rule.go
new file mode 100644
index 000000000..84b52c4db
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/no_public_control_plane_rule.go
@@ -0,0 +1,157 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/cidr"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "no-public-control-plane",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "GKE Control Plane should not be publicly accessible",
+			Explanation: `The GKE control plane is exposed to the public internet by default. `,
+			Impact:      "GKE control plane exposed to public internet",
+			Resolution:  "Use private nodes and master authorised networks to prevent exposure",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "primary" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  master_authorized_networks_config = [{
+    cidr_blocks = [{
+      cidr_block = "0.0.0.0/0"
+      display_name = "external"
+    }]
+  }]
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "primary" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  master_authorized_networks_config = [{
+    cidr_blocks = [{
+      cidr_block = "10.10.128.0/24"
+      display_name = "internal"
+    }]
+  }]
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			config := resourceBlock.GetAttribute("master_authorized_networks_config")
+			if config.IsNil() {
+				return
+			}
+			config.Each(func(key cty.Value, val cty.Value) {
+				if !val.Type().IsObjectType() {
+					return
+				}
+				m := val.AsValueMap()
+				blocks, ok := m["cidr_blocks"]
+				if !ok {
+					return
+				}
+				for _, block := range blocks.AsValueSlice() {
+					if !block.Type().IsObjectType() {
+						continue
+					}
+					blockObj := block.AsValueMap()
+					cidrBlock, ok := blockObj["cidr_block"]
+					if !ok {
+						continue
+					}
+					if cidrBlock.Type() != cty.String {
+						continue
+					}
+					if cidr.IsOpen(cidrBlock.AsString()) {
+						set.AddResult().
+							WithDescription("Resource '%s' defines a cluster with an internet exposed control plane.", resourceBlock).
+							WithAttribute(config)
+					}
+				}
+			})
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/use_client_cert_auth_rule.go b/internal/app/tfsec/rules/google/gke/use_client_cert_auth_rule.go
new file mode 100644
index 000000000..099835134
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/use_client_cert_auth_rule.go
@@ -0,0 +1,129 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:       provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "use-client-cert-auth",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Clusters should use client certificates for authentication",
+			Explanation: `Client certificates are the most secure and recommended method of authentication.`,
+			Impact:      "Less secure authentication method in use",
+			Resolution:  "Use client certificates for authentication",
+			BadExample: []string{  `
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "bad_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  master_auth {
+    client_certificate_config {
+      issue_client_certificate = false
+    }
+  }
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{ `
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "good_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  master_auth {
+    client_certificate_config {
+      issue_client_certificate = true
+    }
+  }
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#issue_client_certificate",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.High, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if issueClientCertificateAttr := resourceBlock.GetBlock("master_auth").GetBlock("client_certificate_config").GetAttribute("issue_client_certificate"); issueClientCertificateAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for master_auth.client_certificate_config.issue_client_certificate", resourceBlock.FullName())
+			} else if issueClientCertificateAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have master_auth.client_certificate_config.issue_client_certificate set to true", resourceBlock.FullName()).
+					WithAttribute(issueClientCertificateAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/gke/use_cluster_labels_rule.go b/internal/app/tfsec/rules/google/gke/use_cluster_labels_rule.go
new file mode 100644
index 000000000..ce2d360d1
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/use_cluster_labels_rule.go
@@ -0,0 +1,118 @@
+package gke
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/pkg/provider"
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/rule"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "gke",
+		ShortCode: "use-cluster-labels",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Clusters should be configured with Labels",
+			Explanation: `Labels make it easier to manage assets and differentiate between clusters and environments, allowing the mapping of computational resources to the wider organisational structure.`,
+			Impact:      "Asset management can be limited/more difficult",
+			Resolution:  "Set cluster resource labels",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "bad_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service-account-id"
+  display_name = "Service Account"
+}
+
+resource "google_container_cluster" "good_example" {
+  name     = "my-gke-cluster"
+  location = "us-central1"
+
+  # We can't create a cluster with no node pool defined, but we want to only use
+  # separately managed node pools. So we create the smallest possible default
+  # node pool and immediately delete it.
+  remove_default_node_pool = true
+  initial_node_count       = 1
+  resource_labels = {
+    "env" = "staging"
+  }
+}
+
+resource "google_container_node_pool" "primary_preemptible_nodes" {
+  name       = "my-node-pool"
+  location   = "us-central1"
+  cluster    = google_container_cluster.primary.name
+  node_count = 1
+
+  node_config {
+    preemptible  = true
+    machine_type = "e2-medium"
+
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    service_account = google_service_account.default.email
+    oauth_scopes    = [
+      "https://www.googleapis.com/auth/cloud-platform"
+    ]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#resource_labels",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_container_cluster",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if resourceLabelsAttr := resourceBlock.GetAttribute("resource_labels"); resourceLabelsAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' does not use resource_labels", resourceBlock.FullName())
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/sql/no_public_access_rule.go b/internal/app/tfsec/rules/google/sql/no_public_access_rule.go
index 2e37c712a..4e44d16c0 100644
--- a/internal/app/tfsec/rules/google/sql/no_public_access_rule.go
+++ b/internal/app/tfsec/rules/google/sql/no_public_access_rule.go
@@ -94,7 +94,7 @@ resource "google_sql_database_instance" "postgres" {
 			}
 
 			for _, authorizedNetworkBlock := range ipConfigBlock.GetBlocks("authorized_networks") {
-				if cidrAttr := authorizedNetworkBlock.GetAttribute("value"); cidr.IsOpen(cidrAttr) {
+				if cidrAttr := authorizedNetworkBlock.GetAttribute("value"); cidr.IsAttributeOpen(cidrAttr) {
 					set.AddResult().
 						WithDescription("Resource '%s' authorizes access from the public internet", resourceBlock.FullName()).
 						WithAttribute(cidrAttr)
diff --git a/internal/app/tfsec/rules/kubernetes/network/no_public_egress_rule.go b/internal/app/tfsec/rules/kubernetes/network/no_public_egress_rule.go
index 45e87f70e..f2653567a 100644
--- a/internal/app/tfsec/rules/kubernetes/network/no_public_egress_rule.go
+++ b/internal/app/tfsec/rules/kubernetes/network/no_public_egress_rule.go
@@ -171,7 +171,7 @@ resource "kubernetes_network_policy" "good_example" {
 
 			for _, to := range egressBlock.GetBlocks("to") {
 				if cidrAttr := to.GetBlock("ip_block").GetAttribute("cidr"); cidrAttr.IsString() {
-					if cidr.IsOpen(cidrAttr) {
+					if cidr.IsAttributeOpen(cidrAttr) {
 						set.AddResult().
 							WithDescription("Resource '%s' allows egress traffic to the internet", resourceBlock.FullName()).
 							WithAttribute(cidrAttr)
diff --git a/internal/app/tfsec/rules/kubernetes/network/no_public_ingress_rule.go b/internal/app/tfsec/rules/kubernetes/network/no_public_ingress_rule.go
index 5c5e82a78..d086dfa97 100644
--- a/internal/app/tfsec/rules/kubernetes/network/no_public_ingress_rule.go
+++ b/internal/app/tfsec/rules/kubernetes/network/no_public_ingress_rule.go
@@ -170,7 +170,7 @@ resource "kubernetes_network_policy" "good_example" {
 
 			for _, from := range ingressBlock.GetBlocks("from") {
 				if cidrAttr := from.GetBlock("ip_block").GetAttribute("cidr"); cidrAttr.IsString() {
-					if cidr.IsOpen(cidrAttr) {
+					if cidr.IsAttributeOpen(cidrAttr) {
 						set.AddResult().
 							WithDescription("Resource '%s' allows ingress traffic from the internet", resourceBlock.FullName()).
 							WithAttribute(cidrAttr)
diff --git a/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go b/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go
index a5640c907..0f636fd6f 100644
--- a/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go
+++ b/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go
@@ -74,7 +74,7 @@ resource "openstack_fw_rule_v1" "rule_1" {
 						fmt.Sprintf("Resource '%s' defines a firewall rule with no restriction on destination IP", resourceBlock),
 					).
 					WithAttribute(destinationIP)
-			} else if cidr.IsOpen(destinationIP) {
+			} else if cidr.IsAttributeOpen(destinationIP) {
 				set.AddResult().
 					WithDescription("Resource '%s' defines a firewall rule with a public destination CIDR", resourceBlock).
 					WithAttribute(destinationIP)
@@ -84,7 +84,7 @@ resource "openstack_fw_rule_v1" "rule_1" {
 				set.AddResult().
 					WithDescription("Resource '%s' defines a firewall rule with no restriction on source IP", resourceBlock).
 					WithAttribute(sourceIP)
-			} else if cidr.IsOpen(sourceIP) {
+			} else if cidr.IsAttributeOpen(sourceIP) {
 				set.AddResult().
 					WithDescription("Resource '%s' defines a firewall rule with a public source CIDR", resourceBlock).
 					WithAttribute(sourceIP)


Test patch:
diff --git a/internal/app/tfsec/rules/google/gke/enable_ip_aliasing_rule_test.go b/internal/app/tfsec/rules/google/gke/enable_ip_aliasing_rule_test.go
new file mode 100644
index 000000000..eee6133b6
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_ip_aliasing_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleEnableIpAliasing_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-ip-aliasing"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleEnableIpAliasing_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-ip-aliasing"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_master_networks_rule_test.go b/internal/app/tfsec/rules/google/gke/enable_master_networks_rule_test.go
new file mode 100644
index 000000000..fd8172e35
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_master_networks_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleEnableMasterNetworks_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-master-networks"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleEnableMasterNetworks_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-master-networks"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_network_policy_rule_test.go b/internal/app/tfsec/rules/google/gke/enable_network_policy_rule_test.go
new file mode 100644
index 000000000..ab5742e9b
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_network_policy_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleEnableNetworkPolicy_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-network-policy"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleEnableNetworkPolicy_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-network-policy"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_private_cluster_rule_test.go b/internal/app/tfsec/rules/google/gke/enable_private_cluster_rule_test.go
new file mode 100644
index 000000000..e2e1b8507
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_private_cluster_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleEnablePrivateCluster_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-private-cluster"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleEnablePrivateCluster_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-private-cluster"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_stackdriver_logging_rule_test.go b/internal/app/tfsec/rules/google/gke/enable_stackdriver_logging_rule_test.go
new file mode 100644
index 000000000..ce596eacf
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_stackdriver_logging_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleEnableStackdriverLogging_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-stackdriver-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleEnableStackdriverLogging_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-stackdriver-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/enable_stackdriver_monitoring_rule_test.go b/internal/app/tfsec/rules/google/gke/enable_stackdriver_monitoring_rule_test.go
new file mode 100644
index 000000000..c7ccee5a2
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/enable_stackdriver_monitoring_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleEnableStackdriverMonitoring_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-stackdriver-monitoring"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleEnableStackdriverMonitoring_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-enable-stackdriver-monitoring"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/no_public_control_plane_rule_test.go b/internal/app/tfsec/rules/google/gke/no_public_control_plane_rule_test.go
new file mode 100644
index 000000000..61be8f2c5
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/no_public_control_plane_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleNoPublicControlPlane_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-no-public-control-plane"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleNoPublicControlPlane_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-no-public-control-plane"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/use_client_cert_auth_rule_test.go b/internal/app/tfsec/rules/google/gke/use_client_cert_auth_rule_test.go
new file mode 100644
index 000000000..326752658
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/use_client_cert_auth_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleUseClientCertAuth_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-use-client-cert-auth"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleUseClientCertAuth_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-use-client-cert-auth"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}
diff --git a/internal/app/tfsec/rules/google/gke/use_cluster_labels_rule_test.go b/internal/app/tfsec/rules/google/gke/use_cluster_labels_rule_test.go
new file mode 100644
index 000000000..ed0a69d2d
--- /dev/null
+++ b/internal/app/tfsec/rules/google/gke/use_cluster_labels_rule_test.go
@@ -0,0 +1,53 @@
+package gke
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleUseClusterLabels_FailureExamples(t *testing.T) {
+	expectedCode := "google-gke-use-cluster-labels"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, badExample := range rule.Documentation.BadExample {
+		t.Logf("Running bad example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(badExample) == "" {
+			t.Fatalf("bad example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (bad) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(badExample, t)
+		testutil.AssertCheckCode(t, rule.ID(), "", results)
+	}
+}
+
+func Test_GoogleUseClusterLabels_SuccessExamples(t *testing.T) {
+	expectedCode := "google-gke-use-cluster-labels"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.Fatalf("Rule not found: %s", expectedCode)
+	}
+	for i, example := range rule.Documentation.GoodExample {
+		t.Logf("Running good example for '%s' #%d", expectedCode, i+1)
+		if strings.TrimSpace(example) == "" {
+			t.Fatalf("good example code not provided for %s", rule.ID())
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				t.Fatalf("Scan (good) failed: %s", err)
+			}
+		}()
+		results := testutil.ScanHCL(example, t)
+		testutil.AssertCheckCode(t, "", rule.ID(), results)
+	}
+}