Repository: aquasecurity/tfsec
Pull request #948 (2021-07-26 11:02:45)

Add check for azure sql firewall
if start is 0.0.0.0 and end isn't the same, raise an error



Patch:
diff --git a/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule.go b/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule.go
new file mode 100644
index 000000000..fb7bcd3d2
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule.go
@@ -0,0 +1,77 @@
+package database
+
+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:   "database",
+		ShortCode: "no-public-firewall-access",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure database firewalls do not permit public access",
+			Explanation: `Azure services can be allowed access through the firewall using a start and end IP address of 0.0.0.0. No other end ip address should be combined with a start of 0.0.0.0`,
+			Impact:      "Publicly accessible databases could lead to compromised data",
+			Resolution:  "Don't use wide ip ranges for the sql firewall",
+			BadExample: `
+resource "azurerm_sql_firewall_rule" "bad_example" {
+  name                = "bad_rule"
+  resource_group_name = azurerm_resource_group.example.name
+  server_name         = azurerm_sql_server.example.name
+  start_ip_address    = "0.0.0.0"
+  end_ip_address      = "255.255.255.255"
+}
+`,
+			GoodExample: `
+resource "azurerm_sql_firewall_rule" "good_example" {
+  name                = "good_rule"
+  resource_group_name = azurerm_resource_group.example.name
+  server_name         = azurerm_sql_server.example.name
+  start_ip_address    = "0.0.0.0"
+  end_ip_address      = "0.0.0.0"
+}
+`,
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/sql_firewall_rule#end_ip_address",
+				"https://docs.microsoft.com/en-us/rest/api/sql/2021-02-01-preview/firewall-rules/create-or-update",
+			},
+		},
+		Provider:        provider.AzureProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"azurerm_sql_firewall_rule"},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+
+			if resourceBlock.MissingChild("start_ip_address") || resourceBlock.MissingChild("end_ip_address") {
+				return
+			}
+
+			sourceIpAttr := resourceBlock.GetAttribute("start_ip_address")
+			if sourceIpAttr.Equals("0.0.0.0") {
+				endIpAttr := resourceBlock.GetAttribute("end_ip_address")
+				if !endIpAttr.Equals("0.0.0.0") {
+					set.Add(
+						result.New(resourceBlock).
+							WithDescription(fmt.Sprintf("Resource '%s' has an open IP range set.", resourceBlock.FullName())).
+							WithRange(endIpAttr.Range()).
+							WithAttributeAnnotation(endIpAttr),
+					)
+				}
+			}
+
+		},
+	})
+}


Test patch:
diff --git a/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule_test.go b/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule_test.go
new file mode 100644
index 000000000..dc130a4be
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule_test.go
@@ -0,0 +1,66 @@
+package database
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureNoPublicFirewallAccess(t *testing.T) {
+	expectedCode := "azure-database-no-public-firewall-access"
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode string
+		mustExcludeResultCode string
+	}{
+		{
+			name: "rule with open ip range fails check",
+			source: `
+resource "azurerm_sql_firewall_rule" "bad_example" {
+  name                = "bad_rule"
+  resource_group_name = azurerm_resource_group.example.name
+  server_name         = azurerm_sql_server.example.name
+  start_ip_address    = "0.0.0.0"
+  end_ip_address      = "255.255.255.255"
+}
+`,
+			mustIncludeResultCode: expectedCode,
+		},
+		{
+			name: "rule with specific Azure services start and end ip passes check",
+			source: `
+resource "azurerm_sql_firewall_rule" "good_example" {
+  name                = "good_rule"
+  resource_group_name = azurerm_resource_group.example.name
+  server_name         = azurerm_sql_server.example.name
+  start_ip_address    = "0.0.0.0"
+  end_ip_address      = "0.0.0.0"
+}
+`,
+			mustExcludeResultCode: expectedCode,
+		},
+		{
+			name: "rule with specific Azure services start and end ip passes check",
+			source: `
+resource "azurerm_sql_firewall_rule" "good_example" {
+  name                = "good_rule"
+  resource_group_name = azurerm_resource_group.example.name
+  server_name         = azurerm_sql_server.example.name
+  start_ip_address    = "10.0.2.0"
+  end_ip_address      = "10.0.2.240"
+}
+`,
+			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)
+		})
+	}
+}