Repository: aquasecurity/tfsec
Pull request #1063 (2021-08-31 19:57:57)

Added multiple Azure scans

brandon-bailey-rc: > Hey @brandon-bailey - this is great - much appreciated.
> 
> Its failing on the linter (looks like it just wants the first link to be the terraform documentation link)
> 
> ```
> make pr-ready
> ```

Okay, I have added the terraform documentation links to the relevant files!

Patch:
diff --git a/internal/app/tfsec/rules/azure/appservice/detailed_error_messages_enabled_rule.go b/internal/app/tfsec/rules/azure/appservice/detailed_error_messages_enabled_rule.go
new file mode 100644
index 000000000..1a109eba1
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/detailed_error_messages_enabled_rule.go
@@ -0,0 +1,64 @@
+package appservice
+
+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:   "appservice",
+		ShortCode: "detailed-error-messages-enabled",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "App service disables detailed error messages",
+			Explanation: `Copies of the .htm error pages that would have been sent to the client browser. For security reasons, detailed error pages shouldn't be sent to clients in production, but App Service can save the error page each time an application error occurs that has HTTP code 400 or greater. The page may contain information that can help determine why the server returns the error code.`,
+			Impact:      "Missing crucial details in the error messages",
+			Resolution:  "Enable detailed_error_messages_enabled",
+			BadExample: []string{`
+resource "azurerm_app_service" "bad_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_app_service" "good_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+  detailed_error_messages_enabled = true
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service#detailed_error_messages_enabled",
+				"https://docs.microsoft.com/en-us/azure/app-service/troubleshoot-diagnostic-logs",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_app_service",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			detailedErrorMessages := resourceBlock.GetAttribute("detailed_error_messages_enabled")
+			if detailedErrorMessages.IsNil() {
+				set.AddResult().
+					WithDescription("Resource '%s' is missing the detailed_error_messages_enabled attribute", resourceBlock.FullName())
+			}
+			if detailedErrorMessages.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have detailed_error_messages_enabled set to true", resourceBlock.FullName()).
+					WithAttribute(detailedErrorMessages)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/dotnet_framework_version_rule.go b/internal/app/tfsec/rules/azure/appservice/dotnet_framework_version_rule.go
new file mode 100644
index 000000000..591d6e709
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/dotnet_framework_version_rule.go
@@ -0,0 +1,86 @@
+package appservice
+
+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:   "appservice",
+		ShortCode: "dotnet-framework-version",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Azure App Service Web app does not use the latest .Net Core version",
+			Explanation: `Azure App Service web applications developed with the .NET software stack should use the latest available version of .NET to ensure the latest security fixes are in use.`,
+			Impact:      "Outdated .NET could contain open vulnerabilities",
+			Resolution:  "Use the latest version of the .NET framework",
+			BadExample: []string{`
+resource "azurerm_app_service" "bad_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+}
+`,
+				`
+resource "azurerm_app_service" "bad_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+
+  site_config {
+	dotnet_framework_version = "v4.0"
+  }
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_app_service" "good_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+
+  site_config {
+	dotnet_framework_version = "v5.0"
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service#dotnet_framework_version",
+				"https://docs.microsoft.com/en-us/azure/app-service/configure-language-dotnetcore",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_app_service",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			if resourceBlock.MissingChild("site_config") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have a value for site_config block", resourceBlock.FullName())
+			}
+			siteConfig := resourceBlock.GetBlock("site_config")
+			if siteConfig.MissingChild("dotnet_framework_version") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have a value for site_config.dotnet_framework_version", resourceBlock.FullName())
+			}
+
+			dotNetFramework := siteConfig.GetAttribute("dotnet_framework_version")
+
+			if dotNetFramework.NotEqual("v5.0") || dotNetFramework.IsNil() {
+				set.AddResult().
+					WithDescription("Resource '%s' is configured with incorrect values", resourceBlock.FullName()).
+					WithAttribute(dotNetFramework)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/failed_request_tracing_enabled_rule.go b/internal/app/tfsec/rules/azure/appservice/failed_request_tracing_enabled_rule.go
new file mode 100644
index 000000000..a23357cf9
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/failed_request_tracing_enabled_rule.go
@@ -0,0 +1,75 @@
+package appservice
+
+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:   "appservice",
+		ShortCode: "failed-request-tracing-enabled",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "App service does not enable failed request tracing",
+			Explanation: `Detailed tracing information on failed requests, including a trace of the IIS components used to process the request and the time taken in each component. It's useful if you want to improve site performance or isolate a specific HTTP error. One folder is generated for each failed request, which contains the XML log file, and the XSL stylesheet to view the log file with.`,
+			Impact:      "Logging of failed request tracing will not be logged",
+			Resolution:  "Enable failed_request_tracing_enabled",
+			BadExample: []string{`
+resource "azurerm_app_service" "bad_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_app_service" "good_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+
+  logs {
+    failed_request_tracing_enabled = true
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service#failed_request_tracing_enabled",
+				"https://docs.microsoft.com/en-us/azure/app-service/troubleshoot-diagnostic-logs",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_app_service",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			if resourceBlock.MissingChild("logs") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logs enabled", resourceBlock.FullName())
+				return
+			}
+
+			logProps := resourceBlock.GetBlock("logs")
+			if logProps.MissingChild("failed_request_tracing_enabled") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logs.failed_request_tracing_enabled block", resourceBlock.FullName()).WithBlock(logProps)
+				return
+			}
+			failedTracing := logProps.GetAttribute("failed_request_tracing_enabled")
+			if failedTracing.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logs.failed_request_tracing_enabled set to true", resourceBlock.FullName()).
+					WithAttribute(failedTracing)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/ftp_deployments_disabled_rule.go b/internal/app/tfsec/rules/azure/appservice/ftp_deployments_disabled_rule.go
new file mode 100644
index 000000000..db887d134
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/ftp_deployments_disabled_rule.go
@@ -0,0 +1,71 @@
+package appservice
+
+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:   "appservice",
+		ShortCode: "ftp-deployments-disabled",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure FTP Deployments are disabled",
+			Explanation: `FTPS (Secure FTP) is used to enhance security for Azure web application using App Service as it adds an extra layer of security to the FTP protocol, and help you to comply with the industry standards and regulations. For enhanced security, it is highly advices to use FTP over TLS/SSL only. You can also disable both FTP and FTPS if you don't use FTP deployment.`,
+			Impact:      "FTP is insecure and can lead to loss of data",
+			Resolution:  "Disable FTP",
+			BadExample: []string{`
+resource "azurerm_app_service" "bad_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_app_service" "good_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+  ftps_state = "Disabled"
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service#ftps_state",
+				"https://docs.microsoft.com/en-us/azure/app-service/deploy-ftp",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_app_service",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+
+			if ftpsState := resourceBlock.GetAttribute("ftps_state"); ftpsState.IsNil() {
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for ftps_state.", resourceBlock.FullName())
+				return
+			} else if ftpsState.IsAny("FtpsOnly", "AllAllowed") {
+				set.AddResult().
+					WithDescription("Resource '%s' has an ftps state which enables FTP/FTPS.", resourceBlock.FullName()).
+					WithAttribute(ftpsState)
+			} else if ftpsState.Equals("Disabled") {
+				return
+			} else {
+				set.AddResult().
+					WithDescription("Resource '%s' has a value for ftps_state that is not one of the possible values.", resourceBlock.FullName()).
+					WithAttribute(ftpsState)
+			}
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/http_logs_enabled_rule.go b/internal/app/tfsec/rules/azure/appservice/http_logs_enabled_rule.go
new file mode 100644
index 000000000..b509176c9
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/http_logs_enabled_rule.go
@@ -0,0 +1,71 @@
+package appservice
+
+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:   "appservice",
+		ShortCode: "http-logs-enabled",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "App service does not enable HTTP logging",
+			Explanation: `Raw HTTP request data in the W3C extended log file format. Each log message includes data such as the HTTP method, resource URI, client IP, client port, user agent, response code, and so on.`,
+			Impact:      "Missed logs related to HTTP requests",
+			Resolution:  "Enable http_logs",
+			BadExample: []string{`
+resource "azurerm_app_service" "bad_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_app_service" "good_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+  logs {
+    http_logs {
+      retention_in_days = 4
+      retention_in_mb = 10
+    }
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service#http_logs",
+				"https://docs.microsoft.com/en-us/azure/app-service/troubleshoot-diagnostic-logs",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_app_service",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+
+			if resourceBlock.MissingChild("logs") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logs enabled", resourceBlock.FullName())
+				return
+			}
+			logProps := resourceBlock.GetBlock("logs")
+			if logProps.MissingChild("http_logs") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logs.http_logs enabled", resourceBlock.FullName()).WithBlock(logProps)
+			}
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/php_version_rule.go b/internal/app/tfsec/rules/azure/appservice/php_version_rule.go
new file mode 100644
index 000000000..96a4c924e
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/php_version_rule.go
@@ -0,0 +1,74 @@
+package appservice
+
+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:   "appservice",
+		ShortCode: "php-version",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Azure App Service Web app does not use the latest PHP version",
+			Explanation: `Azure App Service web applications developed with the PHP should use the latest available version of PHP to ensure the latest security fixes are in use.`,
+			Impact:      "Old PHP Versions can contain vulnerabilities which lead to compromised Web Applications",
+			Resolution:  "Ensure Latest PHP Version is being used",
+			BadExample: []string{`
+resource "azurerm_app_service" "good_example" {
+	name                = "example-app-service"
+	location            = azurerm_resource_group.example.location
+	resource_group_name = azurerm_resource_group.example.name
+	app_service_plan_id = azurerm_app_service_plan.example.id
+	site_config {
+	  php_version = "7.3"
+	}
+  }
+`},
+			GoodExample: []string{`
+resource "azurerm_app_service" "good_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+  site_config {
+    php_version = "7.4"
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service#php_version",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_app_service",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			if resourceBlock.MissingChild("site_config") {
+				return
+			}
+			// We are only running this check if the php_version tag is set, if the app service is not using php we should not count this against them
+			if resourceBlock.GetBlock("site_config").HasBlock("php_version") {
+				if phpVersionAttr := resourceBlock.GetBlock("site_config").GetAttribute("php_version"); phpVersionAttr.NotEqual("7.4") {
+					set.AddResult().
+						WithDescription("Resource '%s' does not have site_config.php_version set to 7.4 which is the latest version", resourceBlock.FullName()).
+						WithAttribute(phpVersionAttr)
+				} else {
+					return
+				}
+			} else {
+				return
+			}
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/python_version_rule.go b/internal/app/tfsec/rules/azure/appservice/python_version_rule.go
new file mode 100644
index 000000000..b288c0261
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/python_version_rule.go
@@ -0,0 +1,74 @@
+package appservice
+
+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:   "appservice",
+		ShortCode: "python-version",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Azure App Service Web app does not use the latest Python version",
+			Explanation: `Azure App Service web applications developed with the Python should use the latest available version of Python to ensure the latest security fixes are in use.`,
+			Impact:      "Old Python Versions can contain vulnerabilities which lead to compromised Web Applications",
+			Resolution:  "Ensure Latest Python Version is being used",
+			BadExample: []string{`
+resource "azurerm_app_service" "good_example" {
+	name                = "example-app-service"
+	location            = azurerm_resource_group.example.location
+	resource_group_name = azurerm_resource_group.example.name
+	app_service_plan_id = azurerm_app_service_plan.example.id
+	site_config {
+	  python_version = "2.7"
+	}
+  }
+`},
+			GoodExample: []string{`
+resource "azurerm_app_service" "good_example" {
+  name                = "example-app-service"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+  site_config {
+    python_version = "3.4"
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service#python_version",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_app_service",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			if resourceBlock.MissingChild("site_config") {
+				return
+			}
+			// We are only running this check if the python_version tag is set, if the app service is not using python we should not count this against them
+			if resourceBlock.GetBlock("site_config").HasBlock("python_version") {
+				if pythonVersionAttr := resourceBlock.GetBlock("site_config").GetAttribute("python_version"); pythonVersionAttr.NotEqual("3.4") {
+					set.AddResult().
+						WithDescription("Resource '%s' does not have site_config.python_version set to 3.4 which is the latest version", resourceBlock.FullName()).
+						WithAttribute(pythonVersionAttr)
+				} else {
+					return
+				}
+			} else {
+				return
+			}
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/functionapp/enable_http2_rule.go b/internal/app/tfsec/rules/azure/functionapp/enable_http2_rule.go
new file mode 100644
index 000000000..9b911f586
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/functionapp/enable_http2_rule.go
@@ -0,0 +1,74 @@
+package functionapp
+
+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:   "functionapp",
+		ShortCode: "enable-http2",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Web App uses the latest HTTP version",
+			Explanation: `Use the latest version of HTTP to ensure you are benefiting from security fixes`,
+			Impact:      "Outdated versions of HTTP has security vulnerabilities",
+			Resolution:  "Use the latest version of HTTP",
+			BadExample: []string{`
+resource "azurerm_function_app" "bad_example" {
+  name                = "example-function-app"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+}
+`,
+				`
+resource "azurerm_function_app" "bad_example" {
+  name                = "example-function-app"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+  site_config {
+	  http2_enabled = false
+  }
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_function_app" "good_example" {
+  name                = "example-function-app"
+  location            = azurerm_resource_group.example.location
+  resource_group_name = azurerm_resource_group.example.name
+  app_service_plan_id = azurerm_app_service_plan.example.id
+  site_config {
+	  http2_enabled = true
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/function_app#http2_enabled",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"azurerm_function_app",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, module block.Module) {
+			if http2EnabledAttr := resourceBlock.GetBlock("site_config").GetAttribute("http2_enabled"); http2EnabledAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for site_config.http2_enabled", resourceBlock.FullName())
+			} else if http2EnabledAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' has attribute site_config.http2_enabled that is false", resourceBlock.FullName()).
+					WithAttribute(http2EnabledAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/securitycenter/defender_on_container_registry_rule.go b/internal/app/tfsec/rules/azure/securitycenter/defender_on_container_registry_rule.go
new file mode 100644
index 000000000..5c850f04a
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/securitycenter/defender_on_container_registry_rule.go
@@ -0,0 +1,61 @@
+package securitycenter
+
+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:   "security-center",
+		ShortCode: "defender-on-container",
+		Documentation: rule.RuleDocumentation{
+			Summary: "Ensure Azure Defender is set to On for container registries",
+			Explanation: `Azure Defender is a cloud workload protection service that utilizes and agent-based deployment to analyze signals from Azure network fabric and the service control plane, to detect threats across all Azure resources. It can also analyze non-Azure resources, utilizing Azure Arc, including those on-premises and in both AWS and GCP (once they've been onboarded).
+			Azure Defender for container registries includes a vulnerability scanner to scan the images in Azure Resource Manager-based Azure Container Registry registries and provide deeper visibility image vulnerabilities.`,
+			Impact:     "Not enabling defender for container registries could lead to compromised account",
+			Resolution: "Enable ContainerRegistry in Azure Defender",
+			BadExample: []string{`
+resource "azurerm_security_center_subscription_pricing" "bad_example" {
+  tier          = "Free"
+  resource_type = "VirtualMachines"
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_security_center_subscription_pricing" "good_example" {
+  tier          = "Standard"
+  resource_type = "VirtualMachines,ContainerRegistry"
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/security_center_subscription_pricing#resource_type",
+				"https://docs.microsoft.com/en-us/azure/security-center/defender-for-container-registries-introduction",
+			},
+		},
+		Provider:        provider.AzureProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"azurerm_security_center_subscription_pricing"},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ block.Module) {
+
+			if resourceBlock.MissingChild("resource_type") {
+				return
+			}
+
+			resourceTypeAttr := resourceBlock.GetAttribute("resource_type")
+			if !resourceTypeAttr.Contains("ContainerRegistry", block.IgnoreCase) {
+				set.AddResult().
+					WithDescription("Resource '%s' does not contain ContainerRegistry", resourceBlock.FullName()).
+					WithAttribute(resourceTypeAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/azure/storage/container_activity_logs_not_public_rule.go b/internal/app/tfsec/rules/azure/storage/container_activity_logs_not_public_rule.go
new file mode 100644
index 000000000..55c49873c
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/storage/container_activity_logs_not_public_rule.go
@@ -0,0 +1,59 @@
+package storage
+
+// generator-locked
+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{
+		Service:   "storage",
+		ShortCode: "container-activity-logs-not-public",
+		Documentation: rule.RuleDocumentation{
+			Summary:    "Ensure public access level for Blob Containers is set to private",
+			Impact:     "Data in the storage container could be exposed publicly",
+			Resolution: "Disable public access to storage containers",
+			Explanation: `
+			Anonymous, public read access to a container and its blobs can be enabled in Azure Blob storage. It grants read-only access to these resources without sharing the account key or requiring a shared access signature.
+
+			We recommend you do not provide anonymous access to blob containers until, and unless, it is strongly desired. A shared access signature token should be used for providing controlled and timed access to blob containers.`,
+			BadExample: []string{`
+resource "azurerm_storage_container" "bad_example" {
+	name                  = "terraform-container-storage"
+	container_access_type = "public"
+}
+`},
+			GoodExample: []string{`
+resource "azurerm_storage_container" "good_example" {
+	name                  = "terraform-container-storage"
+	container_access_type = "private"
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container#container_access_type",
+			},
+		},
+		Provider:        provider.AzureProvider,
+		RequiredTypes:   []string{"resource"},
+		RequiredLabels:  []string{"azurerm_storage_container"},
+		DefaultSeverity: severity.Critical,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ block.Module) {
+
+			if resourceBlock.HasChild("container_access_type") {
+				httpsOnlyAttr := resourceBlock.GetAttribute("container_access_type")
+				if httpsOnlyAttr.NotEqual("private") {
+					set.AddResult().
+						WithDescription("Resource '%s' does not have private access level to blob containers.", resourceBlock.FullName())
+				}
+			} else {
+				return
+			}
+
+		},
+	})
+}


Test patch:
diff --git a/internal/app/tfsec/rules/azure/appservice/detailed_error_messages_enabled_rule_test.go b/internal/app/tfsec/rules/azure/appservice/detailed_error_messages_enabled_rule_test.go
new file mode 100644
index 000000000..11450afae
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/detailed_error_messages_enabled_rule_test.go
@@ -0,0 +1,53 @@
+package appservice
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureDetailedErrorMessagesEnabled_FailureExamples(t *testing.T) {
+	expectedCode := "azure-appservice-detailed-error-messages-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_AzureDetailedErrorMessagesEnabled_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-appservice-detailed-error-messages-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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/dotnet_framework_version_rule_test.go b/internal/app/tfsec/rules/azure/appservice/dotnet_framework_version_rule_test.go
new file mode 100644
index 000000000..9e58ba21e
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/dotnet_framework_version_rule_test.go
@@ -0,0 +1,53 @@
+package appservice
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureDotnetFrameworkVersion_FailureExamples(t *testing.T) {
+	expectedCode := "azure-appservice-dotnet-framework-version"
+
+	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_AzureDotnetFrameworkVersion_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-appservice-dotnet-framework-version"
+
+	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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/failed_request_tracing_enabled_rule_test.go b/internal/app/tfsec/rules/azure/appservice/failed_request_tracing_enabled_rule_test.go
new file mode 100644
index 000000000..85a5661b2
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/failed_request_tracing_enabled_rule_test.go
@@ -0,0 +1,53 @@
+package appservice
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureFailedRequestTracingEnabled_FailureExamples(t *testing.T) {
+	expectedCode := "azure-appservice-failed-request-tracing-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_AzureFailedRequestTracingEnabled_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-appservice-failed-request-tracing-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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/ftp_deployments_disabled_rule_test.go b/internal/app/tfsec/rules/azure/appservice/ftp_deployments_disabled_rule_test.go
new file mode 100644
index 000000000..a548dd4b5
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/ftp_deployments_disabled_rule_test.go
@@ -0,0 +1,53 @@
+package appservice
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureFtpDeploymentsDisabled_FailureExamples(t *testing.T) {
+	expectedCode := "azure-appservice-ftp-deployments-disabled"
+
+	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_AzureFtpDeploymentsDisabled_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-appservice-ftp-deployments-disabled"
+
+	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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/http_logs_enabled_rule_test.go b/internal/app/tfsec/rules/azure/appservice/http_logs_enabled_rule_test.go
new file mode 100644
index 000000000..99604a094
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/http_logs_enabled_rule_test.go
@@ -0,0 +1,53 @@
+package appservice
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureHttpLogsEnabled_FailureExamples(t *testing.T) {
+	expectedCode := "azure-appservice-http-logs-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_AzureHttpLogsEnabled_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-appservice-http-logs-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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/php_version_rule_test.go b/internal/app/tfsec/rules/azure/appservice/php_version_rule_test.go
new file mode 100644
index 000000000..1a6ff0ecc
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/php_version_rule_test.go
@@ -0,0 +1,53 @@
+package appservice
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzurePhpVersion_FailureExamples(t *testing.T) {
+	expectedCode := "azure-appservice-php-version"
+
+	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_AzurePhpVersion_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-appservice-php-version"
+
+	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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/appservice/python_version_rule_test.go b/internal/app/tfsec/rules/azure/appservice/python_version_rule_test.go
new file mode 100644
index 000000000..c3721fb6f
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/appservice/python_version_rule_test.go
@@ -0,0 +1,53 @@
+package appservice
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzurePythonVersion_FailureExamples(t *testing.T) {
+	expectedCode := "azure-appservice-python-version"
+
+	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_AzurePythonVersion_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-appservice-python-version"
+
+	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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/functionapp/enable_http2_rule_test.go b/internal/app/tfsec/rules/azure/functionapp/enable_http2_rule_test.go
new file mode 100644
index 000000000..bd51961ae
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/functionapp/enable_http2_rule_test.go
@@ -0,0 +1,53 @@
+package functionapp
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureEnableHttp2_FailureExamples(t *testing.T) {
+	expectedCode := "azure-functionapp-enable-http2"
+
+	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_AzureEnableHttp2_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-functionapp-enable-http2"
+
+	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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/securitycenter/defender_on_container_registry_rule_test.go b/internal/app/tfsec/rules/azure/securitycenter/defender_on_container_registry_rule_test.go
new file mode 100644
index 000000000..dcc375649
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/securitycenter/defender_on_container_registry_rule_test.go
@@ -0,0 +1,53 @@
+package securitycenter
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureDefenderOnContainer_FailureExamples(t *testing.T) {
+	expectedCode := "azure-security-center-defender-on-container"
+
+	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_AzureDefenderOnContaienr_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-security-center-defender-on-container"
+
+	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)
+	}
+}
diff --git a/internal/app/tfsec/rules/azure/storage/container_activity_logs_not_public_rule_test.go b/internal/app/tfsec/rules/azure/storage/container_activity_logs_not_public_rule_test.go
new file mode 100644
index 000000000..055776bc2
--- /dev/null
+++ b/internal/app/tfsec/rules/azure/storage/container_activity_logs_not_public_rule_test.go
@@ -0,0 +1,53 @@
+package storage
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AzureContainerActivityLogsNotPublic_FailureExamples(t *testing.T) {
+	expectedCode := "azure-storage-container-activity-logs-not-public"
+
+	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_AzureContainerActivityLogsNotPublic_SuccessExamples(t *testing.T) {
+	expectedCode := "azure-storage-container-activity-logs-not-public"
+
+	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)
+	}
+}