Repository: aquasecurity/tfsec
Pull request #996 (2021-08-04 19:05:51)

Add lots more gcp rules


Patch:
diff --git a/cmd/tfsec-skeleton/examples/mutate.go b/cmd/tfsec-skeleton/examples/mutate.go
index 38f429e59..0a32af9af 100644
--- a/cmd/tfsec-skeleton/examples/mutate.go
+++ b/cmd/tfsec-skeleton/examples/mutate.go
@@ -38,6 +38,9 @@ func (m *machine) processAttributeLine(line string) string {
 	name := strings.TrimSpace(parts[0])
 	if strings.Join(append(m.stack, name), ".") == m.dotPath {
 		line = fmt.Sprintf("%s= %s", parts[0], sprintHCL(m.value))
+		if m.value == nil {
+			line = ""
+		}
 		m.found = true
 	}
 	if strings.Contains(line, "<<") {
@@ -61,7 +64,7 @@ func (m *machine) processBlockOpening(line string) string {
 }
 
 func (m *machine) processBlockClosing(line string) string {
-	if m.inPath && !m.found {
+	if m.inPath && !m.found && m.value != nil {
 		// we were in the right place - did we find our attr? if not, we need to add it
 		inject := expandPathAndValue(strings.TrimPrefix(m.dotPath, strings.Join(m.stack, ".")+"."), m.value, m.tabStr, len(m.stack))
 		m.output = append(m.output, inject)
diff --git a/cmd/tfsec-skeleton/generation.go b/cmd/tfsec-skeleton/generation.go
index de35bc38d..70a2559d1 100644
--- a/cmd/tfsec-skeleton/generation.go
+++ b/cmd/tfsec-skeleton/generation.go
@@ -46,13 +46,12 @@ func verifyPathDoesNotExist(checkPath string, forceOverwrite bool) error {
 		if err != nil {
 			return err
 		}
-		if strings.Contains(string(file), "// generator-locked") {
-			return fmt.Errorf("file [%s] is locked for update, remove comment to overwrite", checkPath)
-		}
-
 		if !forceOverwrite {
 			return fmt.Errorf("file [%s] already exists so not creating check", checkPath)
 		}
+		if strings.Contains(string(file), "// generator-locked") {
+			return fmt.Errorf("file [%s] is locked for update, remove comment to overwrite", checkPath)
+		}
 	}
 	return nil
 }
diff --git a/cmd/tfsec-skeleton/main.go b/cmd/tfsec-skeleton/main.go
index efebb13ac..4c46fdb00 100644
--- a/cmd/tfsec-skeleton/main.go
+++ b/cmd/tfsec-skeleton/main.go
@@ -43,15 +43,18 @@ var rootCmd = &cobra.Command{
 			inputs = []*Input{input}
 		}
 
+		var count int
 		for _, input := range inputs {
 			deref := *input
 			if err := writeRuleFromInput(&deref, forceOverwrite); err != nil {
-				return err
+				fmt.Println(err)
+				continue
 			}
+			count++
 			fmt.Printf("Added %s-%s-%s...\n", input.Provider, input.Service, input.ShortCode)
 		}
 
-		terminal.PrintSuccessf("\nAdded %d new rule(s).\n", len(inputs))
+		terminal.PrintSuccessf("\nAdded %d new rule(s).\n", count)
 		return nil
 	},
 }
diff --git a/cmd/tfsec-skeleton/requirements/attributes.go b/cmd/tfsec-skeleton/requirements/attributes.go
index 451b6763b..653fd28af 100644
--- a/cmd/tfsec-skeleton/requirements/attributes.go
+++ b/cmd/tfsec-skeleton/requirements/attributes.go
@@ -39,8 +39,6 @@ func NewAttributeRequirement(blockType string, blockLabel string, dotPath string
 
 func (a *attributeBase) makeGoodValue() interface{} {
 	switch a.comparison {
-	case ComparisonEquals:
-		return a.value
 	case ComparisonNotEquals, ComparisonNotAnyOf:
 		return flipValue(a.value)
 	case ComparisonAnyOf:
@@ -68,8 +66,12 @@ func (a *attributeBase) makeGoodValue() interface{} {
 			return []string{}
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
+	case ComparisonDefined:
+		return "something"
+	case ComparisonNotDefined:
+		return nil
 	default:
-		panic(fmt.Sprintf("comparison '%s' is not supported", a.comparison))
+		return a.value
 	}
 }
 
@@ -91,8 +93,6 @@ func (a *attributeBase) makeBadValue() interface{} {
 	switch a.comparison {
 	case ComparisonEquals, ComparisonAnyOf:
 		return flipValue(a.value)
-	case ComparisonNotEquals:
-		return a.value
 	case ComparisonNotAnyOf:
 		if strs, ok := a.value.([]string); ok && len(strs) > 0 {
 			return strs[0]
@@ -118,8 +118,45 @@ func (a *attributeBase) makeBadValue() interface{} {
 			return []string{s}
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
+	case ComparisonDefined:
+		return nil
+	case ComparisonNotDefined:
+		return "something"
 	default:
-		panic(fmt.Sprintf("comparison'%s' is not supported", a.comparison))
+		return a.value
+	}
+}
+
+func (a *attributeBase) getMessageForComparison() string {
+
+	switch a.comparison {
+	case ComparisonEquals:
+		return fmt.Sprintf("Resource '%%s' does not have %s set to %v", a.dotPath, a.value)
+	case ComparisonNotEquals:
+		return fmt.Sprintf("Resource '%%s' has %s set to %v", a.dotPath, a.value)
+	case ComparisonAnyOf:
+		return fmt.Sprintf("Resource '%%s' does not have %s set to one of %s", a.dotPath, a.value)
+	case ComparisonNotAnyOf:
+		return fmt.Sprintf("Resource '%%s' has %s set to one of %s", a.dotPath, a.value)
+	case ComparisonGreaterThan:
+		return fmt.Sprintf("Resource '%%s' does not have %s set to greater than %d", a.dotPath, a.value)
+	case ComparisonLessThan:
+		return fmt.Sprintf("Resource '%%s' does not have %s set to less than %d", a.dotPath, a.value)
+	case ComparisonGreaterThanOrEqual:
+		return fmt.Sprintf("Resource '%%s' does not have %s set to greater than or equal to %d", a.dotPath, a.value)
+	case ComparisonLessThanOrEqual:
+		return fmt.Sprintf("Resource '%%s' does not have %s set to greater than or equal to %d", a.dotPath, a.value)
+	case ComparisonContains:
+		return fmt.Sprintf("Resource '%%s' should have %s in %s", a.value, a.dotPath)
+	case ComparisonNotContains:
+		return fmt.Sprintf("Resource '%%s' has %s in %s", a.value, a.dotPath)
+	case ComparisonDefined:
+		return fmt.Sprintf("Resource '%%s' does not set %s", a.dotPath)
+	case ComparisonNotDefined:
+		return fmt.Sprintf("Resource '%%s' sets %s", a.dotPath)
+
+	default:
+		panic(fmt.Sprintf("comparison '%s' is not supported", a.comparison))
 	}
 }
 
@@ -164,33 +201,7 @@ func (a *attributeBase) GenerateRuleCode() string {
 			} else if `, attrVarName, a.dotPath)
 	}
 
-	var messageTemplate string
-
-	switch a.comparison {
-	case ComparisonEquals:
-		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to %v", a.dotPath, a.value)
-	case ComparisonNotEquals:
-		messageTemplate = fmt.Sprintf("Resource '%%s' has %s set to %v", a.dotPath, a.value)
-	case ComparisonAnyOf:
-		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to one of %s", a.dotPath, a.value)
-	case ComparisonNotAnyOf:
-		messageTemplate = fmt.Sprintf("Resource '%%s' has %s set to one of %s", a.dotPath, a.value)
-	case ComparisonGreaterThan:
-		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to greater than %d", a.dotPath, a.value)
-	case ComparisonLessThan:
-		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to less than %d", a.dotPath, a.value)
-	case ComparisonGreaterThanOrEqual:
-		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to greater than or equal to %d", a.dotPath, a.value)
-	case ComparisonLessThanOrEqual:
-		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to greater than or equal to %d", a.dotPath, a.value)
-	case ComparisonContains:
-		messageTemplate = fmt.Sprintf("Resource '%%s' should have %s in %s", a.value, a.dotPath)
-	case ComparisonNotContains:
-		messageTemplate = fmt.Sprintf("Resource '%%s' has %s in %s", a.value, a.dotPath)
-
-	default:
-		panic(fmt.Sprintf("comparison '%s' is not supported", a.comparison))
-	}
+	messageTemplate := a.getMessageForComparison()
 
 	code += fmt.Sprintf(`%s.%s {
 				set.AddResult().
diff --git a/cmd/tfsec-skeleton/requirements/comparison.go b/cmd/tfsec-skeleton/requirements/comparison.go
index 40cf3b8cf..2263c602a 100644
--- a/cmd/tfsec-skeleton/requirements/comparison.go
+++ b/cmd/tfsec-skeleton/requirements/comparison.go
@@ -14,6 +14,8 @@ const (
 	ComparisonLessThanOrEqual    Comparison = "lessthanorequal"
 	ComparisonContains           Comparison = "contains"
 	ComparisonNotContains        Comparison = "notcontains"
+	ComparisonDefined            Comparison = "defined"
+	ComparisonNotDefined         Comparison = "notdefined"
 )
 
 func (c Comparison) Reverse() Comparison {
@@ -38,6 +40,10 @@ func (c Comparison) Reverse() Comparison {
 		return ComparisonContains
 	case ComparisonContains:
 		return ComparisonNotContains
+	case ComparisonDefined:
+		return ComparisonNotDefined
+	case ComparisonNotDefined:
+		return ComparisonDefined
 	default:
 		return ComparisonNone
 	}
diff --git a/cmd/tfsec-skeleton/requirements/requirements.go b/cmd/tfsec-skeleton/requirements/requirements.go
index b46bc89ac..5a12098cb 100644
--- a/cmd/tfsec-skeleton/requirements/requirements.go
+++ b/cmd/tfsec-skeleton/requirements/requirements.go
@@ -108,6 +108,13 @@ func snakeToCamel(input string) string {
 
 func buildComparisonForValue(value interface{}, comparison Comparison) string {
 
+	switch comparison {
+	case ComparisonDefined:
+		return `IsResolvable()`
+	case ComparisonNotDefined:
+		return `IsNotResolvable()`
+	}
+
 	switch t := value.(type) {
 	case []string:
 		return buildStringSliceComparison(t, comparison)
diff --git a/internal/app/tfsec/block/attribute.go b/internal/app/tfsec/block/attribute.go
index 23081cb9b..63a02a393 100644
--- a/internal/app/tfsec/block/attribute.go
+++ b/internal/app/tfsec/block/attribute.go
@@ -36,6 +36,7 @@ type Attribute interface {
 	IsResourceBlockReference(resourceType string) bool
 	ReferencesBlock(b Block) bool
 	IsResolvable() bool
+	IsNotResolvable() bool
 	IsString() bool
 	IsNumber() bool
 	IsBool() bool
diff --git a/internal/app/tfsec/block/hclattribute.go b/internal/app/tfsec/block/hclattribute.go
index 6deb98c68..1487d039f 100644
--- a/internal/app/tfsec/block/hclattribute.go
+++ b/internal/app/tfsec/block/hclattribute.go
@@ -35,7 +35,11 @@ func (attr *HCLAttribute) IsResolvable() bool {
 	if attr == nil {
 		return false
 	}
-	return attr.Value() != cty.NilVal
+	return attr.Value() != cty.NilVal && attr.Value().IsKnown()
+}
+
+func (attr *HCLAttribute) IsNotResolvable() bool {
+	return !attr.IsResolvable()
 }
 
 func (attr *HCLAttribute) Type() cty.Type {
@@ -477,7 +481,7 @@ func (attr *HCLAttribute) MapValue(mapKey string) cty.Value {
 			}
 		}
 	}
-	return cty.StringVal("")
+	return cty.NilVal
 }
 
 func (attr *HCLAttribute) LessThan(checkValue interface{}) bool {
diff --git a/internal/app/tfsec/rules/google/bigquery/no_public_access_rule.go b/internal/app/tfsec/rules/google/bigquery/no_public_access_rule.go
new file mode 100644
index 000000000..fd4d090c1
--- /dev/null
+++ b/internal/app/tfsec/rules/google/bigquery/no_public_access_rule.go
@@ -0,0 +1,97 @@
+package bigquery
+
+// 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:   "bigquery",
+		ShortCode: "no-public-access",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "BigQuery datasets should only be accessible within the organisation",
+			Explanation: `Using 'allAuthenticatedUsers' provides any GCP user - even those outside of your organisation - access to your BigQuery dataset.`,
+			Impact:      "Exposure of sensitive data to the public iniernet",
+			Resolution:  "Configure access permissions with higher granularity",
+			BadExample: []string{`
+resource "google_bigquery_dataset" "bad_example" {
+  dataset_id                  = "example_dataset"
+  friendly_name               = "test"
+  description                 = "This is a test description"
+  location                    = "EU"
+  default_table_expiration_ms = 3600000
+
+  labels = {
+    env = "default"
+  }
+
+  access {
+    role          = "OWNER"
+    special_group = "allAuthenticatedUsers"
+  }
+
+  access {
+    role   = "READER"
+    domain = "hashicorp.com"
+  }
+}
+
+`},
+			GoodExample: []string{`
+resource "google_bigquery_dataset" "good_example" {
+  dataset_id                  = "example_dataset"
+  friendly_name               = "test"
+  description                 = "This is a test description"
+  location                    = "EU"
+  default_table_expiration_ms = 3600000
+
+  labels = {
+    env = "default"
+  }
+
+  access {
+    role          = "OWNER"
+    user_by_email = google_service_account.bqowner.email
+  }
+
+  access {
+    role   = "READER"
+    domain = "hashicorp.com"
+  }
+}
+
+resource "google_service_account" "bqowner" {
+  account_id = "bqowner"
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_dataset#special_group",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_bigquery_dataset",
+		},
+		DefaultSeverity: severity.Critical,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if specialGroupAttr := resourceBlock.GetBlock("access").GetAttribute("special_group"); specialGroupAttr.Equals("allAuthenticatedUsers") {
+				set.AddResult().
+					WithDescription("Resource '%s' has access.special_group set to allAuthenticatedUsers", resourceBlock.FullName()).
+					WithAttribute(specialGroupAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/disk_encryption_customer_key_rule.go b/internal/app/tfsec/rules/google/compute/disk_encryption_customer_key_rule.go
new file mode 100644
index 000000000..12911b4bb
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/disk_encryption_customer_key_rule.go
@@ -0,0 +1,76 @@
+package compute
+
+// 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:   "compute",
+		ShortCode: "disk-encryption-customer-key",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Disks should be encrypted with Customer Supplied Encryption Keys",
+			Explanation: `Using unmanaged keys makes rotation and general management difficult.`,
+			Impact:      "Using unmanaged keys does not allow for proper management",
+			Resolution:  "Use managed keys ",
+			BadExample: []string{  `
+resource "google_compute_disk" "bad_example" {
+  name  = "test-disk"
+  type  = "pd-ssd"
+  zone  = "us-central1-a"
+  image = "debian-9-stretch-v20200805"
+  labels = {
+    environment = "dev"
+  }
+  physical_block_size_bytes = 4096
+}
+`},
+			GoodExample: []string{ `
+resource "google_compute_disk" "good_example" {
+  name  = "test-disk"
+  type  = "pd-ssd"
+  zone  = "us-central1-a"
+  image = "debian-9-stretch-v20200805"
+  labels = {
+    environment = "dev"
+  }
+  physical_block_size_bytes = 4096
+  disk_encryption_key {
+    kms_key_self_link = "something"
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_disk#kms_key_self_link",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"google_compute_disk",
+		},
+		DefaultSeverity: severity.Low, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if kmsKeySelfLinkAttr := resourceBlock.GetBlock("disk_encryption_key").GetAttribute("kms_key_self_link"); kmsKeySelfLinkAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for disk_encryption_key.kms_key_self_link", resourceBlock.FullName())
+			} else if kmsKeySelfLinkAttr.IsNotResolvable() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not set disk_encryption_key.kms_key_self_link", resourceBlock.FullName()).
+					WithAttribute(kmsKeySelfLinkAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/enable_vpc_flow_logs_rule.go b/internal/app/tfsec/rules/google/compute/enable_vpc_flow_logs_rule.go
new file mode 100644
index 000000000..f25e43032
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/enable_vpc_flow_logs_rule.go
@@ -0,0 +1,85 @@
+package compute
+
+// 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:   "compute",
+		ShortCode: "enable-vpc-flow-logs",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "VPC flow logs should be enabled for all subnets",
+			Explanation: `VPC flow logs record information about all traffic, which is a vital tool in reviewing anomalous traffic.`,
+			Impact:      "Limited auditing capability and awareness",
+			Resolution:  "Enable VPC flow logs",
+			BadExample: []string{`
+resource "google_compute_subnetwork" "bad_example" {
+  name          = "test-subnetwork"
+  ip_cidr_range = "10.2.0.0/16"
+  region        = "us-central1"
+  network       = google_compute_network.custom-test.id
+  secondary_ip_range {
+    range_name    = "tf-test-secondary-range-update1"
+    ip_cidr_range = "192.168.10.0/24"
+  }
+  enable_flow_logs = false
+}
+
+resource "google_compute_network" "custom-test" {
+  name                    = "test-network"
+  auto_create_subnetworks = false
+}
+`},
+			GoodExample: []string{`
+resource "google_compute_subnetwork" "good_example" {
+  name          = "test-subnetwork"
+  ip_cidr_range = "10.2.0.0/16"
+  region        = "us-central1"
+  network       = google_compute_network.custom-test.id
+  secondary_ip_range {
+    range_name    = "tf-test-secondary-range-update1"
+    ip_cidr_range = "192.168.10.0/24"
+  }
+  enable_flow_logs = true
+}
+
+resource "google_compute_network" "custom-test" {
+  name                    = "test-network"
+  auto_create_subnetworks = false
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_subnetwork#enable_flow_logs",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_compute_subnetwork",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if enableFlowLogsAttr := resourceBlock.GetAttribute("enable_flow_logs"); enableFlowLogsAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for enable_flow_logs", resourceBlock.FullName())
+			} else if enableFlowLogsAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have enable_flow_logs set to true", resourceBlock.FullName()).
+					WithAttribute(enableFlowLogsAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/no_plaintext_disk_keys_rule.go b/internal/app/tfsec/rules/google/compute/no_plaintext_disk_keys_rule.go
new file mode 100644
index 000000000..877852cf6
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_plaintext_disk_keys_rule.go
@@ -0,0 +1,73 @@
+package compute
+
+// 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:   "compute",
+		ShortCode: "no-plaintext-disk-keys",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Disk encryption keys should not be provided in plaintext",
+			Explanation: `Providing your encryption key in plaintext format means anyone with access to the source code also has access to the key.`,
+			Impact:      "Compromise of encryption keys",
+			Resolution:  "Use managed keys or provide the raw key via a secrets manager ",
+			BadExample: []string{`
+resource "google_compute_disk" "bad_example" {
+  name  = "test-disk"
+  type  = "pd-ssd"
+  zone  = "us-central1-a"
+  image = "debian-9-stretch-v20200805"
+  labels = {
+    environment = "dev"
+  }
+  physical_block_size_bytes = 4096
+  disk_encryption_key {
+    raw_key = "something"
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_compute_disk" "good_example" {
+  name  = "test-disk"
+  type  = "pd-ssd"
+  zone  = "us-central1-a"
+  image = "debian-9-stretch-v20200805"
+  labels = {
+    environment = "dev"
+  }
+  physical_block_size_bytes = 4096
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_disk#raw_key",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_compute_disk",
+		},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if rawKeyAttr := resourceBlock.GetBlock("disk_encryption_key").GetAttribute("raw_key"); rawKeyAttr.IsResolvable() {
+				set.AddResult().
+					WithDescription("Resource '%s' sets disk_encryption_key.raw_key", resourceBlock.FullName()).
+					WithAttribute(rawKeyAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/no_plaintext_vm_disk_keys_rule.go b/internal/app/tfsec/rules/google/compute/no_plaintext_vm_disk_keys_rule.go
new file mode 100644
index 000000000..6469d8f23
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_plaintext_vm_disk_keys_rule.go
@@ -0,0 +1,137 @@
+package compute
+
+// 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:   "compute",
+		ShortCode: "no-plaintext-vm-disk-keys",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "VM disk encryption keys should not be provided in plaintext",
+			Explanation: `Providing your encryption key in plaintext format means anyone with access to the source code also has access to the key.`,
+			Impact:      "Compromise of encryption keys",
+			Resolution:  "Use managed keys or provide the raw key via a secrets manager ",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "bad_example" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+    disk_encryption_key_raw = "something"
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    foo = "bar"
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "good_example" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    foo = "bar"
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#disk_encryption_key_raw",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_compute_instance",
+		},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if diskEncryptionKeyRawAttr := resourceBlock.GetBlock("boot_disk").GetAttribute("disk_encryption_key_raw"); diskEncryptionKeyRawAttr.IsResolvable() {
+				set.AddResult().
+					WithDescription("Resource '%s' sets boot_disk.disk_encryption_key_raw", resourceBlock.FullName()).
+					WithAttribute(diskEncryptionKeyRawAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/no_project_wide_ssh_keys_rule.go b/internal/app/tfsec/rules/google/compute/no_project_wide_ssh_keys_rule.go
new file mode 100644
index 000000000..6f472e9db
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_project_wide_ssh_keys_rule.go
@@ -0,0 +1,145 @@
+package compute
+
+// 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"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "compute",
+		ShortCode: "no-project-wide-ssh-keys",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Disable project-wide SSH keys for all instances",
+			Explanation: `Use of project-wide SSH keys means that a compromise of any one of these key pairs can result in all instances being compromised. It is recommended to use instance-level keys.`,
+			Impact:      "Compromise of a single key pair compromises all instances",
+			Resolution:  "Disable project-wide SSH keys",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "default" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    block-project-ssh-keys = false
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "default" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    block-project-ssh-keys = true
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_compute_instance",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			metadataAttr := resourceBlock.GetAttribute("metadata")
+			val := metadataAttr.MapValue("block-project-ssh-keys")
+			if val.Type() == cty.NilType {
+				set.AddResult().
+					WithDescription("Resource'%s' allows the use of project-wide SSH keys by default", resourceBlock)
+				return
+			}
+			if val.Type() == cty.Bool && val.False() {
+				set.AddResult().
+					WithDescription("Resource'%s' explicitly allows the use of project-wide SSH keys by default", resourceBlock).
+					WithAttribute(metadataAttr)
+				return
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/no_serial_port_rule.go b/internal/app/tfsec/rules/google/compute/no_serial_port_rule.go
new file mode 100644
index 000000000..91c8ac98a
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_serial_port_rule.go
@@ -0,0 +1,140 @@
+package compute
+
+// 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"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "compute",
+		ShortCode: "no-serial-port",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Disable serial port connectivity for all instances",
+			Explanation: `When serial port access is enabled, the access is not governed by network security rules meaning the port can be exposed publicly.`,
+			Impact:      "Unrestricted network access to the serial console of the instance",
+			Resolution:  "Disable serial port access",
+			BadExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "default" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    serial-port-enable = true
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "default" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    serial-port-enable = false
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_compute_instance",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			metadataAttr := resourceBlock.GetAttribute("metadata")
+			val := metadataAttr.MapValue("serial-port-enable")
+			if val.Type() == cty.Bool && val.True() {
+				set.AddResult().
+					WithDescription("Resource'%s' explicitly enables serial port", resourceBlock).
+					WithAttribute(metadataAttr)
+				return
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/project_level_oslogin_rule.go b/internal/app/tfsec/rules/google/compute/project_level_oslogin_rule.go
new file mode 100644
index 000000000..89e8a6d0b
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/project_level_oslogin_rule.go
@@ -0,0 +1,69 @@
+package compute
+
+// 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"
+	"github.com/zclconf/go-cty/cty"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.GoogleProvider,
+		Service:   "compute",
+		ShortCode: "project-level-oslogin",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "OS Login should be enabled at project level",
+			Explanation: `OS Login automatically revokes the relevant SSH keys when an IAM user has their access revoked.`,
+			Impact:      "Access via SSH key cannot be revoked automatically when an IAM user is removed.",
+			Resolution:  "Enable OS Login at project level",
+			BadExample: []string{`
+resource "google_compute_project_metadata" "default" {
+  metadata = {
+	enable-oslogin = false
+  }
+}
+`},
+			GoodExample: []string{`
+resource "google_compute_project_metadata" "default" {
+  metadata = {
+    enable-oslogin = true
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_project_metadata#",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_compute_project_metadata",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			metadataAttr := resourceBlock.GetAttribute("metadata")
+			val := metadataAttr.MapValue("enable-oslogin")
+			if val.Type() == cty.NilType {
+				set.AddResult().
+					WithDescription("Resource'%s' has OS Login disabled by default", resourceBlock)
+				return
+			}
+			if val.Type() == cty.Bool && val.False() {
+				set.AddResult().
+					WithDescription("Resource'%s' has OS Login explicitly disabled", resourceBlock).
+					WithAttribute(metadataAttr)
+				return
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/use_secure_tls_policy_rule.go b/internal/app/tfsec/rules/google/compute/use_secure_tls_policy_rule.go
new file mode 100644
index 000000000..c25dfd34f
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/use_secure_tls_policy_rule.go
@@ -0,0 +1,64 @@
+package compute
+
+// 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:   "compute",
+		ShortCode: "use-secure-tls-policy",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "SSL policies should enforce secure versions of TLS",
+			Explanation: `TLS versions prior to 1.2 are outdated and insecure. You should use 1.2 as aminimum version.`,
+			Impact:      "Data in transit is not sufficiently secured",
+			Resolution:  "Enforce a minimum TLS version of 1.2",
+			BadExample: []string{`
+resource "google_compute_ssl_policy" "bad_example" {
+  name    = "production-ssl-policy"
+  profile = "MODERN"
+  min_tls_version = "TLS_1_1"
+}
+
+`},
+			GoodExample: []string{`
+resource "google_compute_ssl_policy" "good_example" {
+  name    = "production-ssl-policy"
+  profile = "MODERN"
+  min_tls_version = "TLS_1_2"
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_ssl_policy#min_tls_version",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"google_compute_ssl_policy",
+		},
+		DefaultSeverity: severity.Critical,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if minTlsVersionAttr := resourceBlock.GetAttribute("min_tls_version"); minTlsVersionAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for min_tls_version", resourceBlock.FullName())
+			} else if minTlsVersionAttr.NotEqual("TLS_1_2") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have min_tls_version set to TLS_1_2", resourceBlock.FullName()).
+					WithAttribute(minTlsVersionAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/compute/vm_disk_encryption_customer_key_rule.go b/internal/app/tfsec/rules/google/compute/vm_disk_encryption_customer_key_rule.go
new file mode 100644
index 000000000..d14c99daf
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/vm_disk_encryption_customer_key_rule.go
@@ -0,0 +1,140 @@
+package compute
+
+// 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:   "compute",
+		ShortCode: "vm-disk-encryption-customer-key",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "VM disks should be encrypted with Customer Supplied Encryption Keys",
+			Explanation: `Using unmanaged keys makes rotation and general management difficult.`,
+			Impact:      "Using unmanaged keys does not allow for proper management",
+			Resolution:  "Use managed keys ",
+			BadExample: []string{  `
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "bad_example" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    foo = "bar"
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			GoodExample: []string{ `
+resource "google_service_account" "default" {
+  account_id   = "service_account_id"
+  display_name = "Service Account"
+}
+
+resource "google_compute_instance" "good_example" {
+  name         = "test"
+  machine_type = "e2-medium"
+  zone         = "us-central1-a"
+
+  tags = ["foo", "bar"]
+
+  boot_disk {
+    initialize_params {
+      image = "debian-cloud/debian-9"
+    }
+    kms_key_self_link = "something"
+  }
+
+  // Local SSD disk
+  scratch_disk {
+    interface = "SCSI"
+  }
+
+  network_interface {
+    network = "default"
+
+    access_config {
+      // Ephemeral IP
+    }
+  }
+
+  metadata = {
+    foo = "bar"
+  }
+
+  metadata_startup_script = "echo hi > /test.txt"
+
+  service_account {
+    # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
+    email  = google_service_account.default.email
+    scopes = ["cloud-platform"]
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#kms_key_self_link",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"google_compute_instance",
+		},
+		DefaultSeverity: severity.Low, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if kmsKeySelfLinkAttr := resourceBlock.GetBlock("boot_disk").GetAttribute("kms_key_self_link"); kmsKeySelfLinkAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for boot_disk.kms_key_self_link", resourceBlock.FullName())
+			} else if kmsKeySelfLinkAttr.IsNotResolvable() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not set boot_disk.kms_key_self_link", resourceBlock.FullName()).
+					WithAttribute(kmsKeySelfLinkAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/project/no_default_network_rule.go b/internal/app/tfsec/rules/google/project/no_default_network_rule.go
new file mode 100644
index 000000000..1a7f70ef3
--- /dev/null
+++ b/internal/app/tfsec/rules/google/project/no_default_network_rule.go
@@ -0,0 +1,65 @@
+package project
+
+// 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:   "project",
+		ShortCode: "no-default-network",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Default network should not be created at project level",
+			Explanation: `The default network which is provided for a project contains multiple insecure firewall rules which allow ingress to the project's infrastructure. Creation of this network should therefore be disabled.`,
+			Impact:      "Exposure of internal infrastructure/services to public internet",
+			Resolution:  "Disable automatic default network creation",
+			BadExample: []string{  `
+resource "google_project" "bad_example" {
+  name       = "My Project"
+  project_id = "your-project-id"
+  org_id     = "1234567"
+  auto_create_network = true
+}
+`},
+			GoodExample: []string{ `
+resource "google_project" "good_example" {
+  name       = "My Project"
+  project_id = "your-project-id"
+  org_id     = "1234567"
+  auto_create_network = false
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project#auto_create_network",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"google_project",
+		},
+		DefaultSeverity: severity.High, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if autoCreateNetworkAttr := resourceBlock.GetAttribute("auto_create_network"); autoCreateNetworkAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for auto_create_network", resourceBlock.FullName())
+			} else if autoCreateNetworkAttr.IsTrue() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have auto_create_network set to false", resourceBlock.FullName()).
+					WithAttribute(autoCreateNetworkAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/init.go b/internal/app/tfsec/rules/init.go
index c05281a8e..20d2aadc6 100644
--- a/internal/app/tfsec/rules/init.go
+++ b/internal/app/tfsec/rules/init.go
@@ -59,9 +59,11 @@ import (
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/digitalocean/spaces"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/general/secrets"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/github/repositories"
+	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/google/bigquery"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/google/compute"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/google/gke"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/google/iam"
+	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/google/project"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/google/sql"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/google/storage"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/kubernetes/network"


Test patch:
diff --git a/internal/app/tfsec/rules/aws/ecr/no_public_access_rule_test.go b/internal/app/tfsec/rules/aws/ecr/no_public_access_rule_test.go
index 487873f96..b6dd66a0b 100644
--- a/internal/app/tfsec/rules/aws/ecr/no_public_access_rule_test.go
+++ b/internal/app/tfsec/rules/aws/ecr/no_public_access_rule_test.go
@@ -13,7 +13,7 @@ func Test_AWSNoPublicAccess_FailureExamples(t *testing.T) {
 
 	rule, err := scanner.GetRuleById(expectedCode)
 	if err != nil {
-		t.FailNow()
+		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)
@@ -35,7 +35,7 @@ func Test_AWSNoPublicAccess_SuccessExamples(t *testing.T) {
 
 	rule, err := scanner.GetRuleById(expectedCode)
 	if err != nil {
-		t.FailNow()
+		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)
diff --git a/internal/app/tfsec/rules/google/bigquery/no_public_access_rule_test.go b/internal/app/tfsec/rules/google/bigquery/no_public_access_rule_test.go
new file mode 100644
index 000000000..5aff7bc4b
--- /dev/null
+++ b/internal/app/tfsec/rules/google/bigquery/no_public_access_rule_test.go
@@ -0,0 +1,53 @@
+package bigquery
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleNoPublicAccess_FailureExamples(t *testing.T) {
+	expectedCode := "google-bigquery-no-public-access"
+
+	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_GoogleNoPublicAccess_SuccessExamples(t *testing.T) {
+	expectedCode := "google-bigquery-no-public-access"
+
+	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/compute/disk_encryption_customer_key_rule_test.go b/internal/app/tfsec/rules/google/compute/disk_encryption_customer_key_rule_test.go
new file mode 100644
index 000000000..5a57643e9
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/disk_encryption_customer_key_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleDiskEncryptionCustomerKey_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-disk-encryption-customer-key"
+
+	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_GoogleDiskEncryptionCustomerKey_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-disk-encryption-customer-key"
+
+	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/compute/enable_vpc_flow_logs_rule_test.go b/internal/app/tfsec/rules/google/compute/enable_vpc_flow_logs_rule_test.go
new file mode 100644
index 000000000..04e486829
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/enable_vpc_flow_logs_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleEnableVpcFlowLogs_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-enable-vpc-flow-logs"
+
+	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_GoogleEnableVpcFlowLogs_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-enable-vpc-flow-logs"
+
+	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/compute/no_plaintext_disk_keys_rule_test.go b/internal/app/tfsec/rules/google/compute/no_plaintext_disk_keys_rule_test.go
new file mode 100644
index 000000000..1bcc0141c
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_plaintext_disk_keys_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleNoPlaintextDiskKeys_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-no-plaintext-disk-keys"
+
+	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_GoogleNoPlaintextDiskKeys_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-no-plaintext-disk-keys"
+
+	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/compute/no_plaintext_vm_disk_keys_rule_test.go b/internal/app/tfsec/rules/google/compute/no_plaintext_vm_disk_keys_rule_test.go
new file mode 100644
index 000000000..e7fcba0af
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_plaintext_vm_disk_keys_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleNoPlaintextVmDiskKeys_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-no-plaintext-vm-disk-keys"
+
+	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_GoogleNoPlaintextVmDiskKeys_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-no-plaintext-vm-disk-keys"
+
+	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/compute/no_project_wide_ssh_keys_rule_test.go b/internal/app/tfsec/rules/google/compute/no_project_wide_ssh_keys_rule_test.go
new file mode 100644
index 000000000..6afdd4561
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_project_wide_ssh_keys_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleNoProjectWideSshKeys_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-no-project-wide-ssh-keys"
+
+	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_GoogleNoProjectWideSshKeys_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-no-project-wide-ssh-keys"
+
+	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/compute/no_serial_port_rule_test.go b/internal/app/tfsec/rules/google/compute/no_serial_port_rule_test.go
new file mode 100644
index 000000000..c97c8e699
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/no_serial_port_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleNoSerialPort_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-no-serial-port"
+
+	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_GoogleNoSerialPort_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-no-serial-port"
+
+	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/compute/project_level_oslogin_rule_test.go b/internal/app/tfsec/rules/google/compute/project_level_oslogin_rule_test.go
new file mode 100644
index 000000000..69eed881e
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/project_level_oslogin_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleProjectLevelOslogin_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-project-level-oslogin"
+
+	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_GoogleProjectLevelOslogin_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-project-level-oslogin"
+
+	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/compute/use_secure_tls_policy_rule_test.go b/internal/app/tfsec/rules/google/compute/use_secure_tls_policy_rule_test.go
new file mode 100644
index 000000000..9e5f9e1b1
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/use_secure_tls_policy_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleUseSecureTlsPolicy_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-use-secure-tls-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_GoogleUseSecureTlsPolicy_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-use-secure-tls-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/compute/vm_disk_encryption_customer_key_rule_test.go b/internal/app/tfsec/rules/google/compute/vm_disk_encryption_customer_key_rule_test.go
new file mode 100644
index 000000000..01fe9bd49
--- /dev/null
+++ b/internal/app/tfsec/rules/google/compute/vm_disk_encryption_customer_key_rule_test.go
@@ -0,0 +1,53 @@
+package compute
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleVmDiskEncryptionCustomerKey_FailureExamples(t *testing.T) {
+	expectedCode := "google-compute-vm-disk-encryption-customer-key"
+
+	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_GoogleVmDiskEncryptionCustomerKey_SuccessExamples(t *testing.T) {
+	expectedCode := "google-compute-vm-disk-encryption-customer-key"
+
+	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/project/no_default_network_rule_test.go b/internal/app/tfsec/rules/google/project/no_default_network_rule_test.go
new file mode 100644
index 000000000..89a5cb395
--- /dev/null
+++ b/internal/app/tfsec/rules/google/project/no_default_network_rule_test.go
@@ -0,0 +1,53 @@
+package project
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GoogleNoDefaultNetwork_FailureExamples(t *testing.T) {
+	expectedCode := "google-project-no-default-network"
+
+	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_GoogleNoDefaultNetwork_SuccessExamples(t *testing.T) {
+	expectedCode := "google-project-no-default-network"
+
+	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)
+	}
+}