Repository: aquasecurity/tfsec
Pull request #1027 (2021-08-16 10:47:48)

2148 role
- Add mssql alert checks
- Add check that role isn't open



Patch:
diff --git a/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule.go b/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule.go
new file mode 100644
index 000000000..3c1d364ee
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule.go
@@ -0,0 +1,88 @@
+package authorization
+
+// 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/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:   "authorization",
+		ShortCode: "limit-role-actions",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Roles limited to the required actions",
+			Explanation: `The permissions granted to a role should be kept to the minimum required to be able to do the task. Wildcard permissions must not be used.`,
+			Impact:      "Open permissions for subscriptions could result in an easily compromisable account",
+			Resolution:  "Use targeted permissions for roles",
+			BadExample: []string{`
+data "azurerm_subscription" "primary" {
+}
+
+resource "azurerm_role_definition" "example" {
+  name        = "my-custom-role"
+  scope       = data.azurerm_subscription.primary.id
+  description = "This is a custom role created via Terraform"
+
+  permissions {
+    actions     = ["*"]
+    not_actions = []
+  }
+
+  assignable_scopes = [
+    "/"
+  ]
+}
+`},
+			GoodExample: []string{`
+data "azurerm_subscription" "primary" {
+}
+
+resource "azurerm_role_definition" "example" {
+  name        = "my-custom-role"
+  scope       = data.azurerm_subscription.primary.id
+  description = "This is a custom role created via Terraform"
+
+  permissions {
+    actions     = ["*"]
+    not_actions = []
+  }
+
+  assignable_scopes = [
+    data.azurerm_subscription.primary.id,
+  ]
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition#actions",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_role_definition",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			if permissionBlock := resourceBlock.GetBlock("permissions"); permissionBlock.IsNotNil() {
+				if actionsAttr := permissionBlock.GetAttribute("actions"); actionsAttr.IsNotNil() && actionsAttr.Contains("*") {
+					// need more information
+					if assignableScopesAttr := resourceBlock.GetAttribute("assignable_scopes"); assignableScopesAttr.IsNil() || assignableScopesAttr.Contains("/") {
+						set.AddResult().
+							WithDescription("Resource '%s' has wildcard action with open assignable_scopes", resourceBlock.FullName()).
+							WithAttribute(actionsAttr)
+					}
+				}
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/init.go b/internal/app/tfsec/rules/init.go
index 21a39e3b4..40d4c7942 100644
--- a/internal/app/tfsec/rules/init.go
+++ b/internal/app/tfsec/rules/init.go
@@ -41,8 +41,7 @@ import (
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/aws/vpc"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/aws/workspace"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/azure/appservice"
-
-	// _ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/azure/authorization"
+	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/azure/authorization"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/azure/compute"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/azure/container"
 	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/azure/database"


Test patch:
diff --git a/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule_test.go b/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule_test.go
new file mode 100644
index 000000000..6f9c734d3
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule_test.go
@@ -0,0 +1,53 @@
+package authorization
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureLimitRoleActions_FailureExamples(t *testing.T) {
+	expectedCode := "azure-authorization-limit-role-actions"
+
+	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_AzureLimitRoleActions_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-authorization-limit-role-actions"
+
+	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)
+	}
+}