Repository: aquasecurity/tfsec
Pull request #1028 (2021-08-16 13:10:02)

Add postgresql log configuration
ensure that logging is turned on for an instance for
- log_connection
- log_checkpoint
- connection_throttling



Patch:
diff --git a/internal/app/tfsec/rules/azure/database/postgres_configration_log_checkpoints_rule.go b/internal/app/tfsec/rules/azure/database/postgres_configration_log_checkpoints_rule.go
new file mode 100644
index 000000000..213a185ec
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/postgres_configration_log_checkpoints_rule.go
@@ -0,0 +1,101 @@
+package database
+
+// 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/debug"
+	"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.AzureProvider,
+		Service:   "database",
+		ShortCode: "postgres-configration-log-checkpoints",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server",
+			Explanation: `Postgresql can generate logs for checkpoints to improve visibility for audit and configuration issue resolution.`,
+			Impact:      "No error and query logs generated on checkpoint",
+			Resolution:  "Enable checkpoint logging",
+			BadExample: []string{`
+resource "azurerm_resource_group" "example" {
+  name     = "example-resources"
+  location = "West Europe"
+}
+
+resource "azurerm_postgresql_server" "example" {
+  name                = "example-psqlserver"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+
+  administrator_login          = "psqladminun"
+  administrator_login_password = "H@Sh1CoR3!"
+
+  sku_name   = "GP_Gen5_4"
+  version    = "9.6"
+  storage_mb = 640000
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_resource_group" "example" {
+  name     = "example-resources"
+  location = "West Europe"
+}
+
+resource "azurerm_postgresql_server" "example" {
+  name                = "example-psqlserver"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+
+  administrator_login          = "psqladminun"
+  administrator_login_password = "H@Sh1CoR3!"
+
+  sku_name   = "GP_Gen5_4"
+  version    = "9.6"
+  storage_mb = 640000
+}
+
+resource "azurerm_postgresql_configuration" "example" {
+  name                = "log_checkpoints"
+  resource_group_name = azurerm_resource_group.example.name
+  server_name         = azurerm_postgresql_server.example.name
+  value               = "on"
+}
+
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_configuration",
+				"https://docs.microsoft.com/en-us/azure/postgresql/concepts-server-logs#configure-logging",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_postgresql_server",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			referencingBlocks, err := module.GetReferencingResources(resourceBlock, "azurerm_postgresql_configuration", "server_name")
+			if err != nil {
+				debug.Log("error occurred trying to get the referencing block for %s", resourceBlock.FullName())
+			}
+			for _, refBlock := range referencingBlocks {
+				if nameAttr := refBlock.GetAttribute("name"); nameAttr.IsNotNil() && nameAttr.Equals("log_checkpoints") {
+					if valAttr := refBlock.GetAttribute("value"); valAttr.IsNotNil() && valAttr.Equals("on", block.IgnoreCase) {
+						return
+					}
+				}
+			}
+			set.AddResult().
+				WithDescription("Resource '%s' does not have a corresponding log configuration enabling 'log_checkpoints'", resourceBlock.FullName())
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/database/postgres_configration_log_connection_throttling_rule.go b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connection_throttling_rule.go
new file mode 100644
index 000000000..d3a513ac5
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connection_throttling_rule.go
@@ -0,0 +1,101 @@
+package database
+
+// 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/debug"
+	"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.AzureProvider,
+		Service:   "database",
+		ShortCode: "postgres-configration-log-connection-throttling",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server",
+			Explanation: `Postgresql can generate logs for connection throttling to improve visibility for audit and configuration issue resolution.`,
+			Impact:      "No log information to help diagnosing connection contention issues",
+			Resolution:  "Enable connection throttling logging",
+			BadExample: []string{`
+resource "azurerm_resource_group" "example" {
+  name     = "example-resources"
+  location = "West Europe"
+}
+
+resource "azurerm_postgresql_server" "example" {
+  name                = "example-psqlserver"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+
+  administrator_login          = "psqladminun"
+  administrator_login_password = "H@Sh1CoR3!"
+
+  sku_name   = "GP_Gen5_4"
+  version    = "9.6"
+  storage_mb = 640000
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_resource_group" "example" {
+  name     = "example-resources"
+  location = "West Europe"
+}
+
+resource "azurerm_postgresql_server" "example" {
+  name                = "example-psqlserver"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+
+  administrator_login          = "psqladminun"
+  administrator_login_password = "H@Sh1CoR3!"
+
+  sku_name   = "GP_Gen5_4"
+  version    = "9.6"
+  storage_mb = 640000
+}
+
+resource "azurerm_postgresql_configuration" "example" {
+	name                = "connection_throttling"
+	resource_group_name = azurerm_resource_group.example.name
+	server_name         = azurerm_postgresql_server.example.name
+	value               = "on"
+  }
+  
+  `},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_configuration",
+				"https://docs.microsoft.com/en-us/azure/postgresql/concepts-server-logs#configure-logging",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_postgresql_server",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			referencingBlocks, err := module.GetReferencingResources(resourceBlock, "azurerm_postgresql_configuration", "server_name")
+			if err != nil {
+				debug.Log("error occurred trying to get the referencing block for %s", resourceBlock.FullName())
+			}
+			for _, refBlock := range referencingBlocks {
+				if nameAttr := refBlock.GetAttribute("name"); nameAttr.IsNotNil() && nameAttr.Equals("connection_throttling") {
+					if valAttr := refBlock.GetAttribute("value"); valAttr.IsNotNil() && valAttr.Equals("on", block.IgnoreCase) {
+						return
+					}
+				}
+			}
+			set.AddResult().
+				WithDescription("Resource '%s' does not have a corresponding log configuration enabling 'connection_throttling'", resourceBlock.FullName())
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/database/postgres_configration_log_connections_rule.go b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connections_rule.go
new file mode 100644
index 000000000..11a04ffcd
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connections_rule.go
@@ -0,0 +1,100 @@
+package database
+
+// 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/debug"
+	"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.AzureProvider,
+		Service:   "database",
+		ShortCode: "postgres-configration-log-connections",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server",
+			Explanation: `Postgresql can generate logs for successful connections to improve visibility for audit and configuration issue resolution.`,
+			Impact:      "No visibility of successful connections",
+			Resolution:  "Enable connection logging",
+			BadExample: []string{`
+resource "azurerm_resource_group" "example" {
+  name     = "example-resources"
+  location = "West Europe"
+}
+
+resource "azurerm_postgresql_server" "example" {
+  name                = "example-psqlserver"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+
+  administrator_login          = "psqladminun"
+  administrator_login_password = "H@Sh1CoR3!"
+
+  sku_name   = "GP_Gen5_4"
+  version    = "9.6"
+  storage_mb = 640000
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_resource_group" "example" {
+  name     = "example-resources"
+  location = "West Europe"
+}
+
+resource "azurerm_postgresql_server" "example" {
+  name                = "example-psqlserver"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+
+  administrator_login          = "psqladminun"
+  administrator_login_password = "H@Sh1CoR3!"
+
+  sku_name   = "GP_Gen5_4"
+  version    = "9.6"
+  storage_mb = 640000
+}
+
+resource "azurerm_postgresql_configuration" "example" {
+	name                = "log_connections"
+	resource_group_name = azurerm_resource_group.example.name
+	server_name         = azurerm_postgresql_server.example.name
+	value               = "on"
+  }
+  
+  `},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_configuration",
+				"https://docs.microsoft.com/en-us/azure/postgresql/concepts-server-logs#configure-logging"},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_postgresql_server",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			referencingBlocks, err := module.GetReferencingResources(resourceBlock, "azurerm_postgresql_configuration", "server_name")
+			if err != nil {
+				debug.Log("error occurred trying to get the referencing block for %s", resourceBlock.FullName())
+			}
+			for _, refBlock := range referencingBlocks {
+				if nameAttr := refBlock.GetAttribute("name"); nameAttr.IsNotNil() && nameAttr.Equals("log_connections") {
+					if valAttr := refBlock.GetAttribute("value"); valAttr.IsNotNil() && valAttr.Equals("on", block.IgnoreCase) {
+						return
+					}
+				}
+			}
+			set.AddResult().
+				WithDescription("Resource '%s' does not have a corresponding log configuration enabling 'log_connections'", resourceBlock.FullName())
+		},
+	})
+}


Test patch:
diff --git a/internal/app/tfsec/rules/azure/database/postgres_configration_log_checkpoints_rule_test.go b/internal/app/tfsec/rules/azure/database/postgres_configration_log_checkpoints_rule_test.go
new file mode 100644
index 000000000..a9f69c116
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/postgres_configration_log_checkpoints_rule_test.go
@@ -0,0 +1,53 @@
+package database
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzurePostgresConfigrationLogCheckpoints_FailureExamples(t *testing.T) {
+	expectedCode := "azure-database-postgres-configration-log-checkpoints"
+
+	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_AzurePostgresConfigrationLogCheckpoints_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-database-postgres-configration-log-checkpoints"
+
+	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/azure/database/postgres_configration_log_connection_throttling_rule_test.go b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connection_throttling_rule_test.go
new file mode 100644
index 000000000..53e0f4685
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connection_throttling_rule_test.go
@@ -0,0 +1,53 @@
+package database
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzurePostgresConfigrationLogConnectionThrottling_FailureExamples(t *testing.T) {
+	expectedCode := "azure-database-postgres-configration-log-connection-throttling"
+
+	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_AzurePostgresConfigrationLogConnectionThrottling_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-database-postgres-configration-log-connection-throttling"
+
+	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/azure/database/postgres_configration_log_connections_rule_test.go b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connections_rule_test.go
new file mode 100644
index 000000000..76d18a9df
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/postgres_configration_log_connections_rule_test.go
@@ -0,0 +1,53 @@
+package database
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzurePostgresConfigrationLogConnections_FailureExamples(t *testing.T) {
+	expectedCode := "azure-database-postgres-configration-log-connections"
+
+	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_AzurePostgresConfigrationLogConnections_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-database-postgres-configration-log-connections"
+
+	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)
+	}
+}