Repository: aquasecurity/tfsec
Pull request #1226 (2021-12-30 21:54:28)

Azure monitor - convert to use defsec logic
Closes: https://github.com/aquasecurity/tfsec/issues/1225


Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 105dbf262..a47c4668a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -42,7 +42,7 @@ Find your new check and the associated test in one of the subfolders of `interna
 
 Here's an example:
 
-You need to tell the scanner about your check; this is done by calling an init() function with the following code:
+You need to tell the scanner about your check; this is done by calling an `init()` function with the following code:
 
 ```go
 func init() {
@@ -68,27 +68,11 @@ hackable = false
 		RequiredTypes:  []string{"resource"},
 		// the type of resource(s) you want to target
 		RequiredLabels: []string{"aws_gibson"},
-		// the actual logic for your check
-		CheckTerraform: func(block block.Block, module block.Module) (results rules.Results){
-			// TODO: add check logic here
-			return results
-		},
 	})
 }
 ```
 
-Now all that's left is writing the logic itself. You'll likely find it useful here to learn from preexisting check code, but the logic is usually fairly minimal. Here's a basic example:
-
-```go
-...
-
-		CheckTerraform: func(block block.Block, module block.Module) (results rules.Results){
-			if attr := block.GetAttribute("hackable"); attr.IsTrue() {
-				results.Add("The Gibson '%s' is configured to be hackable.", attr)
-			}
-		},
-...
-```
+Now all that's left is writing the logic itself. This has been moved to [defsec](https://github.com/aquasecurity/defsec). You need to make sure that there's an adapter for the resource. You can see [aws/ec2/adapter.go](https://github.com/aquasecurity/tfsec/blob/master/internal/app/tfsec/adapter/aws/ec2/adapt.go) for an example.
 
 You can see a good example of a real check file [here](https://github.com/aquasecurity/tfsec/blob/master/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go).
 This check also provides [tests](https://github.com/aquasecurity/tfsec/blob/master/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule_test.go) and uses provided data checks like `cidr.IsAttributeOpen()` provided [here](https://github.com/aquasecurity/tfsec/blob/master/internal/app/tfsec/cidr/cidr.go).
@@ -99,10 +83,8 @@ There is no longer a need to create dedicated tests for new checks - the `BadExa
 
 The first example that you add for Good and Bad will be used in the documentation, additional blocks you want to be tested to to verify the check should be added afterwards.
 
-
 And that's it! If you have any difficulties, please feel free to raise a draft PR and note any questions/problems in the description and we'll do our best to help you out.
 
-
 ### Submitting the PR
 
 When you are ready to submit the PR for review, please run 
diff --git a/internal/app/tfsec/adapter/azure/appservice/adapt.go b/internal/app/tfsec/adapter/azure/appservice/adapt.go
index 5ea9e6139..f317304fb 100644
--- a/internal/app/tfsec/adapter/azure/appservice/adapt.go
+++ b/internal/app/tfsec/adapter/azure/appservice/adapt.go
@@ -2,9 +2,91 @@ package appservice
 
 import (
 	"github.com/aquasecurity/defsec/provider/azure/appservice"
+	"github.com/aquasecurity/defsec/types"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 )
 
 func Adapt(modules []block.Module) appservice.AppService {
-	return appservice.AppService{}
+	return appservice.AppService{
+		Services:     adaptServices(modules),
+		FunctionApps: adaptFunctionApps(modules),
+	}
+}
+
+func adaptServices(modules []block.Module) []appservice.Service {
+	var services []appservice.Service
+
+	for _, module := range modules {
+		for _, resource := range module.GetResourcesByType("azurerm_app_service") {
+			services = append(services, adaptService(resource))
+		}
+	}
+	return services
+}
+
+func adaptFunctionApps(modules []block.Module) []appservice.FunctionApp {
+	var functionApps []appservice.FunctionApp
+
+	for _, module := range modules {
+		for _, resource := range module.GetResourcesByType("azurerm_function_app") {
+			functionApps = append(functionApps, adaptFunctionApp(resource))
+		}
+	}
+	return functionApps
+}
+
+func adaptService(resource block.Block) appservice.Service {
+	enableClientCertAttr := resource.GetAttribute("client_cert_enabled")
+	enableClientCertVal := enableClientCertAttr.AsBoolValueOrDefault(false, resource)
+
+	identityBlock := resource.GetBlock("identity")
+	typeVal := types.String("", *resource.GetMetadata())
+	if identityBlock.IsNotNil() {
+		typeAttr := identityBlock.GetAttribute("type")
+		typeVal = typeAttr.AsStringValueOrDefault("", identityBlock)
+	}
+
+	authBlock := resource.GetBlock("auth_settings")
+	enabledVal := types.Bool(false, *resource.GetMetadata())
+	if authBlock.IsNotNil() {
+		enabledAttr := authBlock.GetAttribute("enabled")
+		enabledVal = enabledAttr.AsBoolValueOrDefault(false, authBlock)
+	}
+
+	siteBlock := resource.GetBlock("site_config")
+	enableHTTP2Val := types.Bool(false, *resource.GetMetadata())
+	minTLSVersionVal := types.String("1.2", *resource.GetMetadata())
+	if siteBlock.IsNotNil() {
+		enableHTTP2Attr := siteBlock.GetAttribute("http2_enabled")
+		enableHTTP2Val = enableHTTP2Attr.AsBoolValueOrDefault(false, siteBlock)
+
+		minTLSVersionAttr := siteBlock.GetAttribute("min_tls_version")
+		minTLSVersionVal = minTLSVersionAttr.AsStringValueOrDefault("1.2", siteBlock)
+	}
+
+	return appservice.Service{
+		EnableClientCert: enableClientCertVal,
+		Identity: struct{ Type types.StringValue }{
+			Type: typeVal,
+		},
+		Authentication: struct{ Enabled types.BoolValue }{
+			Enabled: enabledVal,
+		},
+		Site: struct {
+			EnableHTTP2       types.BoolValue
+			MinimumTLSVersion types.StringValue
+		}{
+			EnableHTTP2:       enableHTTP2Val,
+			MinimumTLSVersion: minTLSVersionVal,
+		},
+	}
+}
+
+func adaptFunctionApp(resource block.Block) appservice.FunctionApp {
+	HTTPSOnlyAttr := resource.GetAttribute("https_only")
+	HTTPSOnlyVal := HTTPSOnlyAttr.AsBoolValueOrDefault(false, resource)
+
+	return appservice.FunctionApp{
+		HTTPSOnly: HTTPSOnlyVal,
+	}
 }
diff --git a/internal/app/tfsec/adapter/azure/authorization/adapt.go b/internal/app/tfsec/adapter/azure/authorization/adapt.go
index d5834a779..d85eea439 100644
--- a/internal/app/tfsec/adapter/azure/authorization/adapt.go
+++ b/internal/app/tfsec/adapter/azure/authorization/adapt.go
@@ -2,9 +2,51 @@ package authorization
 
 import (
 	"github.com/aquasecurity/defsec/provider/azure/authorization"
+	"github.com/aquasecurity/defsec/types"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 )
 
 func Adapt(modules []block.Module) authorization.Authorization {
-	return authorization.Authorization{}
+	return authorization.Authorization{
+		RoleDefinitions: adaptRoleDefinitions(modules),
+	}
+}
+
+func adaptRoleDefinitions(modules []block.Module) []authorization.RoleDefinition {
+	var roleDefinitions []authorization.RoleDefinition
+	for _, module := range modules {
+		for _, resource := range module.GetResourcesByType("azurerm_role_definition") {
+			roleDefinitions = append(roleDefinitions, adaptRoleDefinition(resource))
+		}
+	}
+	return roleDefinitions
+}
+
+func adaptRoleDefinition(resource block.Block) authorization.RoleDefinition {
+	permissionsBlocks := resource.GetBlocks("permissions")
+	var permissionsVal []authorization.Permission
+
+	for _, permissionsBlock := range permissionsBlocks {
+		actionsAttr := permissionsBlock.GetAttribute("actions")
+		var actionsVal []types.StringValue
+		actions := actionsAttr.ValueAsStrings()
+		for _, action := range actions {
+			actionsVal = append(actionsVal, types.String(action, *permissionsBlock.GetMetadata()))
+		}
+		permissionsVal = append(permissionsVal, authorization.Permission{
+			Actions: actionsVal,
+		})
+	}
+
+	assignableScopesAttr := resource.GetAttribute("assignable_scopes")
+	var assignableScopesVal []types.StringValue
+	assignableScopes := assignableScopesAttr.ValueAsStrings()
+	for _, scope := range assignableScopes {
+		assignableScopesVal = append(assignableScopesVal, types.String(scope, *resource.GetMetadata()))
+	}
+
+	return authorization.RoleDefinition{
+		Permissions:      permissionsVal,
+		AssignableScopes: assignableScopesVal,
+	}
 }
diff --git a/internal/app/tfsec/adapter/azure/compute/adapt.go b/internal/app/tfsec/adapter/azure/compute/adapt.go
index daa79c1bf..d95d9e160 100644
--- a/internal/app/tfsec/adapter/azure/compute/adapt.go
+++ b/internal/app/tfsec/adapter/azure/compute/adapt.go
@@ -1,10 +1,119 @@
 package compute
 
 import (
+	"encoding/base64"
+
 	"github.com/aquasecurity/defsec/provider/azure/compute"
+	"github.com/aquasecurity/defsec/types"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 )
 
 func Adapt(modules []block.Module) compute.Compute {
-	return compute.Compute{}
+	return adaptCompute(modules)
+}
+
+func adaptCompute(modules []block.Module) compute.Compute {
+
+	var managedDisks []compute.ManagedDisk
+	var linuxVirtualMachines []compute.LinuxVirtualMachine
+	var windowsVirtualMachines []compute.WindowsVirtualMachine
+
+	for _, module := range modules {
+
+		for _, resource := range module.GetResourcesByType("azurerm_linux_virtual_machine") {
+			linuxVirtualMachines = append(linuxVirtualMachines, adaptLinuxVM(resource))
+		}
+		for _, resource := range module.GetResourcesByType("azurerm_windows_virtual_machine") {
+			windowsVirtualMachines = append(windowsVirtualMachines, adaptWindowsVM(resource))
+		}
+		for _, resource := range module.GetResourcesByType("azurerm_virtual_machine") {
+			if resource.HasChild("os_profile_linux_config") {
+				linuxVirtualMachines = append(linuxVirtualMachines, adaptLinuxVM(resource))
+			} else if resource.HasChild("os_profile_windows_config") {
+				windowsVirtualMachines = append(windowsVirtualMachines, adaptWindowsVM(resource))
+			}
+		}
+		for _, resource := range module.GetResourcesByType("azurerm_managed_disk") {
+			managedDisks = append(managedDisks, adaptManagedDisk(resource))
+		}
+	}
+
+	return compute.Compute{
+		LinuxVirtualMachines:   linuxVirtualMachines,
+		WindowsVirtualMachines: windowsVirtualMachines,
+		ManagedDisks:           managedDisks,
+	}
+}
+
+func adaptManagedDisk(resource block.Block) compute.ManagedDisk {
+	encryptionBlock := resource.GetBlock("encryption_settings")
+	var enabledVal types.BoolValue
+
+	if encryptionBlock.IsNotNil() {
+		enabledAttr := encryptionBlock.GetAttribute("enabled")
+		enabledVal = enabledAttr.AsBoolValueOrDefault(false, encryptionBlock)
+	}
+
+	return compute.ManagedDisk{
+		Encryption: compute.Encryption{
+			Enabled: enabledVal,
+		},
+	}
+}
+
+func adaptLinuxVM(resource block.Block) compute.LinuxVirtualMachine {
+	workingBlock := resource
+
+	if resource.TypeLabel() == "azurerm_virtual_machine" {
+		workingBlock = resource.GetBlock("os_profile")
+	}
+	customDataAttr := workingBlock.GetAttribute("custom_data")
+	var customDataVal types.StringValue
+	if customDataAttr.IsResolvable() && customDataAttr.IsString() {
+		encoded, err := base64.StdEncoding.DecodeString(customDataAttr.Value().AsString())
+		if err != nil {
+			encoded = []byte(customDataAttr.Value().AsString())
+		}
+		customDataVal = types.String(string(encoded), *workingBlock.GetMetadata())
+	}
+
+	if resource.TypeLabel() == "azurerm_virtual_machine" {
+		workingBlock = resource.GetBlock("os_profile_linux_config")
+	}
+	disablePasswordAuthAttr := workingBlock.GetAttribute("disable_password_authentication")
+	disablePasswordAuthVal := disablePasswordAuthAttr.AsBoolValueOrDefault(true, workingBlock)
+
+	return compute.LinuxVirtualMachine{
+		VirtualMachine: compute.VirtualMachine{
+			CustomData: customDataVal,
+		},
+		OSProfileLinuxConfig: compute.OSProfileLinuxConfig{
+			DisablePasswordAuthentication: disablePasswordAuthVal,
+		},
+	}
+}
+
+func adaptWindowsVM(resource block.Block) compute.WindowsVirtualMachine {
+	workingBlock := resource
+
+	if resource.TypeLabel() == "azurerm_virtual_machine" {
+		workingBlock = resource.GetBlock("os_profile")
+	}
+
+	customDataAttr := workingBlock.GetAttribute("custom_data")
+	var customDataVal types.StringValue
+
+	if customDataAttr.IsResolvable() && customDataAttr.IsString() {
+		encoded, err := base64.StdEncoding.DecodeString(customDataAttr.Value().AsString())
+		if err != nil {
+			encoded = []byte(customDataAttr.Value().AsString())
+		}
+		customDataVal = types.String(string(encoded), *workingBlock.GetMetadata())
+	}
+
+	return compute.WindowsVirtualMachine{
+		VirtualMachine: compute.VirtualMachine{
+			CustomData: customDataVal,
+		},
+	}
 }
diff --git a/internal/app/tfsec/adapter/azure/monitor/adapt.go b/internal/app/tfsec/adapter/azure/monitor/adapt.go
index 7d168081b..72a2a4193 100644
--- a/internal/app/tfsec/adapter/azure/monitor/adapt.go
+++ b/internal/app/tfsec/adapter/azure/monitor/adapt.go
@@ -2,9 +2,57 @@ package monitor
 
 import (
 	"github.com/aquasecurity/defsec/provider/azure/monitor"
+	"github.com/aquasecurity/defsec/types"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 )
 
 func Adapt(modules []block.Module) monitor.Monitor {
-	return monitor.Monitor{}
+	return monitor.Monitor{
+		LogProfiles: adaptLogProfiles(modules),
+	}
+}
+
+func adaptLogProfiles(modules []block.Module) []monitor.LogProfile {
+	var logProfiles []monitor.LogProfile
+
+	for _, module := range modules {
+		for _, resource := range module.GetResourcesByType("azurerm_monitor_log_profile") {
+			logProfiles = append(logProfiles, adaptLogProfile(resource))
+		}
+	}
+	return logProfiles
+}
+
+func adaptLogProfile(resource block.Block) monitor.LogProfile {
+	retentionPolicyBlock := resource.GetBlock("retention_policy")
+
+	enabledAttr := retentionPolicyBlock.GetAttribute("enabled")
+	enabledVal := enabledAttr.AsBoolValueOrDefault(false, resource)
+
+	daysAttr := retentionPolicyBlock.GetAttribute("days")
+	daysVal := daysAttr.AsIntValueOrDefault(0, resource)
+
+	categoriesAttr := resource.GetAttribute("categories")
+	var categoriesVal []types.StringValue
+	categories := categoriesAttr.ValueAsStrings()
+	for _, category := range categories {
+		categoriesVal = append(categoriesVal, types.String(category, *resource.GetMetadata()))
+	}
+
+	locationsAttr := resource.GetAttribute("locations")
+	var locationsVal []types.StringValue
+	locations := locationsAttr.ValueAsStrings()
+	for _, location := range locations {
+		locationsVal = append(locationsVal, types.String(location, *resource.GetMetadata()))
+	}
+
+	return monitor.LogProfile{
+		Metadata: *resource.GetMetadata(),
+		RetentionPolicy: monitor.RetentionPolicy{
+			Enabled: enabledVal,
+			Days:    daysVal,
+		},
+		Categories: categoriesVal,
+		Locations:  locationsVal,
+	}
 }
diff --git a/internal/app/tfsec/adapter/azure/synapse/adapt.go b/internal/app/tfsec/adapter/azure/synapse/adapt.go
index 86804fe60..be5d0ce2d 100644
--- a/internal/app/tfsec/adapter/azure/synapse/adapt.go
+++ b/internal/app/tfsec/adapter/azure/synapse/adapt.go
@@ -6,5 +6,26 @@ import (
 )
 
 func Adapt(modules []block.Module) synapse.Synapse {
-	return synapse.Synapse{}
+	return synapse.Synapse{
+		Workspaces: adaptWorkspaces(modules),
+	}
+}
+
+func adaptWorkspaces(modules []block.Module) []synapse.Workspace {
+	var workspaces []synapse.Workspace
+	for _, module := range modules {
+		for _, resource := range module.GetResourcesByType("azurerm_synapse_workspace") {
+			workspaces = append(workspaces, adaptWorkspace(resource))
+		}
+	}
+	return workspaces
+}
+
+func adaptWorkspace(resource block.Block) synapse.Workspace {
+	enableManagedVNAttr := resource.GetAttribute("managed_virtual_network_enabled")
+	enableManagedVNVal := enableManagedVNAttr.AsBoolValueOrDefault(false, resource)
+
+	return synapse.Workspace{
+		EnableManagedVirtualNetwork: enableManagedVNVal,
+	}
 }
diff --git a/internal/app/tfsec/block/type.go b/internal/app/tfsec/block/type.go
index 05ee86f26..6c0fb7987 100644
--- a/internal/app/tfsec/block/type.go
+++ b/internal/app/tfsec/block/type.go
@@ -38,6 +38,10 @@ var TypeLocal = Type{
 	refName: "local",
 }
 
+var TypeMoved = Type{
+	name: "moved",
+}
+
 var TypeProvider = Type{
 	name: "provider",
 }
@@ -58,6 +62,7 @@ var ValidTypes = []Type{
 	TypeData,
 	TypeLocal,
 	TypeModule,
+	TypeMoved,
 	TypeOutput,
 	TypeProvider,
 	TypeResource,
diff --git a/internal/app/tfsec/parser/evaluator.go b/internal/app/tfsec/parser/evaluator.go
index 89d918fd3..a12bffedb 100644
--- a/internal/app/tfsec/parser/evaluator.go
+++ b/internal/app/tfsec/parser/evaluator.go
@@ -399,7 +399,7 @@ func (e *Evaluator) getValuesByBlockType(blockType string) cty.Value {
 				continue
 			}
 			values[b.Label()] = val
-		case "locals":
+		case "locals", "moved":
 			for key, val := range b.Values().AsValueMap() {
 				values[key] = val
 			}
diff --git a/internal/app/tfsec/rules/azure/appservice/account_identity_registered_rule.go b/internal/app/tfsec/rules/azure/appservice/account_identity_registered_rule.go
index 0fff9cd47..dbe920411 100644
--- a/internal/app/tfsec/rules/azure/appservice/account_identity_registered_rule.go
+++ b/internal/app/tfsec/rules/azure/appservice/account_identity_registered_rule.go
@@ -1,9 +1,7 @@
 package appservice
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/appservice"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -41,11 +39,5 @@ func init() {
 			"azurerm_app_service",
 		},
 		Base: appservice.CheckAccountIdentityRegistered,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			if identityAttr := resourceBlock.GetBlock("identity"); identityAttr.IsNil() { // alert on use of default value
-				results.Add("Resource does not set identity", resourceBlock)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/appservice/authentication_enabled_rule.go b/internal/app/tfsec/rules/azure/appservice/authentication_enabled_rule.go
index ec7ac3544..ed1eb430d 100644
--- a/internal/app/tfsec/rules/azure/appservice/authentication_enabled_rule.go
+++ b/internal/app/tfsec/rules/azure/appservice/authentication_enabled_rule.go
@@ -1,9 +1,7 @@
 package appservice
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/appservice"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -40,15 +38,5 @@ func init() {
 			"azurerm_app_service",
 		},
 		Base: appservice.CheckAuthenticationEnabled,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			if authBlock := resourceBlock.GetBlock("auth_settings"); authBlock.IsNil() {
-				results.Add("Resource uses default value for auth_settings.enabled", resourceBlock)
-			} else if enabledAttr := authBlock.GetAttribute("enabled"); enabledAttr.IsNil() {
-				results.Add("Resource uses default value for auth_settings.enabled", authBlock)
-			} else if enabledAttr.IsFalse() {
-				results.Add("Resource has attribute auth_settings.enabled that is false", enabledAttr)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/appservice/enable_http2_rule.go b/internal/app/tfsec/rules/azure/appservice/enable_http2_rule.go
index 804472301..df66fcd34 100644
--- a/internal/app/tfsec/rules/azure/appservice/enable_http2_rule.go
+++ b/internal/app/tfsec/rules/azure/appservice/enable_http2_rule.go
@@ -1,9 +1,7 @@
 package appservice
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/appservice"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -51,15 +49,5 @@ func init() {
 			"azurerm_app_service",
 		},
 		Base: appservice.CheckEnableHttp2,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			if configBlock := resourceBlock.GetBlock("site_config"); configBlock.IsNil() {
-				results.Add("Resource uses default value for site_config.http2_enabled", resourceBlock)
-			} else if http2EnabledAttr := configBlock.GetAttribute("http2_enabled"); http2EnabledAttr.IsNil() { // alert on use of default value
-				results.Add("Resource uses default value for site_config.http2_enabled", configBlock)
-			} else if http2EnabledAttr.IsFalse() {
-				results.Add("Resource has attribute site_config.http2_enabled that is false", http2EnabledAttr)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go b/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go
index 2aeef5f60..ca072aa57 100644
--- a/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go
+++ b/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go
@@ -1,9 +1,7 @@
 package appservice
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/appservice"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -40,15 +38,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_function_app"},
 		Base:           appservice.CheckEnforceHttps,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			if resourceBlock.MissingChild("https_only") {
-				results.Add("Resource should have https_only set to true, the default is false.", resourceBlock)
-				return
-			}
-			if httpsOnlyAttr := resourceBlock.GetAttribute("https_only"); httpsOnlyAttr.IsFalse() {
-				results.Add("Resource should be HTTPS only.", httpsOnlyAttr)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/appservice/require_client_cert_rule.go b/internal/app/tfsec/rules/azure/appservice/require_client_cert_rule.go
index cba20964b..dc45bcd8f 100644
--- a/internal/app/tfsec/rules/azure/appservice/require_client_cert_rule.go
+++ b/internal/app/tfsec/rules/azure/appservice/require_client_cert_rule.go
@@ -1,9 +1,7 @@
 package appservice
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/appservice"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -47,13 +45,5 @@ func init() {
 			"azurerm_app_service",
 		},
 		Base: appservice.CheckRequireClientCert,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			if clientCertEnabledAttr := resourceBlock.GetAttribute("client_cert_enabled"); clientCertEnabledAttr.IsNil() { // alert on use of default value
-				results.Add("Resource uses default value for client_cert_enabled", resourceBlock)
-			} else if clientCertEnabledAttr.IsFalse() {
-				results.Add("Resource has attribute client_cert_enabled that is false", clientCertEnabledAttr)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/appservice/use_secure_tls_policy_rule.go b/internal/app/tfsec/rules/azure/appservice/use_secure_tls_policy_rule.go
index 5ed498887..7f037caf1 100644
--- a/internal/app/tfsec/rules/azure/appservice/use_secure_tls_policy_rule.go
+++ b/internal/app/tfsec/rules/azure/appservice/use_secure_tls_policy_rule.go
@@ -1,9 +1,7 @@
 package appservice
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/appservice"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -40,15 +38,5 @@ func init() {
 			"azurerm_app_service",
 		},
 		Base: appservice.CheckUseSecureTlsPolicy,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			if resourceBlock.MissingChild("site_config") {
-				return
-			}
-
-			if minTlsVersionAttr := resourceBlock.GetBlock("site_config").GetAttribute("min_tls_version"); minTlsVersionAttr.IsNotNil() && minTlsVersionAttr.NotEqual("1.2") {
-				results.Add("Resource does not have site_config.min_tls_version set to 1.2", minTlsVersionAttr)
-			}
-			return results
-		},
 	})
 }
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
index cd424bd69..09d352a12 100644
--- a/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule.go
+++ b/internal/app/tfsec/rules/azure/authorization/limit_role_actions_rule.go
@@ -1,9 +1,7 @@
 package authorization
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/authorization"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -58,18 +56,5 @@ func init() {
 			"azurerm_role_definition",
 		},
 		Base: authorization.CheckLimitRoleActions,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			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() {
-						results.Add("Resource has wildcard action with open assignable_scopes", resourceBlock)
-					} else if assignableScopesAttr.Contains("/") {
-						results.Add("Resource has wildcard action with open assignable_scopes", assignableScopesAttr)
-					}
-				}
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go b/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go
index 26ac2c1f0..40c61748a 100644
--- a/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go
+++ b/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go
@@ -1,9 +1,7 @@
 package compute
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -80,24 +78,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_linux_virtual_machine", "azurerm_virtual_machine"},
 		Base:           compute.CheckDisablePasswordAuthentication,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			workingBlock := resourceBlock
-			if resourceBlock.TypeLabel() == "azurerm_virtual_machine" {
-				if resourceBlock.HasChild("os_profile_linux_config") {
-					workingBlock = resourceBlock.GetBlock("os_profile_linux_config")
-				}
-			}
-
-			if workingBlock.MissingChild("disable_password_authentication") {
-				return
-			}
-
-			passwordAuthAttr := workingBlock.GetAttribute("disable_password_authentication")
-			if passwordAuthAttr.IsFalse() {
-				results.Add("Resource has password authentication enabled.", passwordAuthAttr)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go b/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go
index 7eff1f597..2a4ae80d1 100644
--- a/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go
+++ b/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go
@@ -1,9 +1,7 @@
 package compute
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -29,22 +27,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_managed_disk"},
 		Base:           compute.CheckEnableDiskEncryption,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			encryptionSettingsBlock := resourceBlock.GetBlock("encryption_settings")
-			if encryptionSettingsBlock.IsNil() {
-				return // encryption is by default now, so this is fine
-			}
-
-			if encryptionSettingsBlock.MissingChild("enabled") {
-				return
-			}
-
-			enabledAttr := encryptionSettingsBlock.GetAttribute("enabled")
-			if enabledAttr.IsFalse() {
-				results.Add("Resource defines an unencrypted managed disk.", enabledAttr)
-			}
-
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go b/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go
index 92f9f0629..d51ebcd1e 100644
--- a/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go
+++ b/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go
@@ -1,16 +1,10 @@
 package compute
 
 import (
-	"encoding/base64"
-
 	"github.com/aquasecurity/defsec/rules/azure/compute"
 
-	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
-	"github.com/owenrumney/squealer/pkg/squealer"
 )
 
 func init() {
@@ -18,17 +12,27 @@ func init() {
 		BadExample: []string{`
  resource "azurerm_virtual_machine" "bad_example" {
  	name = "bad_example"
- 	custom_data =<<EOF
- export DATABASE_PASSWORD=\"SomeSortOfPassword\"
- EOF
+	os_profile_linux_config {
+		disable_password_authentication = false
+	}
+	os_profile {
+		custom_data =<<EOF
+			export DATABASE_PASSWORD=\"SomeSortOfPassword\"
+			EOF
+	}
  }
  `},
 		GoodExample: []string{`
  resource "azurerm_virtual_machine" "good_example" {
  	name = "good_example"
- 	custom_data =<<EOF
- export GREETING="Hello there"
- EOF
+	os_profile_linux_config {
+		disable_password_authentication = false
+	}
+	os_profile {
+		custom_data =<<EOF
+			export GREETING="Hello there"
+			EOF
+	}
  }
  `},
 		Links: []string{
@@ -37,36 +41,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_virtual_machine", "azurerm_linux_virtual_machine", "azurerm_windows_virtual_machine"},
 		Base:           compute.CheckNoSecretsInCustomData,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			if resourceBlock.MissingChild("custom_data") {
-				return
-			}
-
-			customDataAttr := resourceBlock.GetAttribute("custom_data")
-
-			if resourceBlock.TypeLabel() == "azurerm_virtual_machine" {
-				for _, str := range customDataAttr.ValueAsStrings() {
-					if checkStringForSensitive(str) {
-						results.Add("Resource has custom_data with sensitive data.", customDataAttr)
-					}
-				}
-			} else if customDataAttr.IsResolvable() && customDataAttr.IsString() {
-				encoded, err := base64.StdEncoding.DecodeString(customDataAttr.Value().AsString())
-				if err != nil {
-					debug.Log("could not decode the base64 string in the terraform, trying with the string verbatim")
-					encoded = []byte(customDataAttr.Value().AsString())
-				}
-				if checkStringForSensitive(string(encoded)) {
-					results.Add("Resource has custom_data with sensitive data.", customDataAttr)
-				}
-
-			}
-			return results
-		},
 	})
 }
-
-func checkStringForSensitive(stringToCheck string) bool {
-	return squealer.NewStringScanner().Scan(stringToCheck).TransgressionFound
-}
diff --git a/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go b/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go
index b4f8ff102..15d0a3466 100644
--- a/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go
+++ b/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go
@@ -1,9 +1,7 @@
 package monitor
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/monitor"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -36,29 +34,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_monitor_log_profile"},
 		Base:           monitor.CheckActivityLogRetentionSet,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			if resourceBlock.MissingChild("retention_policy") {
-				return
-			}
-
-			retentionPolicyBlock := resourceBlock.GetBlock("retention_policy")
-
-			if retentionPolicyBlock.MissingChild("enabled") {
-				results.Add("Resource does not enable retention policy", retentionPolicyBlock)
-				return
-			}
-
-			if retentionPolicyBlock.MissingChild("days") {
-				results.Add("Resource does not retention policy days set", retentionPolicyBlock)
-				return
-			}
-
-			daysAttr := retentionPolicyBlock.GetAttribute("days")
-			if daysAttr.LessThan(356) {
-				results.Add("Resource has retention period of less than 365 days", daysAttr)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go b/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go
index 1ac3d3e52..f8c598386 100644
--- a/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go
+++ b/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go
@@ -1,11 +1,7 @@
 package monitor
 
 import (
-	"fmt"
-
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/monitor"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -46,21 +42,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_monitor_log_profile"},
 		Base:           monitor.CheckCaptureAllActivities,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			categoriesAttr := resourceBlock.GetAttribute("categories")
-			if categoriesAttr.IsNil() || categoriesAttr.IsEmpty() {
-				results.Add("Resource does not have required categories", resourceBlock)
-				return
-			}
-
-			for _, category := range []string{"Action", "Write", "Delete"} {
-				if !categoriesAttr.Contains(category) {
-					results.Add(fmt.Sprintf("Resource is missing '%s' category", category), categoriesAttr)
-				}
-			}
-
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go b/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go
index 338c3af7b..9d1148519 100644
--- a/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go
+++ b/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go
@@ -1,12 +1,8 @@
 package monitor
 
 import (
-	"fmt"
-
 	"github.com/aquasecurity/defsec/rules/azure/monitor"
 
-	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -122,27 +118,6 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_monitor_log_profile"},
 		Base:           monitor.CheckCaptureAllRegions,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			if resourceBlock.MissingChild("locations") {
-				results.Add("Resource does not have the locations block set", resourceBlock)
-				return
-			}
-
-			locationsAttr := resourceBlock.GetAttribute("locations")
-			if locationsAttr.IsEmpty() {
-				results.Add("Resource does not have all locations specified", locationsAttr)
-				return
-			}
-
-			for _, location := range locations {
-				if !locationsAttr.Contains(location) {
-					results.Add(fmt.Sprintf("Resource does not have the location '%s'", location), locationsAttr)
-				}
-			}
-
-			return results
-		},
 	})
 }
 
diff --git a/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go b/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go
index d513b285c..f8175e8a3 100644
--- a/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go
+++ b/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go
@@ -1,9 +1,7 @@
 package synapse
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/azure/synapse"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -57,17 +55,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"azurerm_synapse_workspace"},
 		Base:           synapse.CheckVirtualNetworkEnabled,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			if resourceBlock.MissingChild("managed_virtual_network_enabled") {
-				results.Add("Resource should have managed_virtual_network_enabled set to true, the default is false.", resourceBlock)
-				return
-			}
-			managedNetworkAttr := resourceBlock.GetAttribute("managed_virtual_network_enabled")
-			if managedNetworkAttr.IsFalse() {
-				results.Add("Resource should have managed_virtual_network_enabled set to true, the default is false.", managedNetworkAttr)
-			}
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/schema/schema.go b/internal/app/tfsec/schema/schema.go
index 2f8d3023a..9920a7a15 100644
--- a/internal/app/tfsec/schema/schema.go
+++ b/internal/app/tfsec/schema/schema.go
@@ -19,6 +19,9 @@ var TerraformSchema_0_12 = &hcl.BodySchema{
 		{
 			Type: "locals",
 		},
+		{
+			Type: "moved",
+		},
 		{
 			Type:       "output",
 			LabelNames: []string{"name"},


Test patch:
diff --git a/internal/app/tfsec/parser/parser_test.go b/internal/app/tfsec/parser/parser_test.go
index b7cb16484..316d7c503 100644
--- a/internal/app/tfsec/parser/parser_test.go
+++ b/internal/app/tfsec/parser/parser_test.go
@@ -32,6 +32,10 @@ provider "cats" {
 
 }
 
+moved {
+
+}
+
 resource "cats_cat" "mittens" {
 	name = "mittens"
 	special = true
diff --git a/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule_test.go b/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule_test.go
index 8b1687032..115866297 100644
--- a/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule_test.go
+++ b/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule_test.go
@@ -20,9 +20,14 @@ func Test_AzureNoSecretsInCustomData(t *testing.T) {
 			source: `
  			resource "azurerm_virtual_machine" "bad_example" {
  				name = "bad_example"
- 				custom_data =<<EOF
- DATABASE_PASSWORD=SomeSortOfPassword
- EOF
+				os_profile_windows_config {
+					disable_password_authentication = false
+				}
+				os_profile {
+					custom_data =<<EOF
+						DATABASE_PASSWORD=SomeSortOfPassword
+						EOF
+				}
  			}
  `,
 			mustIncludeResultCode: expectedCode,
@@ -32,9 +37,14 @@ func Test_AzureNoSecretsInCustomData(t *testing.T) {
 			source: `
  			resource "azurerm_virtual_machine" "bad_example" {
  				name = "bad_example"
- 				custom_data =<<EOF
- DATABASE_PASSWORD="SomeSortOfPassword"
- EOF
+				os_profile_windows_config {
+					disable_password_authentication = false
+				}
+				os_profile {
+ 					custom_data =<<EOF
+ 						DATABASE_PASSWORD="SomeSortOfPassword"
+ 						EOF
+				}
  			}
  `,
 			mustIncludeResultCode: expectedCode,
@@ -52,11 +62,16 @@ func Test_AzureNoSecretsInCustomData(t *testing.T) {
 		{
 			name: "virtual machine with no sensitive information in custom_data passes check",
 			source: `
- resource "azurerm_virtual_machine" "god_example" {
+ resource "azurerm_virtual_machine" "good_example" {
  				name = "good_example"
- 				custom_data =<<EOF
- GREETING_TEXT="Hello"
- EOF
+				os_profile_windows_config {
+					disable_password_authentication = false
+				}
+				os_profile {
+					custom_data =<<EOF
+						GREETING_TEXT="Hello"
+						EOF
+				}
  			}
  `,
 			mustExcludeResultCode: expectedCode,
@@ -64,7 +79,7 @@ func Test_AzureNoSecretsInCustomData(t *testing.T) {
 		{
 			name: "linux virtual machine with no sensitive information in base64 custom_data passes check",
 			source: `
- resource "azurerm_linux_virtual_machine" "god_example" {
+ resource "azurerm_linux_virtual_machine" "good_example" {
  				name = "good_example"
  				custom_data = "ZXhwb3J0IEVESVRPUj12aW1hY3M=" 
  			}