From e21b2f12bb6e6f1a2343f47da67bd8f4b72e929e Mon Sep 17 00:00:00 2001 From: Preben Huybrechts Date: Thu, 31 Oct 2024 14:15:53 +0100 Subject: [PATCH] linux web app --- README.md | 5 +- main.go | 3 + rules/azurerm_linux_web_app_ftps_state.go | 87 +++++++++++++++++++ .../azurerm_linux_web_app_ftps_state_test.go | 75 ++++++++++++++++ ...urerm_linux_web_app_minimum_tls_version.go | 87 +++++++++++++++++++ ..._linux_web_app_minimum_tls_version_test.go | 74 ++++++++++++++++ 6 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 rules/azurerm_linux_web_app_ftps_state.go create mode 100644 rules/azurerm_linux_web_app_ftps_state_test.go create mode 100644 rules/azurerm_linux_web_app_minimum_tls_version.go create mode 100644 rules/azurerm_linux_web_app_minimum_tls_version_test.go diff --git a/README.md b/README.md index 6116369..8dc4170 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,10 @@ plugin "template" { |Name|Description|Severity|Enabled|Link| | --- | --- | --- | --- | --- | -|azurerm_storage_account_tls_version.go|Enforce TLS 1.2 on storage accounts |ERROR|✔|| +|azurerm_linux_web_app_ftps_state|Disable sftp to a linux web app |ERROR|✔|| +|azurerm_linux_web_app_minimum_tls_version|Enforce TLS 1.2 on linux web apps |ERROR|✔|| +|azurerm_mssql_database_transparent_data_encryption_enabled|Enforce transparant data encryption|ERROR|✔|| +|azurerm_storage_account_tls_version|Enforce TLS 1.2 on storage accounts |ERROR|✔|| ## Building the plugin diff --git a/main.go b/main.go index 7e0dd52..3aba763 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,9 @@ func main() { Name: "azurerm-security", Version: "0.1.0", Rules: []tflint.Rule{ + rules.NewAzurermLinuxWebAppFtpsState(), + rules.NewAzurermLinuxWebAppMinimumTlsVersion(), + rules.NewAzurermMssqlDatabaseEncryption(), rules.NewAzurermStorageAccountUnsecureTls(), }, }, diff --git a/rules/azurerm_linux_web_app_ftps_state.go b/rules/azurerm_linux_web_app_ftps_state.go new file mode 100644 index 0000000..83791c3 --- /dev/null +++ b/rules/azurerm_linux_web_app_ftps_state.go @@ -0,0 +1,87 @@ +package rules + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AzurermLinuxWebAppFtpsState checks if ftps_state is disabled +type AzurermLinuxWebAppFtpsState struct { + tflint.DefaultRule + + resourceType string + attributeName string + expectedValue string +} + +// NewAzurermLinuxWebAppFtpsState creates a new rule instance +func NewAzurermLinuxWebAppFtpsState() *AzurermLinuxWebAppFtpsState { + return &AzurermLinuxWebAppFtpsState{ + resourceType: "azurerm_linux_web_app", + attributeName: "ftps_state", + expectedValue: "Disabled", + } +} + +// Name returns the rule name +func (r *AzurermLinuxWebAppFtpsState) Name() string { + return "azurerm_linux_web_app_ftps_state" +} + +// Enabled returns whether the rule is enabled by default +func (r *AzurermLinuxWebAppFtpsState) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AzurermLinuxWebAppFtpsState) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AzurermLinuxWebAppFtpsState) Link() string { + return "" +} + +// Check verifies that ftps_state is set to "Disabled" +func (r *AzurermLinuxWebAppFtpsState) Check(runner tflint.Runner) error { + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + runner.EmitIssue( + r, + "ftps_state should be set to Disabled", + resource.DefRange, + ) + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func(val string) error { + if val != r.expectedValue { + runner.EmitIssue( + r, + fmt.Sprintf("ftps_state is set to %q, should be Disabled", val), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + + if err != nil { + return err + } + } + + return nil +} \ No newline at end of file diff --git a/rules/azurerm_linux_web_app_ftps_state_test.go b/rules/azurerm_linux_web_app_ftps_state_test.go new file mode 100644 index 0000000..95de24a --- /dev/null +++ b/rules/azurerm_linux_web_app_ftps_state_test.go @@ -0,0 +1,75 @@ +package rules + +import ( + "testing" + + hcl "github.com/hashicorp/hcl/v2" + "github.com/terraform-linters/tflint-plugin-sdk/helper" +) + +func Test_AzurermLinuxWebAppFtpsState(t *testing.T) { + tests := []struct { + Name string + Content string + Expected helper.Issues + }{ + { + Name: "FTPS enabled", + Content: ` +resource "azurerm_linux_web_app" "example" { + ftps_state = "Enabled" +}`, + Expected: helper.Issues{ + { + Rule: NewAzurermLinuxWebAppFtpsState(), + Message: `ftps_state is set to "Enabled", should be Disabled`, + Range: hcl.Range{ + Filename: "resource.tf", + Start: hcl.Pos{Line: 3, Column: 18}, + End: hcl.Pos{Line: 3, Column: 27}, + }, + }, + }, + }, + { + Name: "FTPS state missing", + Content: ` +resource "azurerm_linux_web_app" "example" { +}`, + Expected: helper.Issues{ + { + Rule: NewAzurermLinuxWebAppFtpsState(), + Message: `ftps_state should be set to Disabled`, + Range: hcl.Range{ + Filename: "resource.tf", + Start: hcl.Pos{Line: 2, Column: 1}, + End: hcl.Pos{Line: 2, Column: 43}, + }, + }, + }, + }, + { + Name: "FTPS disabled", + Content: ` +resource "azurerm_linux_web_app" "example" { + ftps_state = "Disabled" +}`, + Expected: helper.Issues{}, + }, + } + + rule := NewAzurermLinuxWebAppFtpsState() + + 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_linux_web_app_minimum_tls_version.go b/rules/azurerm_linux_web_app_minimum_tls_version.go new file mode 100644 index 0000000..5746be5 --- /dev/null +++ b/rules/azurerm_linux_web_app_minimum_tls_version.go @@ -0,0 +1,87 @@ +package rules + +import ( + "fmt" + + "github.com/terraform-linters/tflint-plugin-sdk/hclext" + "github.com/terraform-linters/tflint-plugin-sdk/tflint" +) + +// AzurermLinuxWebAppMinimumTlsVersion checks that minimum_tls_version is set to at least "1.2" +type AzurermLinuxWebAppMinimumTlsVersion struct { + tflint.DefaultRule + + resourceType string + attributeName string + version string +} + +// NewAzurermLinuxWebAppMinimumTlsVersion returns a new rule instance +func NewAzurermLinuxWebAppMinimumTlsVersion() *AzurermLinuxWebAppMinimumTlsVersion { + return &AzurermLinuxWebAppMinimumTlsVersion{ + resourceType: "azurerm_linux_web_app", + attributeName: "minimum_tls_version", + version: "1.2", + } +} + +// Name returns the rule name +func (r *AzurermLinuxWebAppMinimumTlsVersion) Name() string { + return "azurerm_linux_web_app_minimum_tls_version" +} + +// Enabled returns whether the rule is enabled by default +func (r *AzurermLinuxWebAppMinimumTlsVersion) Enabled() bool { + return true +} + +// Severity returns the rule severity +func (r *AzurermLinuxWebAppMinimumTlsVersion) Severity() tflint.Severity { + return tflint.ERROR +} + +// Link returns the rule reference link +func (r *AzurermLinuxWebAppMinimumTlsVersion) Link() string { + return "" +} + +// Check verifies that minimum_tls_version is at least "1.2" +func (r *AzurermLinuxWebAppMinimumTlsVersion) Check(runner tflint.Runner) error { + resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ + Attributes: []hclext.AttributeSchema{ + {Name: r.attributeName}, + }, + }, nil) + if err != nil { + return err + } + + for _, resource := range resources.Blocks { + attribute, exists := resource.Body.Attributes[r.attributeName] + if !exists { + // Emit issue if minimum_tls_version attribute is missing + runner.EmitIssue( + r, + fmt.Sprintf("%s is missing, should be set to %s or higher", r.attributeName, r.version), + resource.DefRange, + ) + continue + } + + err := runner.EvaluateExpr(attribute.Expr, func(val string) error { + if val != r.version { + runner.EmitIssue( + r, + fmt.Sprintf("%s is set to %s, should be %s or higher", r.attributeName, val, r.version), + attribute.Expr.Range(), + ) + } + return nil + }, nil) + if err != nil { + return err + } + } + + return nil +} diff --git a/rules/azurerm_linux_web_app_minimum_tls_version_test.go b/rules/azurerm_linux_web_app_minimum_tls_version_test.go new file mode 100644 index 0000000..3731d53 --- /dev/null +++ b/rules/azurerm_linux_web_app_minimum_tls_version_test.go @@ -0,0 +1,74 @@ +package rules + +import ( + "testing" + + hcl "github.com/hashicorp/hcl/v2" + "github.com/terraform-linters/tflint-plugin-sdk/helper" +) + +func Test_AzurermLinuxWebAppMinimumTlsVersion(t *testing.T) { + tests := []struct { + Name string + Content string + Expected helper.Issues + }{ + { + Name: "minimum_tls_version below 1.2", + Content: ` +resource "azurerm_linux_web_app" "example" { + minimum_tls_version = "1.0" +}`, + Expected: helper.Issues{ + { + Rule: NewAzurermLinuxWebAppMinimumTlsVersion(), + Message: "minimum_tls_version is set to 1.0, should be 1.2 or higher", + Range: hcl.Range{ + Filename: "resource.tf", + Start: hcl.Pos{Line: 3, Column: 27}, + End: hcl.Pos{Line: 3, Column: 32}, + }, + }, + }, + }, + { + Name: "minimum_tls_version set to 1.2", + Content: ` +resource "azurerm_linux_web_app" "example" { + minimum_tls_version = "1.2" +}`, + Expected: helper.Issues{}, + }, + { + Name: "minimum_tls_version attribute missing", + Content: ` +resource "azurerm_linux_web_app" "example" { +}`, + Expected: helper.Issues{ + { + Rule: NewAzurermLinuxWebAppMinimumTlsVersion(), + Message: "minimum_tls_version is missing, should be set to 1.2 or higher", + Range: hcl.Range{ + Filename: "resource.tf", + Start: hcl.Pos{Line: 2, Column: 1}, + End: hcl.Pos{Line: 2, Column: 43}, + }, + }, + }, + }, + } + + rule := NewAzurermLinuxWebAppMinimumTlsVersion() + + 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) + }) + } +}