From eafac26906c7a8bfcd3a7683410b6dd1093133a3 Mon Sep 17 00:00:00 2001 From: Preben Huybrechts Date: Mon, 11 Nov 2024 11:37:27 +0100 Subject: [PATCH 1/2] feat: Keyvault acls --- docs/README.md | 3 +- main.go | 1 + rules/azurerm_keyvault_network_acls.go | 107 ++++++++++++++++++ rules/azurerm_keyvault_network_acls_test.go | 97 ++++++++++++++++ ..._keyvault_public_network_access_enabled.go | 2 +- 5 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 rules/azurerm_keyvault_network_acls.go create mode 100644 rules/azurerm_keyvault_network_acls_test.go diff --git a/docs/README.md b/docs/README.md index 838a03f..70b9fca 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,7 +9,8 @@ ## azurerm_key_vault |Name|Description|Severity|Enabled|Link| | --- | --- | --- | --- | --- | -|azurerm_key_vault_public_network_access_enabled|Consider disabling public network access on keyvaults. |NOTICE|✔|| +|azurerm_key_vault_public_network_access_enabled|Consider disabling public network access on keyvaults. |NOTICE||| +|azurerm_key_vault_network_acls_default_deny|Deny network access to Keyvaults. You can add `bypass = "AzureServices"` to allow azure services to connect to keyvault or add `ip_rules`|WARNING|✔|| ## azurerm_linux_function_app |Name|Description|Severity|Enabled|Link| diff --git a/main.go b/main.go index e4c184d..ce47c7f 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ func createRuleSet() *tflint.BuiltinRuleSet { Rules: []tflint.Rule{ rules.NewAzurermEventhubNamespacePublicNetworkAccessEnabled(), rules.NewAzurermEventhubNamespaceUnsecureTLS(), + rules.NewAzurermKeyVaultNetworkAclsDefaultDeny(), rules.NewAzurermKeyVaultPublicNetworkAccessEnabled(), rules.NewAzurermLinuxFunctionAppFtpsState(), rules.NewAzurermLinuxFunctionAppHTTPSOnly(), diff --git a/rules/azurerm_keyvault_network_acls.go b/rules/azurerm_keyvault_network_acls.go new file mode 100644 index 0000000..031ab06 --- /dev/null +++ b/rules/azurerm_keyvault_network_acls.go @@ -0,0 +1,107 @@ +package rules + +import ( + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AzurermKeyVaultNetworkAclsDefaultDeny checks that network_acls default_action is set to "Deny" +type AzurermKeyVaultNetworkAclsDefaultDeny struct { + tflint.DefaultRule + + resourceType string + blockName string +} + +// NewAzurermKeyVaultNetworkAclsDefaultDeny returns a new rule instance +func NewAzurermKeyVaultNetworkAclsDefaultDeny() *AzurermKeyVaultNetworkAclsDefaultDeny { + return &AzurermKeyVaultNetworkAclsDefaultDeny{ + resourceType: "azurerm_key_vault", + blockName: "network_acls", + } +} + +// Name returns the rule name +func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Name() string { + return "azurerm_key_vault_network_acls_default_deny" +} + +// Enabled returns whether the rule is enabled by default +func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Severity() tflint.Severity { + return tflint.WARNING +} + +// Link returns the rule reference link +func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Link() string { + return "" +} + +// Check checks if network_acls default_action is set to "Deny" +func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Check(runner tflint.Runner) error { + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Blocks: []hclext.BlockSchema{ + { + Type: r.blockName, + Body: &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: "default_action"}, + }, + }, + }, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + networkAcls := resource.Body.Blocks + + if len(networkAcls) == 0 { + runner.EmitIssue( + r, + "network_acls block is not defined, consider adding it with default_action = \"Deny\"", + resource.DefRange, + ) + continue + } + + for _, networkAcl := range networkAcls { + if networkAcl.Type != r.blockName { + continue + } + + attribute, exists := networkAcl.Body.Attributes["default_action"] + if !exists { + runner.EmitIssue( + r, + "default_action is not defined in network_acls block", + networkAcl.DefRange, + ) + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func(val string) error { + if val != "Deny" { + runner.EmitIssue( + r, + "network_acls default_action should be set to \"Deny\"", + attribute.Expr.Range(), + ) + } + return nil + }, nil) + + if err != nil { + return err + } + } + } + + return nil +} \ No newline at end of file diff --git a/rules/azurerm_keyvault_network_acls_test.go b/rules/azurerm_keyvault_network_acls_test.go new file mode 100644 index 0000000..28016c8 --- /dev/null +++ b/rules/azurerm_keyvault_network_acls_test.go @@ -0,0 +1,97 @@ +package rules + +import ( + "testing" + + hcl "github.com/hashicorp/hcl/v2" + "github.com/terraform-linters/tflint-plugin-sdk/helper" +) + +func Test_AzurermKeyVaultNetworkAclsDefaultDeny(t *testing.T) { + tests := []struct { + Name string + Content string + Expected helper.Issues + }{ + { + Name: "no network_acls block", + Content: ` +resource "azurerm_key_vault" "example" { +}`, + Expected: helper.Issues{ + { + Rule: NewAzurermKeyVaultNetworkAclsDefaultDeny(), + Message: "network_acls block is not defined, consider adding it with default_action = \"Deny\"", + Range: hcl.Range{ + Filename: "resource.tf", + Start: hcl.Pos{Line: 2, Column: 1}, + End: hcl.Pos{Line: 2, Column: 39}, + }, + }, + }, + }, + { + Name: "network_acls without default_action", + Content: ` +resource "azurerm_key_vault" "example" { + network_acls { + } +}`, + Expected: helper.Issues{ + { + Rule: NewAzurermKeyVaultNetworkAclsDefaultDeny(), + Message: "default_action is not defined in network_acls block", + Range: hcl.Range{ + Filename: "resource.tf", + Start: hcl.Pos{Line: 3, Column: 5}, + End: hcl.Pos{Line: 3, Column: 17}, + }, + }, + }, + }, + { + Name: "network_acls with default_action Allow", + Content: ` +resource "azurerm_key_vault" "example" { + network_acls { + default_action = "Allow" + } +}`, + Expected: helper.Issues{ + { + Rule: NewAzurermKeyVaultNetworkAclsDefaultDeny(), + Message: "network_acls default_action should be set to \"Deny\"", + Range: hcl.Range{ + Filename: "resource.tf", + Start: hcl.Pos{Line: 4, Column: 26}, + End: hcl.Pos{Line: 4, Column: 33}, + }, + }, + }, + }, + { + Name: "network_acls with default_action Deny", + Content: ` +resource "azurerm_key_vault" "example" { + network_acls { + default_action = "Deny" + } +}`, + Expected: helper.Issues{}, + }, + } + + rule := NewAzurermKeyVaultNetworkAclsDefaultDeny() + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + runner := helper.TestRunner(t, map[string]string{"resource.tf": test.Content}) + + if err := rule.Check(runner); err != nil { + t.Fatalf("Unexpected error occurred: %s", err) + } + + helper.AssertIssues(t, test.Expected, runner.Issues) + }) + } +} diff --git a/rules/azurerm_keyvault_public_network_access_enabled.go b/rules/azurerm_keyvault_public_network_access_enabled.go index f7d2381..73c9162 100644 --- a/rules/azurerm_keyvault_public_network_access_enabled.go +++ b/rules/azurerm_keyvault_public_network_access_enabled.go @@ -28,7 +28,7 @@ func (r *AzurermKeyVaultPublicNetworkAccessEnabled) Name() string { // Enabled returns whether the rule is enabled by default func (r *AzurermKeyVaultPublicNetworkAccessEnabled) Enabled() bool { - return true + return false } // Severity returns the rule severity From 68197fa0c2bc5e1ff29a10e9f913a22320179723 Mon Sep 17 00:00:00 2001 From: Preben Huybrechts Date: Tue, 12 Nov 2024 06:47:25 +0100 Subject: [PATCH 2/2] lint --- main.go | 2 +- rules/azurerm_keyvault_network_acls.go | 32 ++++++++++----------- rules/azurerm_keyvault_network_acls_test.go | 10 +++---- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/main.go b/main.go index ce47c7f..441ca63 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ func createRuleSet() *tflint.BuiltinRuleSet { Rules: []tflint.Rule{ rules.NewAzurermEventhubNamespacePublicNetworkAccessEnabled(), rules.NewAzurermEventhubNamespaceUnsecureTLS(), - rules.NewAzurermKeyVaultNetworkAclsDefaultDeny(), + rules.NewAzurermKeyVaultNetworkACLsDefaultDeny(), rules.NewAzurermKeyVaultPublicNetworkAccessEnabled(), rules.NewAzurermLinuxFunctionAppFtpsState(), rules.NewAzurermLinuxFunctionAppHTTPSOnly(), diff --git a/rules/azurerm_keyvault_network_acls.go b/rules/azurerm_keyvault_network_acls.go index 031ab06..d6bbfc0 100644 --- a/rules/azurerm_keyvault_network_acls.go +++ b/rules/azurerm_keyvault_network_acls.go @@ -5,44 +5,44 @@ import ( "github.com/terraform-linters/tflint-plugin-sdk/tflint" ) -// AzurermKeyVaultNetworkAclsDefaultDeny checks that network_acls default_action is set to "Deny" -type AzurermKeyVaultNetworkAclsDefaultDeny struct { +// AzurermKeyVaultNetworkACLsDefaultDeny checks that network_acls default_action is set to "Deny" +type AzurermKeyVaultNetworkACLsDefaultDeny struct { tflint.DefaultRule resourceType string blockName string } -// NewAzurermKeyVaultNetworkAclsDefaultDeny returns a new rule instance -func NewAzurermKeyVaultNetworkAclsDefaultDeny() *AzurermKeyVaultNetworkAclsDefaultDeny { - return &AzurermKeyVaultNetworkAclsDefaultDeny{ +// NewAzurermKeyVaultNetworkACLsDefaultDeny returns a new rule instance +func NewAzurermKeyVaultNetworkACLsDefaultDeny() *AzurermKeyVaultNetworkACLsDefaultDeny { + return &AzurermKeyVaultNetworkACLsDefaultDeny{ resourceType: "azurerm_key_vault", blockName: "network_acls", } } // Name returns the rule name -func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Name() string { +func (r *AzurermKeyVaultNetworkACLsDefaultDeny) Name() string { return "azurerm_key_vault_network_acls_default_deny" } // Enabled returns whether the rule is enabled by default -func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Enabled() bool { +func (r *AzurermKeyVaultNetworkACLsDefaultDeny) Enabled() bool { return true } // Severity returns the rule severity -func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Severity() tflint.Severity { +func (r *AzurermKeyVaultNetworkACLsDefaultDeny) Severity() tflint.Severity { return tflint.WARNING } // Link returns the rule reference link -func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Link() string { +func (r *AzurermKeyVaultNetworkACLsDefaultDeny) Link() string { return "" } // Check checks if network_acls default_action is set to "Deny" -func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Check(runner tflint.Runner) error { +func (r *AzurermKeyVaultNetworkACLsDefaultDeny) Check(runner tflint.Runner) error { resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ Blocks: []hclext.BlockSchema{ { @@ -60,9 +60,9 @@ func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Check(runner tflint.Runner) erro } for _, resource := range resources.Blocks { - networkAcls := resource.Body.Blocks + networkACLs := resource.Body.Blocks - if len(networkAcls) == 0 { + if len(networkACLs) == 0 { runner.EmitIssue( r, "network_acls block is not defined, consider adding it with default_action = \"Deny\"", @@ -71,17 +71,17 @@ func (r *AzurermKeyVaultNetworkAclsDefaultDeny) Check(runner tflint.Runner) erro continue } - for _, networkAcl := range networkAcls { - if networkAcl.Type != r.blockName { + for _, networkACL := range networkACLs { + if networkACL.Type != r.blockName { continue } - attribute, exists := networkAcl.Body.Attributes["default_action"] + attribute, exists := networkACL.Body.Attributes["default_action"] if !exists { runner.EmitIssue( r, "default_action is not defined in network_acls block", - networkAcl.DefRange, + networkACL.DefRange, ) continue } diff --git a/rules/azurerm_keyvault_network_acls_test.go b/rules/azurerm_keyvault_network_acls_test.go index 28016c8..94d8835 100644 --- a/rules/azurerm_keyvault_network_acls_test.go +++ b/rules/azurerm_keyvault_network_acls_test.go @@ -7,7 +7,7 @@ import ( "github.com/terraform-linters/tflint-plugin-sdk/helper" ) -func Test_AzurermKeyVaultNetworkAclsDefaultDeny(t *testing.T) { +func Test_AzurermKeyVaultNetworkACLsDefaultDeny(t *testing.T) { tests := []struct { Name string Content string @@ -20,7 +20,7 @@ resource "azurerm_key_vault" "example" { }`, Expected: helper.Issues{ { - Rule: NewAzurermKeyVaultNetworkAclsDefaultDeny(), + Rule: NewAzurermKeyVaultNetworkACLsDefaultDeny(), Message: "network_acls block is not defined, consider adding it with default_action = \"Deny\"", Range: hcl.Range{ Filename: "resource.tf", @@ -39,7 +39,7 @@ resource "azurerm_key_vault" "example" { }`, Expected: helper.Issues{ { - Rule: NewAzurermKeyVaultNetworkAclsDefaultDeny(), + Rule: NewAzurermKeyVaultNetworkACLsDefaultDeny(), Message: "default_action is not defined in network_acls block", Range: hcl.Range{ Filename: "resource.tf", @@ -59,7 +59,7 @@ resource "azurerm_key_vault" "example" { }`, Expected: helper.Issues{ { - Rule: NewAzurermKeyVaultNetworkAclsDefaultDeny(), + Rule: NewAzurermKeyVaultNetworkACLsDefaultDeny(), Message: "network_acls default_action should be set to \"Deny\"", Range: hcl.Range{ Filename: "resource.tf", @@ -81,7 +81,7 @@ resource "azurerm_key_vault" "example" { }, } - rule := NewAzurermKeyVaultNetworkAclsDefaultDeny() + rule := NewAzurermKeyVaultNetworkACLsDefaultDeny() for _, test := range tests { t.Run(test.Name, func(t *testing.T) {