Repository: aquasecurity/tfsec
Pull request #1095 (2021-10-01 19:26:05)

Mysql Threat detection and required email security center check
Adding a few more Azure terraform checks


Patch:
diff --git a/internal/app/tfsec/rules/azure/database/mysql_threat_detection_enabled_rule.go b/internal/app/tfsec/rules/azure/database/mysql_threat_detection_enabled_rule.go
new file mode 100644
index 000000000..86c37dfc4
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/mysql_threat_detection_enabled_rule.go
@@ -0,0 +1,82 @@
+package database
+
+// generator-locked
+import (
+	"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/block"
+
+	"github.com/aquasecurity/tfsec/pkg/rule"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Service:   "database",
+		ShortCode: "mysql-threat-detection-enabled",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure databases are not publicly accessible",
+			Explanation: `My SQL server does not enable Threat Detection policy`,
+			Impact:      "Threat detection helps prevent compromise by alerting on threat detections",
+			Resolution:  "Enable threat detection on Mysql database",
+			BadExample: []string{`
+resource "azurerm_mysql_server" "bad_example" {
+  name                = "bad_example"
+
+  public_network_access_enabled    = true
+  ssl_enforcement_enabled          = false
+  ssl_minimal_tls_version_enforced = "TLS1_2"
+
+  threat_detection_policy {
+    enabled = false
+  }
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_mysql_server" "good_example" {
+  name                = "good_example"
+
+  public_network_access_enabled    = false
+  ssl_enforcement_enabled          = false
+  ssl_minimal_tls_version_enforced = "TLS1_2"
+
+  threat_detection_policy {
+    enabled = true
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/mysql_server#threat_detection_policy",
+			},
+		},
+		Provider:        provider.AzureProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"azurerm_mysql_server"},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ block.Module) {
+
+			if resourceBlock.MissingChild("threat_detection_policy") {
+				set.AddResult().
+					WithDescription("Mysql server '%s' does not have threat detection policy configured. By default it is disabled.", resourceBlock.FullName())
+				return
+			}
+
+			tdpBlock := resourceBlock.GetBlock("threat_detection_policy")
+			if tdpBlock.MissingChild("enabled") {
+				set.AddResult().
+					WithDescription("Mysql server '%s' threat detection policy block is empty. By default Threat detection policy is disabled.", resourceBlock.FullName()).
+					WithBlock(tdpBlock)
+			}
+
+			if tdpEnabledAttr := tdpBlock.GetAttribute("enabled"); tdpEnabledAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Mysql Server '%s' has disabled threat detection policy", resourceBlock.FullName()).
+					WithAttribute(tdpEnabledAttr)
+			}
+		},
+	})
+}


Test patch:
diff --git a/internal/app/tfsec/rules/azure/database/mysql_threat_detection_enabled_rule_test.go b/internal/app/tfsec/rules/azure/database/mysql_threat_detection_enabled_rule_test.go
new file mode 100644
index 000000000..502138d34
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/mysql_threat_detection_enabled_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_DatabaseMysqlThreatDetectionEnabled_FailureExamples(t *testing.T) {
+	expectedCode := "azure-database-mysql-threat-detection-enabled"
+
+	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_DatabaseMysqlThreatDetectionEnabled_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-database-mysql-threat-detection-enabled"
+
+	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)
+	}
+}