Repository: aquasecurity/tfsec
Pull request #931 (2021-07-22 13:35:47)

Add multiple Google Cloud SQL Postgres checks
- Add check for google sql checkpoint logging
- Add check for google sql connection logging
- Add check for google sql disconnection logging
- Add check for google sql postgres lock wait logging
- Add check for google sql postgres lock wait logging
- Add google sql postgres min duration statements check
- Add postgres minimum log severity check


Patch:
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule.go
new file mode 100644
index 000000000..21b052e9b
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule.go
@@ -0,0 +1,100 @@
+package sql
+
+import (
+	"fmt"
+
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+
+	"github.com/aquasecurity/tfsec/pkg/provider"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+
+	"github.com/aquasecurity/tfsec/pkg/rule"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Service:   "sql",
+		ShortCode: "pg-log-checkpoints",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure that logging of checkpoints is enabled.",
+			Explanation: `Logging checkpoints provides useful diagnostic data, which can identify performance issues in an application and potential DoS vectors.`,
+			Impact:      "Insufficient diagnostic data.",
+			Resolution:  "Enable checkpoints logging.",
+			BadExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_checkpoints"
+			value = "off"
+		}
+	}
+}
+			`,
+			GoodExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_checkpoints"
+			value = "on"
+		}
+	}
+}
+			`,
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance",
+				"https://www.postgresql.org/docs/13/runtime-config-logging.html#GUC-LOG-CHECKPOINTS",
+			},
+		},
+		Provider:        provider.GoogleProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"google_sql_database_instance"},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			dbVersionAttr := resourceBlock.GetAttribute("database_version")
+			if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") {
+				return
+			}
+
+			settingsBlock := resourceBlock.GetBlock("settings")
+			if settingsBlock == nil {
+				set.Add(
+					result.New(resourceBlock).
+						WithDescription(fmt.Sprintf("Resource '%s' is not configured to log checkpoints", resourceBlock.FullName())),
+				)
+				return
+			}
+
+			for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") {
+				if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_checkpoints") {
+					if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() {
+						if valueAttr.Value().AsString() == "off" {
+							set.Add(
+								result.New(resourceBlock).
+									WithDescription(fmt.Sprintf("Resource '%s' is configured not to log checkpoints", resourceBlock.FullName())),
+							)
+						}
+						return
+					}
+				}
+			}
+
+			set.Add(
+				result.New(resourceBlock).
+					WithDescription(fmt.Sprintf("Resource '%s' is not configured to log checkpoints", resourceBlock.FullName())),
+			)
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_connections_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_connections_rule.go
new file mode 100644
index 000000000..f15a26081
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_connections_rule.go
@@ -0,0 +1,100 @@
+package sql
+
+import (
+	"fmt"
+
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+
+	"github.com/aquasecurity/tfsec/pkg/provider"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+
+	"github.com/aquasecurity/tfsec/pkg/rule"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Service:   "sql",
+		ShortCode: "pg-log-connections",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure that logging of connections is enabled.",
+			Explanation: `Logging connections provides useful diagnostic data such as session length, which can identify performance issues in an application and potential DoS vectors.`,
+			Impact:      "Insufficient diagnostic data.",
+			Resolution:  "Enable connection logging.",
+			BadExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_connections"
+			value = "off"
+		}
+	}
+}
+			`,
+			GoodExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_connections"
+			value = "on"
+		}
+	}
+}
+			`,
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance",
+				"https://www.postgresql.org/docs/13/runtime-config-logging.html#GUC-LOG-CONNECTIONS",
+			},
+		},
+		Provider:        provider.GoogleProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"google_sql_database_instance"},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			dbVersionAttr := resourceBlock.GetAttribute("database_version")
+			if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") {
+				return
+			}
+
+			settingsBlock := resourceBlock.GetBlock("settings")
+			if settingsBlock == nil {
+				set.Add(
+					result.New(resourceBlock).
+						WithDescription(fmt.Sprintf("Resource '%s' is not configured to log connections", resourceBlock.FullName())),
+				)
+				return
+			}
+
+			for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") {
+				if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_connections") {
+					if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() {
+						if valueAttr.Value().AsString() == "off" {
+							set.Add(
+								result.New(resourceBlock).
+									WithDescription(fmt.Sprintf("Resource '%s' is configured not to log connections", resourceBlock.FullName())),
+							)
+						}
+						return
+					}
+				}
+			}
+
+			set.Add(
+				result.New(resourceBlock).
+					WithDescription(fmt.Sprintf("Resource '%s' is not configured to log connections", resourceBlock.FullName())),
+			)
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule.go
new file mode 100644
index 000000000..440c43aaf
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule.go
@@ -0,0 +1,100 @@
+package sql
+
+import (
+	"fmt"
+
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+
+	"github.com/aquasecurity/tfsec/pkg/provider"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+
+	"github.com/aquasecurity/tfsec/pkg/rule"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Service:   "sql",
+		ShortCode: "pg-log-disconnections",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure that logging of disconnections is enabled.",
+			Explanation: `Logging disconnections provides useful diagnostic data such as session length, which can identify performance issues in an application and potential DoS vectors.`,
+			Impact:      "Insufficient diagnostic data.",
+			Resolution:  "Enable disconnection logging.",
+			BadExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_disconnections"
+			value = "off"
+		}
+	}
+}
+			`,
+			GoodExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_disconnections"
+			value = "on"
+		}
+	}
+}
+			`,
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance",
+				"https://www.postgresql.org/docs/13/runtime-config-logging.html#GUC-LOG-DISCONNECTIONS",
+			},
+		},
+		Provider:        provider.GoogleProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"google_sql_database_instance"},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			dbVersionAttr := resourceBlock.GetAttribute("database_version")
+			if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") {
+				return
+			}
+
+			settingsBlock := resourceBlock.GetBlock("settings")
+			if settingsBlock == nil {
+				set.Add(
+					result.New(resourceBlock).
+						WithDescription(fmt.Sprintf("Resource '%s' is not configured to log disconnections", resourceBlock.FullName())),
+				)
+				return
+			}
+
+			for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") {
+				if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_disconnections") {
+					if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() {
+						if valueAttr.Value().AsString() == "off" {
+							set.Add(
+								result.New(resourceBlock).
+									WithDescription(fmt.Sprintf("Resource '%s' is configured not to log disconnections", resourceBlock.FullName())),
+							)
+						}
+						return
+					}
+				}
+			}
+
+			set.Add(
+				result.New(resourceBlock).
+					WithDescription(fmt.Sprintf("Resource '%s' is not configured to log disconnections", resourceBlock.FullName())),
+			)
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_errors_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_errors_rule.go
new file mode 100644
index 000000000..dfd86cd8b
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_errors_rule.go
@@ -0,0 +1,92 @@
+package sql
+
+import (
+	"fmt"
+
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+
+	"github.com/aquasecurity/tfsec/pkg/provider"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+
+	"github.com/aquasecurity/tfsec/pkg/rule"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Service:   "sql",
+		ShortCode: "pg-log-errors",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure that Postgres errors are logged",
+			Explanation: `Setting the minimum log severity too high will cause errors not to be logged`,
+			Impact:      "Loss of error logging",
+			Resolution:  "Set the minimum log severity to at least ERROR",
+			BadExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_messages"
+			value = "PANIC"
+		}
+	}
+}
+			`,
+			GoodExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_messages"
+			value = "WARNING"
+		}
+	}
+}
+			`,
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance",
+				"https://postgresqlco.nf/doc/en/param/log_min_messages/",
+				"https://www.postgresql.org/docs/13/runtime-config-logging.html#GUC-LOG-MIN-MESSAGES",
+			},
+		},
+		Provider:        provider.GoogleProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"google_sql_database_instance"},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			dbVersionAttr := resourceBlock.GetAttribute("database_version")
+			if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") {
+				return
+			}
+
+			settingsBlock := resourceBlock.GetBlock("settings")
+			if settingsBlock == nil {
+				return
+			}
+
+			for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") {
+				if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_min_messages") {
+					if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() {
+						switch valueAttr.Value().AsString() {
+						case "FATAL", "PANIC", "LOG":
+							set.Add(
+								result.New(resourceBlock).
+									WithDescription(fmt.Sprintf("Resource '%s' has a minimum log severity set which ignores errors", resourceBlock.FullName())),
+							)
+						}
+					}
+				}
+			}
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule.go
new file mode 100644
index 000000000..2c67fd32c
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule.go
@@ -0,0 +1,100 @@
+package sql
+
+import (
+	"fmt"
+
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+
+	"github.com/aquasecurity/tfsec/pkg/provider"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+
+	"github.com/aquasecurity/tfsec/pkg/rule"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Service:   "sql",
+		ShortCode: "pg-log-lock-waits",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure that logging of lock waits is enabled.",
+			Explanation: `Lock waits are often an indication of poor performance and often an indicator of a potential denial of service vulnerability, therefore occurrences should be logged for analysis.`,
+			Impact:      "Issues leading to denial of service may not be identified.",
+			Resolution:  "Enable lock wait logging.",
+			BadExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_lock_waits"
+			value = "off"
+		}
+	}
+}
+			`,
+			GoodExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_lock_waits"
+			value = "on"
+		}
+	}
+}
+			`,
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance",
+				"https://www.postgresql.org/docs/13/runtime-config-logging.html#GUC-LOG-LOCK-WAITS",
+			},
+		},
+		Provider:        provider.GoogleProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"google_sql_database_instance"},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			dbVersionAttr := resourceBlock.GetAttribute("database_version")
+			if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") {
+				return
+			}
+
+			settingsBlock := resourceBlock.GetBlock("settings")
+			if settingsBlock == nil {
+				set.Add(
+					result.New(resourceBlock).
+						WithDescription(fmt.Sprintf("Resource '%s' is not configured to log lock waits", resourceBlock.FullName())),
+				)
+				return
+			}
+
+			for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") {
+				if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_lock_waits") {
+					if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() {
+						if valueAttr.Value().AsString() == "off" {
+							set.Add(
+								result.New(resourceBlock).
+									WithDescription(fmt.Sprintf("Resource '%s' is configured not to log lock waits", resourceBlock.FullName())),
+							)
+						}
+						return
+					}
+				}
+			}
+
+			set.Add(
+				result.New(resourceBlock).
+					WithDescription(fmt.Sprintf("Resource '%s' is not configured to log lock waits", resourceBlock.FullName())),
+			)
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule.go b/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule.go
new file mode 100644
index 000000000..802ce9576
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule.go
@@ -0,0 +1,90 @@
+package sql
+
+import (
+	"fmt"
+
+	"github.com/aquasecurity/tfsec/pkg/result"
+	"github.com/aquasecurity/tfsec/pkg/severity"
+
+	"github.com/aquasecurity/tfsec/pkg/provider"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+
+	"github.com/aquasecurity/tfsec/pkg/rule"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Service:   "sql",
+		ShortCode: "pg-no-min-statement-logging",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure that logging of long statements is disabled.",
+			Explanation: `Logging of statements which could contain sensitive data is not advised, therefore this setting should preclude all statements from being logged.`,
+			Impact:      "Sensitive data could be exposed in the database logs.",
+			Resolution:  "Disable minimum duration statement logging completely",
+			BadExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_duration_statement"
+			value = "99"
+		}
+	}
+}
+			`,
+			GoodExample: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_duration_statement"
+			value = "-1"
+		}
+	}
+}
+			`,
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance",
+				"https://www.postgresql.org/docs/13/runtime-config-logging.html#GUC-LOG-MIN-DURATION-STATEMENT",
+			},
+		},
+		Provider:        provider.GoogleProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"google_sql_database_instance"},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			dbVersionAttr := resourceBlock.GetAttribute("database_version")
+			if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") {
+				return
+			}
+
+			settingsBlock := resourceBlock.GetBlock("settings")
+			if settingsBlock == nil {
+				return
+			}
+
+			for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") {
+				if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_min_duration_statement") {
+					if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() {
+						if valueAttr.Value().AsString() != "-1" {
+							set.Add(
+								result.New(resourceBlock).
+									WithDescription(fmt.Sprintf("Resource '%s' causes database query statements to be logged", resourceBlock.FullName())),
+							)
+						}
+					}
+				}
+			}
+
+		},
+	})
+}


Test patch:
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule_test.go b/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule_test.go
new file mode 100644
index 000000000..8cdd6b8e5
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule_test.go
@@ -0,0 +1,83 @@
+package sql
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GooglePgLogCheckpoints(t *testing.T) {
+	expectedCode := "google-sql-pg-log-checkpoints"
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode string
+		mustExcludeResultCode string
+	}{
+		{
+			name: "rule matches when flag is explicitly set to off",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_checkpoints"
+			value = "off"
+		}
+	}
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule matches when flag is set to default (off)",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when flag is set to on",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_checkpoints"
+			value = "on"
+		}
+	}
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when not postgres",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "MYSQL_5_6"
+	region           = "us-central1"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+
+			results := testutil.ScanHCL(test.source, t)
+			testutil.AssertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_connections_rule_test.go b/internal/app/tfsec/rules/google/sql/pg_log_connections_rule_test.go
new file mode 100644
index 000000000..c839a0781
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_connections_rule_test.go
@@ -0,0 +1,83 @@
+package sql
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GooglePgLogConnections(t *testing.T) {
+	expectedCode := "google-sql-pg-log-disconnections"
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode string
+		mustExcludeResultCode string
+	}{
+		{
+			name: "rule matches when flag is explicitly set to off",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_disconnections"
+			value = "off"
+		}
+	}
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule matches when flag is set to default (off)",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when flag is set to on",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_disconnections"
+			value = "on"
+		}
+	}
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when not postgres",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "MYSQL_5_6"
+	region           = "us-central1"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+
+			results := testutil.ScanHCL(test.source, t)
+			testutil.AssertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule_test.go b/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule_test.go
new file mode 100644
index 000000000..c4f2257b4
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule_test.go
@@ -0,0 +1,83 @@
+package sql
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GooglePgLogDisconnections(t *testing.T) {
+	expectedCode := "google-sql-pg-log-connections"
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode string
+		mustExcludeResultCode string
+	}{
+		{
+			name: "rule matches when flag is explicitly set to off",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_connections"
+			value = "off"
+		}
+	}
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule matches when flag is set to default (off)",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when flag is set to on",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_connections"
+			value = "on"
+		}
+	}
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when not postgres",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "MYSQL_5_6"
+	region           = "us-central1"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+
+			results := testutil.ScanHCL(test.source, t)
+			testutil.AssertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_errors_rule_test.go b/internal/app/tfsec/rules/google/sql/pg_log_errors_rule_test.go
new file mode 100644
index 000000000..6317e5f36
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_errors_rule_test.go
@@ -0,0 +1,100 @@
+package sql
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GooglePgLogErrors(t *testing.T) {
+	expectedCode := "google-sql-pg-log-errors"
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode string
+		mustExcludeResultCode string
+	}{
+		{
+			name: "rule matches when flag is explicitly set to panic",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_messages"
+			value = "PANIC"
+		}
+	}
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule matches when flag is explicitly set to ",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_messages"
+			value = "FATAL"
+		}
+	}
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when debug is used",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_messages"
+			value = "DEBUG1"
+		}
+	}
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when default (warning) is used",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when postgres is not used",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "MYSQL_8_0"
+	region           = "us-central1"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+
+			results := testutil.ScanHCL(test.source, t)
+			testutil.AssertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule_test.go b/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule_test.go
new file mode 100644
index 000000000..0c016f4c8
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule_test.go
@@ -0,0 +1,83 @@
+package sql
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GooglePgLogLockWaits(t *testing.T) {
+	expectedCode := "google-sql-pg-log-lock-waits"
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode string
+		mustExcludeResultCode string
+	}{
+		{
+			name: "rule matches when flag is explicitly set to off",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_lock_waits"
+			value = "off"
+		}
+	}
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule matches when flag is set to default (off)",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when flag is set to on",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_lock_waits"
+			value = "on"
+		}
+	}
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when not postgres",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "MYSQL_5_6"
+	region           = "us-central1"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+
+			results := testutil.ScanHCL(test.source, t)
+			testutil.AssertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+}
diff --git a/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule_test.go b/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule_test.go
new file mode 100644
index 000000000..0e9b5994f
--- /dev/null
+++ b/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule_test.go
@@ -0,0 +1,72 @@
+package sql
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_GooglePgLogDurationStatement(t *testing.T) {
+	expectedCode := "google-sql-pg-no-min-statement-logging"
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode string
+		mustExcludeResultCode string
+	}{
+		{
+			name: "rule matches when flag is explicitly set to 99",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_duration_statement"
+			value = "99"
+		}
+	}
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when flag is explicitly set to -1",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+	settings {
+		database_flags {
+			name  = "log_min_duration_statement"
+			value = "-1"
+		}
+	}
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule does not match when flag is set to default (-1)",
+			source: `
+resource "google_sql_database_instance" "db" {
+	name             = "db"
+	database_version = "POSTGRES_12"
+	region           = "us-central1"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+
+			results := testutil.ScanHCL(test.source, t)
+			testutil.AssertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+}