Repository: aquasecurity/tfsec
Pull request #981 (2021-07-30 11:09:52)

Add contains to autogen


Patch:
diff --git a/cmd/tfsec-skeleton/csv.go b/cmd/tfsec-skeleton/csv.go
index ed3d033a1..2b93efa1f 100644
--- a/cmd/tfsec-skeleton/csv.go
+++ b/cmd/tfsec-skeleton/csv.go
@@ -90,7 +90,7 @@ func generateFromCSV(path string) ([]*Input, error) {
 		}
 
 		if err := input.Validate(); err != nil {
-			return nil, fmt.Errorf("line %d of csv failed validation: %s", i, err)
+			return nil, fmt.Errorf("line %d [%s] of csv failed validation: %s", i, input.Summary, err)
 		}
 
 		inputs = append(inputs, &input)
diff --git a/cmd/tfsec-skeleton/examples/mutate.go b/cmd/tfsec-skeleton/examples/mutate.go
index d5b39b861..38f429e59 100644
--- a/cmd/tfsec-skeleton/examples/mutate.go
+++ b/cmd/tfsec-skeleton/examples/mutate.go
@@ -37,7 +37,7 @@ func (m *machine) processAttributeLine(line string) string {
 	parts := strings.Split(line, "=")
 	name := strings.TrimSpace(parts[0])
 	if strings.Join(append(m.stack, name), ".") == m.dotPath {
-		line = fmt.Sprintf("%s= %s", parts[0], sprintGo(m.value))
+		line = fmt.Sprintf("%s= %s", parts[0], sprintHCL(m.value))
 		m.found = true
 	}
 	if strings.Contains(line, "<<") {
@@ -122,7 +122,7 @@ func expandPathAndValue(dotPath string, value interface{}, tabStr string, tabSiz
 	tab := strings.Repeat(tabStr, tabSize)
 	segments := strings.Split(dotPath, ".")
 	if len(segments) == 1 {
-		return fmt.Sprintf("%s%s = %s", tab, segments[0], sprintGo(value))
+		return fmt.Sprintf("%s%s = %s", tab, segments[0], sprintHCL(value))
 	}
 
 	return fmt.Sprintf("%s%s {\n%s\n%s}", tab, segments[0], expandPathAndValue(strings.Join(segments[1:], "."), value, tabStr, tabSize+1), tab)
@@ -144,12 +144,15 @@ func dotSegmentFromLine(line string) string {
 	return strings.Join(output, ".")
 }
 
-func sprintGo(value interface{}) string {
+func sprintHCL(value interface{}) string {
 	if s, ok := value.(string); ok {
 		return fmt.Sprintf("%q", s)
 	}
 	if s, ok := value.([]string); ok {
-		return fmt.Sprintf("%#v", s)
+		if len(s) == 0 {
+			return `[]`
+		}
+		return fmt.Sprintf(`["%s"]`, strings.Join(s, `", "`))
 	}
 	return fmt.Sprintf("%v", value)
 }
diff --git a/cmd/tfsec-skeleton/input.go b/cmd/tfsec-skeleton/input.go
index 35fc3aa11..c0a103f10 100644
--- a/cmd/tfsec-skeleton/input.go
+++ b/cmd/tfsec-skeleton/input.go
@@ -56,7 +56,7 @@ func (i Input) Validate() error {
 	if i.Requirement == nil {
 		return fmt.Errorf("no requirement specified")
 	}
-	if i.AttributeName == "" {
+	if i.AttributeName == "" && i.Requirement.RequirementType() != requirements.CustomRequirement {
 		return fmt.Errorf("no attribute path specified")
 	}
 	return nil
diff --git a/cmd/tfsec-skeleton/requirements/attributes.go b/cmd/tfsec-skeleton/requirements/attributes.go
index 54408a57a..451b6763b 100644
--- a/cmd/tfsec-skeleton/requirements/attributes.go
+++ b/cmd/tfsec-skeleton/requirements/attributes.go
@@ -37,37 +37,35 @@ func NewAttributeRequirement(blockType string, blockLabel string, dotPath string
 	return &req
 }
 
-func (a *attributeBase) makeGoodValue(value interface{}, comparison Comparison) interface{} {
+func (a *attributeBase) makeGoodValue() interface{} {
 	switch a.comparison {
 	case ComparisonEquals:
 		return a.value
-	case ComparisonNotEquals:
+	case ComparisonNotEquals, ComparisonNotAnyOf:
 		return flipValue(a.value)
 	case ComparisonAnyOf:
 		if strs, ok := a.value.([]string); ok && len(strs) > 0 {
 			return strs[0]
 		}
 		panic("only non-zero length list of strings are supported")
-	case ComparisonNotAnyOf:
-		return "something"
-	case ComparisonGreaterThan:
+	case ComparisonGreaterThan, ComparisonGreaterThanOrEqual:
 		if i, ok := a.value.(int); ok {
 			return i + 1
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
-	case ComparisonLessThan:
+	case ComparisonLessThan, ComparisonLessThanOrEqual:
 		if i, ok := a.value.(int); ok {
 			return i - 1
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
-	case ComparisonGreaterThanOrEqual:
-		if i, ok := a.value.(int); ok {
-			return i
+	case ComparisonContains:
+		if s, ok := a.value.(string); ok {
+			return []string{s}
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
-	case ComparisonLessThanOrEqual:
-		if i, ok := a.value.(int); ok {
-			return i
+	case ComparisonNotContains:
+		if _, ok := a.value.(string); ok {
+			return []string{}
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
 	default:
@@ -77,7 +75,7 @@ func (a *attributeBase) makeGoodValue(value interface{}, comparison Comparison)
 
 func (a *attributeBase) GenerateGoodExample() string {
 
-	value := a.makeGoodValue(a.value, a.comparison)
+	value := a.makeGoodValue()
 
 	if a.exampleCode != "" {
 		return examples.SetAttribute(a.exampleCode, fmt.Sprintf("%s.%s.*.%s", a.blockType, a.blockLabel, a.dotPath), value, "good_example")
@@ -89,37 +87,35 @@ func (a *attributeBase) GenerateGoodExample() string {
 `, a.blockType, a.blockLabel, "good_example", createTerraformFromDotPath(a.dotPath, value))
 }
 
-func (a *attributeBase) makeBadValue(value interface{}, comparison Comparison) interface{} {
+func (a *attributeBase) makeBadValue() interface{} {
 	switch a.comparison {
-	case ComparisonEquals:
+	case ComparisonEquals, ComparisonAnyOf:
 		return flipValue(a.value)
 	case ComparisonNotEquals:
 		return a.value
-	case ComparisonAnyOf:
-		return "something"
 	case ComparisonNotAnyOf:
 		if strs, ok := a.value.([]string); ok && len(strs) > 0 {
 			return strs[0]
 		}
 		panic("only non-zero length list of strings are supported")
-	case ComparisonGreaterThan:
+	case ComparisonGreaterThan, ComparisonGreaterThanOrEqual:
 		if i, ok := a.value.(int); ok {
 			return i - 1
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
-	case ComparisonLessThan:
+	case ComparisonLessThan, ComparisonLessThanOrEqual:
 		if i, ok := a.value.(int); ok {
 			return i + 1
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
-	case ComparisonGreaterThanOrEqual:
-		if i, ok := a.value.(int); ok {
-			return i - 1
+	case ComparisonContains:
+		if _, ok := a.value.(string); ok {
+			return []string{}
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
-	case ComparisonLessThanOrEqual:
-		if i, ok := a.value.(int); ok {
-			return i + 1
+	case ComparisonNotContains:
+		if s, ok := a.value.(string); ok {
+			return []string{s}
 		}
 		panic(fmt.Sprintf("comparison '%s' cannot support value %#v", a.comparison, a.value))
 	default:
@@ -129,7 +125,7 @@ func (a *attributeBase) makeBadValue(value interface{}, comparison Comparison) i
 
 func (a *attributeBase) GenerateBadExample() string {
 
-	value := a.makeBadValue(a.value, a.comparison)
+	value := a.makeBadValue()
 
 	if a.exampleCode != "" {
 		return examples.SetAttribute(a.exampleCode, fmt.Sprintf("%s.%s.*.%s", a.blockType, a.blockLabel, a.dotPath), value, "bad_example")
@@ -187,6 +183,11 @@ func (a *attributeBase) GenerateRuleCode() string {
 		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to greater than or equal to %d", a.dotPath, a.value)
 	case ComparisonLessThanOrEqual:
 		messageTemplate = fmt.Sprintf("Resource '%%s' does not have %s set to greater than or equal to %d", a.dotPath, a.value)
+	case ComparisonContains:
+		messageTemplate = fmt.Sprintf("Resource '%%s' should have %s in %s", a.value, a.dotPath)
+	case ComparisonNotContains:
+		messageTemplate = fmt.Sprintf("Resource '%%s' has %s in %s", a.value, a.dotPath)
+
 	default:
 		panic(fmt.Sprintf("comparison '%s' is not supported", a.comparison))
 	}
@@ -199,3 +200,7 @@ func (a *attributeBase) GenerateRuleCode() string {
 
 	return code
 }
+
+func (a *attributeBase) RequirementType() RequirementType {
+	return RequirementType(AttributeRequirement)
+}
diff --git a/cmd/tfsec-skeleton/requirements/comparison.go b/cmd/tfsec-skeleton/requirements/comparison.go
index ebe9cbef8..40cf3b8cf 100644
--- a/cmd/tfsec-skeleton/requirements/comparison.go
+++ b/cmd/tfsec-skeleton/requirements/comparison.go
@@ -12,6 +12,8 @@ const (
 	ComparisonLessThan           Comparison = "lessthan"
 	ComparisonGreaterThanOrEqual Comparison = "greaterthanorequal"
 	ComparisonLessThanOrEqual    Comparison = "lessthanorequal"
+	ComparisonContains           Comparison = "contains"
+	ComparisonNotContains        Comparison = "notcontains"
 )
 
 func (c Comparison) Reverse() Comparison {
@@ -32,6 +34,10 @@ func (c Comparison) Reverse() Comparison {
 		return ComparisonLessThan
 	case ComparisonLessThanOrEqual:
 		return ComparisonGreaterThan
+	case ComparisonNotContains:
+		return ComparisonContains
+	case ComparisonContains:
+		return ComparisonNotContains
 	default:
 		return ComparisonNone
 	}
diff --git a/cmd/tfsec-skeleton/requirements/custom.go b/cmd/tfsec-skeleton/requirements/custom.go
index 9122afd2e..0c50860c0 100644
--- a/cmd/tfsec-skeleton/requirements/custom.go
+++ b/cmd/tfsec-skeleton/requirements/custom.go
@@ -43,3 +43,7 @@ func (a *custom) GenerateBadExample() string {
 func (a *custom) GenerateRuleCode() string {
 	return " // TODO: code goes here"
 }
+
+func (a *custom) RequirementType() RequirementType {
+	return CustomRequirement
+}
diff --git a/cmd/tfsec-skeleton/requirements/requirements.go b/cmd/tfsec-skeleton/requirements/requirements.go
index 3e2d892a2..b46bc89ac 100644
--- a/cmd/tfsec-skeleton/requirements/requirements.go
+++ b/cmd/tfsec-skeleton/requirements/requirements.go
@@ -5,7 +5,15 @@ import (
 	"strings"
 )
 
+type RequirementType int
+
+const (
+	CustomRequirement RequirementType = iota
+	AttributeRequirement
+)
+
 type Requirement interface {
+	RequirementType() RequirementType
 	GenerateGoodExample() string
 	GenerateBadExample() string
 	GenerateRuleCode() string
@@ -136,6 +144,10 @@ func buildStringComparison(value string, comparison Comparison) string {
 			return "!IsEmpty()"
 		}
 		return fmt.Sprintf(`NotEqual(%s)`, sprintGo(value))
+	case ComparisonContains:
+		return fmt.Sprintf(`Contains(%s)`, sprintGo(value))
+	case ComparisonNotContains:
+		return fmt.Sprintf(`NotContains(%s)`, sprintGo(value))
 	}
 	panic(fmt.Sprintf("Comparison '%s' not supported for string", comparison))
 }
diff --git a/internal/app/tfsec/block/attribute.go b/internal/app/tfsec/block/attribute.go
index 628cdcaef..23081cb9b 100644
--- a/internal/app/tfsec/block/attribute.go
+++ b/internal/app/tfsec/block/attribute.go
@@ -11,6 +11,7 @@ type Attribute interface {
 	Range() Range
 	Name() string
 	Contains(checkValue interface{}, equalityOptions ...EqualityOption) bool
+	NotContains(checkValue interface{}, equalityOptions ...EqualityOption) bool
 	StartsWith(prefix interface{}) bool
 	EndsWith(suffix interface{}) bool
 	Equals(checkValue interface{}, equalityOptions ...EqualityOption) bool
diff --git a/internal/app/tfsec/block/hclattribute.go b/internal/app/tfsec/block/hclattribute.go
index d5a43e251..6deb98c68 100644
--- a/internal/app/tfsec/block/hclattribute.go
+++ b/internal/app/tfsec/block/hclattribute.go
@@ -211,6 +211,10 @@ func (attr *HCLAttribute) mapContains(checkValue interface{}, val cty.Value) boo
 	}
 }
 
+func (attr *HCLAttribute) NotContains(checkValue interface{}, equalityOptions ...EqualityOption) bool {
+	return !attr.Contains(checkValue, equalityOptions...)
+}
+
 func (attr *HCLAttribute) Contains(checkValue interface{}, equalityOptions ...EqualityOption) bool {
 	if attr == nil {
 		return false
diff --git a/internal/app/tfsec/rules/aws/documentdb/encryption_customer_key_rule.go b/internal/app/tfsec/rules/aws/documentdb/encryption_customer_key_rule.go
new file mode 100644
index 000000000..ff747a07f
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/documentdb/encryption_customer_key_rule.go
@@ -0,0 +1,92 @@
+package documentdb
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+// generator-locked
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "documentdb",
+		ShortCode: "encryption-customer-key",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "DocumentDB encryption should use Customer Managed Keys",
+			Explanation: `Encryption using AWS keys provides protection for your DocumentDB underlying storage. To increase control of the encryption and manage factors like rotation use customer managed keys.`,
+			Impact:      "Using AWS managed keys does not allow for fine grained control",
+			Resolution:  "Enable encryption using customer managed keys",
+			BadExample: []string{`
+resource "aws_docdb_cluster" "docdb" {
+  cluster_identifier      = "my-docdb-cluster"
+  engine                  = "docdb"
+  master_username         = "foo"
+  master_password         = "mustbeeightchars"
+  backup_retention_period = 5
+  preferred_backup_window = "07:00-09:00"
+  skip_final_snapshot     = true
+}
+`},
+			GoodExample: []string{`
+resource "aws_kms_key" "docdb_encryption" {
+	enable_key_rotation = true
+}
+			
+resource "aws_docdb_cluster" "docdb" {
+  cluster_identifier      = "my-docdb-cluster"
+  engine                  = "docdb"
+  master_username         = "foo"
+  master_password         = "mustbeeightchars"
+  backup_retention_period = 5
+  preferred_backup_window = "07:00-09:00"
+  skip_final_snapshot     = true
+  kms_key_id 			  = aws_kms_key.docdb_encryption.arn
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/docdb_cluster#kms_key_id",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"aws_docdb_cluster",
+			"aws_docdb_cluster_instance",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) {
+
+			if resourceBlock.MissingChild("kms_key_id") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not use CMK", resourceBlock.FullName())
+				return
+			}
+
+			kmsKeyAttr := resourceBlock.GetAttribute("kms_key_id")
+			if kmsKeyAttr.IsDataBlockReference() {
+				kmsData, err := ctx.GetReferencedBlock(kmsKeyAttr)
+				if err != nil {
+					return
+				}
+				keyIdAttr := kmsData.GetAttribute("key_id")
+				if keyIdAttr.IsNotNil() && keyIdAttr.StartsWith("alias/aws/") {
+					set.AddResult().
+						WithDescription("Resource '%s' explicitly uses the default CMK", resourceBlock.FullName()).
+						WithAttribute(kmsKeyAttr)
+				}
+			}
+
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/ebs/encryption_customer_key_rule.go b/internal/app/tfsec/rules/aws/ebs/encryption_customer_key_rule.go
new file mode 100644
index 000000000..b711349f8
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/ebs/encryption_customer_key_rule.go
@@ -0,0 +1,89 @@
+package ebs
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+// generator-locked
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "ebs",
+		ShortCode: "encryption-customer-key",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "EBS volume encryption should use Customer Managed Keys",
+			Explanation: `Encryption using AWS keys provides protection for your EBS volume. To increase control of the encryption and manage factors like rotation use customer managed keys.`,
+			Impact:      "Using AWS managed keys does not allow for fine grained control",
+			Resolution:  "Enable encryption using customer managed keys",
+			BadExample: []string{`
+resource "aws_ebs_volume" "example" {
+  availability_zone = "us-west-2a"
+  size              = 40
+
+  tags = {
+    Name = "HelloWorld"
+  }
+}
+`},
+			GoodExample: []string{`
+resource "aws_kms_key" "ebs_encryption" {
+	enable_key_rotation = true
+}
+
+resource "aws_ebs_volume" "example" {
+  availability_zone = "us-west-2a"
+  size              = 40
+
+  kms_key_id = aws_kms_key.ebs_encryption.arn
+
+  tags = {
+    Name = "HelloWorld"
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume#kms_key_id",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"aws_ebs_volume",
+		},
+		DefaultSeverity: severity.Low,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) {
+
+			if resourceBlock.MissingChild("kms_key_id") {
+				set.AddResult().
+					WithDescription("Resource '%s' does not use CMK", resourceBlock.FullName())
+				return
+			}
+
+			kmsKeyAttr := resourceBlock.GetAttribute("kms_key_id")
+			if kmsKeyAttr.IsDataBlockReference() {
+				kmsData, err := ctx.GetReferencedBlock(kmsKeyAttr)
+				if err != nil {
+					return
+				}
+				keyIdAttr := kmsData.GetAttribute("key_id")
+				if keyIdAttr.IsNotNil() && keyIdAttr.StartsWith("alias/aws/") {
+					set.AddResult().
+						WithDescription("Resource '%s' explicitly uses the default CMK", resourceBlock.FullName()).
+						WithAttribute(kmsKeyAttr)
+				}
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/ecr/no_public_access_rule.go b/internal/app/tfsec/rules/aws/ecr/no_public_access_rule.go
new file mode 100644
index 000000000..5923f98e0
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/ecr/no_public_access_rule.go
@@ -0,0 +1,153 @@
+package ecr
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"encoding/json"
+	"strings"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/rules/aws/iam"
+	"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.AWSProvider,
+		Service:   "ecr",
+		ShortCode: "no-public-access",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "ECR repository policy must block public access",
+			Explanation: `Allowing public access to the ECR repository risks leaking sensitive of abusable information`,
+			Impact:      "Risk of potential data leakage of sensitive artifacts",
+			Resolution:  "Do not allow public access in the policy",
+			BadExample: []string{`
+resource "aws_ecr_repository" "foo" {
+  name = "bar"
+}
+
+resource "aws_ecr_repository_policy" "foopolicy" {
+  repository = aws_ecr_repository.foo.name
+
+  policy = <<EOF
+{
+    "Version": "2008-10-17",
+    "Statement": [
+        {
+            "Sid": "new policy",
+            "Effect": "Allow",
+            "Principal": "*",
+            "Action": [
+                "ecr:GetDownloadUrlForLayer",
+                "ecr:BatchGetImage",
+                "ecr:BatchCheckLayerAvailability",
+                "ecr:PutImage",
+                "ecr:InitiateLayerUpload",
+                "ecr:UploadLayerPart",
+                "ecr:CompleteLayerUpload",
+                "ecr:DescribeRepositories",
+                "ecr:GetRepositoryPolicy",
+                "ecr:ListImages",
+                "ecr:DeleteRepository",
+                "ecr:BatchDeleteImage",
+                "ecr:SetRepositoryPolicy",
+                "ecr:DeleteRepositoryPolicy"
+            ]
+        }
+    ]
+}
+EOF
+}
+`},
+			GoodExample: []string{`
+resource "aws_ecr_repository" "foo" {
+  name = "bar"
+}
+
+resource "aws_ecr_repository_policy" "foopolicy" {
+  repository = aws_ecr_repository.foo.name
+
+  policy = <<EOF
+{
+    "Version": "2008-10-17",
+    "Statement": [
+        {
+            "Sid": "new policy",
+            "Effect": "Allow",
+            "Principal": "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root",
+            "Action": [
+                "ecr:GetDownloadUrlForLayer",
+                "ecr:BatchGetImage",
+                "ecr:BatchCheckLayerAvailability",
+                "ecr:PutImage",
+                "ecr:InitiateLayerUpload",
+                "ecr:UploadLayerPart",
+                "ecr:CompleteLayerUpload",
+                "ecr:DescribeRepositories",
+                "ecr:GetRepositoryPolicy",
+                "ecr:ListImages",
+                "ecr:DeleteRepository",
+                "ecr:BatchDeleteImage",
+                "ecr:SetRepositoryPolicy",
+                "ecr:DeleteRepositoryPolicy"
+            ]
+        }
+    ]
+}
+EOF
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy#policy",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"aws_ecr_repository_policy",
+		},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+
+			policyAttr := resourceBlock.GetAttribute("policy")
+			if policyAttr.IsNil() || !policyAttr.IsString() {
+				return
+			}
+
+			var document iam.PolicyDocument
+			if err := json.Unmarshal([]byte(policyAttr.Value().AsString()), &document); err != nil {
+				debug.Log("Error decoding IAM policy JSON at %s: %s", policyAttr.Range(), err)
+				return
+			}
+
+			for _, statement := range document.Statements {
+				var hasECRAction bool
+				for _, action := range statement.Action {
+					if strings.HasPrefix(action, "ecr:") {
+						hasECRAction = true
+						break
+					}
+				}
+				if !hasECRAction {
+					continue
+				}
+				for _, account := range statement.Principal.AWS {
+					if account == "*" {
+						set.AddResult().
+							WithDescription("Resource '%s' provides public access to the ECR repository.", resourceBlock.FullName())
+					}
+					return
+				}
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go b/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go
index 9d677c01e..f06f78fab 100644
--- a/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go
+++ b/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go
@@ -22,7 +22,7 @@ import (
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 )
 
-type awsIAMPolicyDocument struct {
+type PolicyDocument struct {
 	Statements []awsIAMPolicyDocumentStatement `json:"Statement"`
 }
 
@@ -34,12 +34,53 @@ type awsIAMPolicyDocumentStatement struct {
 }
 
 type awsIAMPolicyPrincipal struct {
-	AWS awsIAMPolicyDocumentValue `json:"AWS"`
+	AWS     []string
+	Service []string
 }
 
 // AWS allows string or []string as value, we convert everything to []string to avoid casting
 type awsIAMPolicyDocumentValue []string
 
+func (value *awsIAMPolicyPrincipal) UnmarshalJSON(b []byte) error {
+
+	var raw interface{}
+	err := json.Unmarshal(b, &raw)
+	if err != nil {
+		return err
+	}
+
+	//  value can be string or []string, convert everything to []string
+	switch v := raw.(type) {
+	case map[string]interface{}:
+		for key, each := range v {
+			switch raw := each.(type) {
+			case string:
+				if key == "Service" {
+					value.Service = append(value.Service, raw)
+				} else {
+					value.AWS = append(value.AWS, raw)
+				}
+			case []string:
+				if key == "Service" {
+					value.Service = append(value.Service, raw...)
+				} else {
+					value.AWS = append(value.AWS, raw...)
+				}
+			}
+		}
+	case string:
+		value.AWS = []string{v}
+	case []interface{}:
+		for _, item := range v {
+			value.AWS = append(value.AWS, fmt.Sprintf("%v", item))
+		}
+	default:
+		return fmt.Errorf("invalid %s value element: allowed is only string or []string", value)
+	}
+
+	return nil
+}
+
 func (value *awsIAMPolicyDocumentValue) UnmarshalJSON(b []byte) error {
 
 	var raw interface{}
@@ -213,7 +254,7 @@ data "aws_iam_policy_document" "kms_policy" {
 }
 
 func checkAWS097PolicyJSON(set result.Set, resourceBlock block.Block, policyAttr block.Attribute) {
-	var document awsIAMPolicyDocument
+	var document PolicyDocument
 	if err := json.Unmarshal([]byte(policyAttr.Value().AsString()), &document); err != nil {
 		return
 	}
diff --git a/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go b/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go
index 20265fa17..3bc5d651f 100644
--- a/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go
+++ b/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go
@@ -184,7 +184,7 @@ func checkAWS099PolicyDocumentBlock(set result.Set, policyDocumentBlock block.Bl
 }
 
 func checkAWS099PolicyJSON(set result.Set, resourceBlock block.Block, policyAttr block.Attribute) {
-	var document awsIAMPolicyDocument
+	var document PolicyDocument
 	if err := json.Unmarshal([]byte(policyAttr.Value().AsString()), &document); err != nil {
 		return
 	}
diff --git a/internal/app/tfsec/rules/aws/launch/no_sensitive_info_rule.go b/internal/app/tfsec/rules/aws/launch/no_sensitive_info_rule.go
new file mode 100644
index 000000000..4f11f82a1
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/launch/no_sensitive_info_rule.go
@@ -0,0 +1,118 @@
+package launch
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+// generator-locked
+
+import (
+	"encoding/base64"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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"
+	"github.com/owenrumney/squealer/pkg/squealer"
+)
+
+func init() {
+	scanner.RegisterCheckRule(rule.Rule{
+		Provider:  provider.AWSProvider,
+		Service:   "launch",
+		ShortCode: "no-sensitive-info",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure all data stored in the Launch configuration EBS is securely encrypted",
+			Explanation: `When creating Launch Configurations, user data can be used for the initial configuration of the check. User data must not contain any sensitive data.`,
+			Impact:      "Sensitive credentials in user data can be leaked",
+			Resolution:  "Don't use sensitive data in user data",
+			BadExample: []string{`
+resource "aws_launch_configuration" "as_conf" {
+  name          = "web_config"
+  image_id      = data.aws_ami.ubuntu.id
+  instance_type = "t2.micro"
+  user_data     = <<EOF
+export DATABASE_PASSWORD=\"SomeSortOfPassword\"
+EOF
+}
+`, `
+resource "aws_launch_configuration" "as_conf" {
+  name             = "web_config"
+  image_id         = data.aws_ami.ubuntu.id
+  instance_type    = "t2.micro"
+  user_data_base64 = "ZXhwb3J0IERBVEFCQVNFX1BBU1NXT1JEPSJTb21lU29ydE9mUGFzc3dvcmQi"
+}
+`},
+			GoodExample: []string{`
+resource "aws_launch_configuration" "as_conf" {
+  name          = "web_config"
+  image_id      = data.aws_ami.ubuntu.id
+  instance_type = "t2.micro"
+  user_data     = <<EOF
+export GREETING="Hello there"
+EOF
+}
+`, `
+resource "aws_launch_configuration" "as_conf" {
+	name             = "web_config"
+	image_id         = data.aws_ami.ubuntu.id
+	instance_type    = "t2.micro"
+	user_data_base64 = "ZXhwb3J0IEVESVRPUj12aW1hY3M="
+  }
+  `,
+			},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_configuration#user_data,user_data_base64",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"aws_launch_configuration",
+		},
+		DefaultSeverity: severity.High,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			// TODO: code goes here
+
+			if resourceBlock.MissingChild("user_data") && resourceBlock.MissingChild("user_data_base64") {
+				return
+			}
+
+			customDataAttr := resourceBlock.GetAttribute("user_data")
+			customDataBase64Attr := resourceBlock.GetAttribute("user_data_base64")
+
+			if customDataAttr.IsNotNil() {
+				for _, str := range customDataAttr.ValueAsStrings() {
+					if checkStringForSensitive(str) {
+						set.AddResult().
+							WithDescription("Resource '%s' has user_data with sensitive data.", resourceBlock.FullName()).
+							WithAttribute(customDataAttr)
+					}
+				}
+			}
+
+			if customDataBase64Attr.IsNotNil() && customDataBase64Attr.IsString() {
+				encoded, err := base64.StdEncoding.DecodeString(customDataBase64Attr.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)) {
+					set.AddResult().
+						WithDescription("Resource '%s' has user_data_base64 with sensitive data.", resourceBlock.FullName()).
+						WithAttribute(customDataAttr)
+				}
+			}
+		},
+	})
+}
+
+func checkStringForSensitive(stringToCheck string) bool {
+	scanResult := squealer.NewStringScanner().Scan(stringToCheck)
+	return scanResult.TransgressionFound
+}
diff --git a/internal/app/tfsec/rules/aws/mq/enable_audit_logging_rule.go b/internal/app/tfsec/rules/aws/mq/enable_audit_logging_rule.go
new file mode 100644
index 000000000..aef7a0cb3
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/mq/enable_audit_logging_rule.go
@@ -0,0 +1,95 @@
+package mq
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "mq",
+		ShortCode: "enable-audit-logging",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "MQ Broker should have audit logging enabled",
+			Explanation: `Logging should be enabled to allow tracing of issues and activity to be investigated more fully. Logs provide additional information and context which is often invalauble during investigation`,
+			Impact:      "Without audit logging it is difficult to trace activity in the MQ broker",
+			Resolution:  "Enable audit logging",
+			BadExample: []string{  `
+resource "aws_mq_broker" "bad_example" {
+  broker_name = "example"
+
+  configuration {
+    id       = aws_mq_configuration.test.id
+    revision = aws_mq_configuration.test.latest_revision
+  }
+
+  engine_type        = "ActiveMQ"
+  engine_version     = "5.15.0"
+  host_instance_type = "mq.t2.micro"
+  security_groups    = [aws_security_group.test.id]
+
+  user {
+    username = "ExampleUser"
+    password = "MindTheGap"
+  }
+  logs {
+    audit = false
+  }
+}
+`},
+			GoodExample: []string{ `
+resource "aws_mq_broker" "good_example" {
+  broker_name = "example"
+
+  configuration {
+    id       = aws_mq_configuration.test.id
+    revision = aws_mq_configuration.test.latest_revision
+  }
+
+  engine_type        = "ActiveMQ"
+  engine_version     = "5.15.0"
+  host_instance_type = "mq.t2.micro"
+  security_groups    = [aws_security_group.test.id]
+
+  user {
+    username = "ExampleUser"
+    password = "MindTheGap"
+  }
+  logs {
+    audit = true
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/mq_broker#audit",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"aws_mq_broker",
+		},
+		DefaultSeverity: severity.Medium, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if auditAttr := resourceBlock.GetBlock("logs").GetAttribute("audit"); auditAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for logs.audit", resourceBlock.FullName())
+			} else if auditAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logs.audit set to true", resourceBlock.FullName()).
+					WithAttribute(auditAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/mq/enable_general_logging_rule.go b/internal/app/tfsec/rules/aws/mq/enable_general_logging_rule.go
new file mode 100644
index 000000000..baccbde87
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/mq/enable_general_logging_rule.go
@@ -0,0 +1,95 @@
+package mq
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "mq",
+		ShortCode: "enable-general-logging",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "MQ Broker should have general logging enabled",
+			Explanation: `Logging should be enabled to allow tracing of issues and activity to be investigated more fully. Logs provide additional information and context which is often invalauble during investigation`,
+			Impact:      "Without logging it is difficult to trace issues",
+			Resolution:  "Enable general logging",
+			BadExample: []string{  `
+resource "aws_mq_broker" "bad_example" {
+  broker_name = "example"
+
+  configuration {
+    id       = aws_mq_configuration.test.id
+    revision = aws_mq_configuration.test.latest_revision
+  }
+
+  engine_type        = "ActiveMQ"
+  engine_version     = "5.15.0"
+  host_instance_type = "mq.t2.micro"
+  security_groups    = [aws_security_group.test.id]
+
+  user {
+    username = "ExampleUser"
+    password = "MindTheGap"
+  }
+  logs {
+    general = false
+  }
+}
+`},
+			GoodExample: []string{ `
+resource "aws_mq_broker" "good_example" {
+  broker_name = "example"
+
+  configuration {
+    id       = aws_mq_configuration.test.id
+    revision = aws_mq_configuration.test.latest_revision
+  }
+
+  engine_type        = "ActiveMQ"
+  engine_version     = "5.15.0"
+  host_instance_type = "mq.t2.micro"
+  security_groups    = [aws_security_group.test.id]
+
+  user {
+    username = "ExampleUser"
+    password = "MindTheGap"
+  }
+  logs {
+    general = true
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/mq_broker#general",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"aws_mq_broker",
+		},
+		DefaultSeverity: severity.Low, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if generalAttr := resourceBlock.GetBlock("logs").GetAttribute("general"); generalAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for logs.general", resourceBlock.FullName())
+			} else if generalAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have logs.general set to true", resourceBlock.FullName()).
+					WithAttribute(generalAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/mq/no_public_access_rule.go b/internal/app/tfsec/rules/aws/mq/no_public_access_rule.go
new file mode 100644
index 000000000..0e6597e6e
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/mq/no_public_access_rule.go
@@ -0,0 +1,91 @@
+package mq
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "mq",
+		ShortCode: "no-public-access",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure MQ Broker is not publicly exposed",
+			Explanation: `Public access of the MQ broker should be disabled and only allow routes to applications that require access.`,
+			Impact:      "Publicly accessible MQ Broker may be vulnerable to compromise",
+			Resolution:  "Disable public access when not required",
+			BadExample: []string{  `
+resource "aws_mq_broker" "bad_example" {
+  broker_name = "example"
+
+  configuration {
+    id       = aws_mq_configuration.test.id
+    revision = aws_mq_configuration.test.latest_revision
+  }
+
+  engine_type        = "ActiveMQ"
+  engine_version     = "5.15.0"
+  host_instance_type = "mq.t2.micro"
+  security_groups    = [aws_security_group.test.id]
+
+  user {
+    username = "ExampleUser"
+    password = "MindTheGap"
+  }
+  publicly_accessible = true
+}
+`},
+			GoodExample: []string{ `
+resource "aws_mq_broker" "good_example" {
+  broker_name = "example"
+
+  configuration {
+    id       = aws_mq_configuration.test.id
+    revision = aws_mq_configuration.test.latest_revision
+  }
+
+  engine_type        = "ActiveMQ"
+  engine_version     = "5.15.0"
+  host_instance_type = "mq.t2.micro"
+  security_groups    = [aws_security_group.test.id]
+
+  user {
+    username = "ExampleUser"
+    password = "MindTheGap"
+  }
+  publicly_accessible = false
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/mq_broker#publicly_accessible",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"aws_mq_broker",
+		},
+		DefaultSeverity: severity.High, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if publiclyAccessibleAttr := resourceBlock.GetAttribute("publicly_accessible"); publiclyAccessibleAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for publicly_accessible", resourceBlock.FullName())
+			} else if publiclyAccessibleAttr.IsTrue() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have publicly_accessible set to false", resourceBlock.FullName()).
+					WithAttribute(publiclyAccessibleAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/msk/enable_logging_rule.go b/internal/app/tfsec/rules/aws/msk/enable_logging_rule.go
new file mode 100644
index 000000000..e2683285b
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/msk/enable_logging_rule.go
@@ -0,0 +1,188 @@
+package msk
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+// generator-locked
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "msk",
+		ShortCode: "enable-logging",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Ensure MSK Cluster logging is enabled",
+			Explanation: `Managed streaming for Kafka can log to Cloud Watch, Kinesis Firehose and S3, at least one of these locations should be logged to`,
+			Impact:      "Without logging it is difficult to trace issues",
+			Resolution:  "Enable logging",
+			BadExample: []string{`
+resource "aws_msk_cluster" "example" {
+  cluster_name           = "example"
+  kafka_version          = "2.4.1"
+  number_of_broker_nodes = 3
+
+  broker_node_group_info {
+    instance_type   = "kafka.m5.large"
+    ebs_volume_size = 1000
+    client_subnets = [
+      aws_subnet.subnet_az1.id,
+      aws_subnet.subnet_az2.id,
+      aws_subnet.subnet_az3.id,
+    ]
+    security_groups = [aws_security_group.sg.id]
+  }
+  tags = {
+    foo = "bar"
+  }
+}
+`},
+			GoodExample: []string{`
+resource "aws_msk_cluster" "example" {
+  cluster_name           = "example"
+  kafka_version          = "2.4.1"
+  number_of_broker_nodes = 3
+
+  broker_node_group_info {
+    instance_type   = "kafka.m5.large"
+    ebs_volume_size = 1000
+    client_subnets = [
+      aws_subnet.subnet_az1.id,
+      aws_subnet.subnet_az2.id,
+      aws_subnet.subnet_az3.id,
+    ]
+    security_groups = [aws_security_group.sg.id]
+  }
+
+  logging_info {
+    broker_logs {
+      firehose {
+        enabled         = false
+        delivery_stream = aws_kinesis_firehose_delivery_stream.test_stream.name
+      }
+      s3 {
+        enabled = true
+        bucket  = aws_s3_bucket.bucket.id
+        prefix  = "logs/msk-"
+      }
+    }
+  }
+
+  tags = {
+    foo = "bar"
+  }
+}
+`, `
+resource "aws_msk_cluster" "example" {
+  cluster_name           = "example"
+  kafka_version          = "2.4.1"
+  number_of_broker_nodes = 3
+
+  broker_node_group_info {
+    instance_type   = "kafka.m5.large"
+    ebs_volume_size = 1000
+    client_subnets = [
+      aws_subnet.subnet_az1.id,
+      aws_subnet.subnet_az2.id,
+      aws_subnet.subnet_az3.id,
+    ]
+    security_groups = [aws_security_group.sg.id]
+  }
+
+  logging_info {
+    broker_logs {
+      cloudwatch_logs {
+        enabled   = false
+        log_group = aws_cloudwatch_log_group.test.name
+      }
+      firehose {
+        enabled         = true
+        delivery_stream = aws_kinesis_firehose_delivery_stream.test_stream.name
+      }
+    }
+  }
+
+  tags = {
+    foo = "bar"
+  }
+}
+`, `
+resource "aws_msk_cluster" "example" {
+  cluster_name           = "example"
+  kafka_version          = "2.4.1"
+  number_of_broker_nodes = 3
+
+  broker_node_group_info {
+    instance_type   = "kafka.m5.large"
+    ebs_volume_size = 1000
+    client_subnets = [
+      aws_subnet.subnet_az1.id,
+      aws_subnet.subnet_az2.id,
+      aws_subnet.subnet_az3.id,
+    ]
+    security_groups = [aws_security_group.sg.id]
+  }
+
+  logging_info {
+    broker_logs {
+      cloudwatch_logs {
+        enabled   = true
+        log_group = aws_cloudwatch_log_group.test.name
+      }
+      firehose {
+        enabled         = false
+        delivery_stream = aws_kinesis_firehose_delivery_stream.test_stream.name
+      }
+      s3 {
+        enabled = true
+        bucket  = aws_s3_bucket.bucket.id
+        prefix  = "logs/msk-"
+      }
+    }
+  }
+
+  tags = {
+    foo = "bar"
+  }
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/msk_cluster#",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"aws_msk_cluster",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+
+			if cwLogAttr := resourceBlock.GetNestedAttribute("logging_info.broker_logs.cloudwatch_logs.enabled"); cwLogAttr.IsNotNil() && cwLogAttr.IsTrue() {
+				return
+			}
+
+			if firehoseLogAttr := resourceBlock.GetNestedAttribute("logging_info.broker_logs.firehose.enabled"); firehoseLogAttr.IsNotNil() && firehoseLogAttr.IsTrue() {
+				return
+			}
+
+			if s3LogAttr := resourceBlock.GetNestedAttribute("logging_info.broker_logs.s3.enabled"); s3LogAttr.IsNotNil() && s3LogAttr.IsTrue() {
+				return
+			}
+
+			set.AddResult().
+				WithDescription("Resource '%s' does not have any broker logging enabled", resourceBlock.FullName())
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/neptune/enable_log_export_rule.go b/internal/app/tfsec/rules/aws/neptune/enable_log_export_rule.go
new file mode 100644
index 000000000..333a7464f
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/neptune/enable_log_export_rule.go
@@ -0,0 +1,74 @@
+package neptune
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+// generator-locked
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "neptune",
+		ShortCode: "enable-log-export",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Nepture logs export should be enabled",
+			Explanation: `Neptune does not have auditing by default. To ensure that you are able to accurately audit the usage of your Neptune instance you should enable export logs.`,
+			Impact:      "Limited visibility of audit trail for changes to Neptune",
+			Resolution:  "Enable export logs",
+			BadExample: []string{`
+resource "aws_neptune_cluster" "bad_example" {
+  cluster_identifier                  = "neptune-cluster-demo"
+  engine                              = "neptune"
+  backup_retention_period             = 5
+  preferred_backup_window             = "07:00-09:00"
+  skip_final_snapshot                 = true
+  iam_database_authentication_enabled = true
+  apply_immediately                   = true
+  enable_cloudwatch_logs_exports      = []
+}
+`},
+			GoodExample: []string{`
+resource "aws_neptune_cluster" "good_example" {
+  cluster_identifier                  = "neptune-cluster-demo"
+  engine                              = "neptune"
+  backup_retention_period             = 5
+  preferred_backup_window             = "07:00-09:00"
+  skip_final_snapshot                 = true
+  iam_database_authentication_enabled = true
+  apply_immediately                   = true
+  enable_cloudwatch_logs_exports      = ["audit"]
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/neptune_cluster#enable_cloudwatch_logs_exports",
+			},
+		},
+		RequiredTypes: []string{
+			"resource",
+		},
+		RequiredLabels: []string{
+			"aws_neptune_cluster",
+		},
+		DefaultSeverity: severity.Medium,
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
+			if enableCloudwatchLogsExportsAttr := resourceBlock.GetAttribute("enable_cloudwatch_logs_exports"); enableCloudwatchLogsExportsAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for enable_cloudwatch_logs_exports", resourceBlock.FullName())
+			} else if enableCloudwatchLogsExportsAttr.NotContains("audit") {
+				set.AddResult().
+					WithDescription("Resource '%s' should have audit in enable_cloudwatch_logs_exports", resourceBlock.FullName()).
+					WithAttribute(enableCloudwatchLogsExportsAttr)
+			}
+		},
+	})
+}
diff --git a/internal/app/tfsec/rules/aws/neptune/enable_storage_encryption_rule.go b/internal/app/tfsec/rules/aws/neptune/enable_storage_encryption_rule.go
new file mode 100644
index 000000000..69435602d
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/neptune/enable_storage_encryption_rule.go
@@ -0,0 +1,73 @@
+package neptune
+
+// ATTENTION!
+// This rule was autogenerated!
+// Before making changes, consider updating the generator.
+
+import (
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext"
+	"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.AWSProvider,
+		Service:   "neptune",
+		ShortCode: "enable-storage-encryption",
+		Documentation: rule.RuleDocumentation{
+			Summary:     "Neptune storage must be encrypted at rest",
+			Explanation: `Encryption of Neptune storage ensures that if their is compromise of the disks, the data is still protected.`,
+			Impact:      "Unencrypted sensitive data is vulnerable to compromise.",
+			Resolution:  "Enable encryption of Neptune storage",
+			BadExample: []string{  `
+resource "aws_neptune_cluster" "bad_example" {
+  cluster_identifier                  = "neptune-cluster-demo"
+  engine                              = "neptune"
+  backup_retention_period             = 5
+  preferred_backup_window             = "07:00-09:00"
+  skip_final_snapshot                 = true
+  iam_database_authentication_enabled = true
+  apply_immediately                   = true
+  storage_encrypted = false
+}
+`},
+			GoodExample: []string{ `
+resource "aws_neptune_cluster" "good_example" {
+  cluster_identifier                  = "neptune-cluster-demo"
+  engine                              = "neptune"
+  backup_retention_period             = 5
+  preferred_backup_window             = "07:00-09:00"
+  skip_final_snapshot                 = true
+  iam_database_authentication_enabled = true
+  apply_immediately                   = true
+  storage_encrypted = true
+}
+`},
+			Links: []string{
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/neptune_cluster#storage_encrypted",
+			},
+		},
+		RequiredTypes:  []string{ 
+			"resource",
+		},
+		RequiredLabels: []string{ 
+			"aws_neptune_cluster",
+		},
+		DefaultSeverity: severity.High, 
+		CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
+			if storageEncryptedAttr := resourceBlock.GetAttribute("storage_encrypted"); storageEncryptedAttr.IsNil() { // alert on use of default value
+				set.AddResult().
+					WithDescription("Resource '%s' uses default value for storage_encrypted", resourceBlock.FullName())
+			} else if storageEncryptedAttr.IsFalse() {
+				set.AddResult().
+					WithDescription("Resource '%s' does not have storage_encrypted set to true", resourceBlock.FullName()).
+					WithAttribute(storageEncryptedAttr)
+			}
+		},
+	})
+}
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 38e29dccf..0265a8ac2 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
@@ -70,7 +70,7 @@ EOF
 					}
 				}
 			} else if customDataAttr.IsResolvable() && customDataAttr.IsString() {
-				encoded, err := base64.RawStdEncoding.DecodeString(customDataAttr.Value().AsString())
+				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())


Test patch:
diff --git a/internal/app/tfsec/rules/aws/documentdb/encryption_customer_key_rule_test.go b/internal/app/tfsec/rules/aws/documentdb/encryption_customer_key_rule_test.go
new file mode 100644
index 000000000..048293b3d
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/documentdb/encryption_customer_key_rule_test.go
@@ -0,0 +1,53 @@
+package documentdb
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSEncryptionCustomerKey_FailureExamples(t *testing.T) {
+	expectedCode := "aws-documentdb-encryption-customer-key"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSEncryptionCustomerKey_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-documentdb-encryption-customer-key"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/ebs/encryption_customer_key_rule_test.go b/internal/app/tfsec/rules/aws/ebs/encryption_customer_key_rule_test.go
new file mode 100644
index 000000000..4f57ae554
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/ebs/encryption_customer_key_rule_test.go
@@ -0,0 +1,53 @@
+package ebs
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSEncryptionCustomerKey_FailureExamples(t *testing.T) {
+	expectedCode := "aws-ebs-encryption-customer-key"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSEncryptionCustomerKey_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-ebs-encryption-customer-key"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/ecr/no_public_access_rule_test.go b/internal/app/tfsec/rules/aws/ecr/no_public_access_rule_test.go
new file mode 100644
index 000000000..487873f96
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/ecr/no_public_access_rule_test.go
@@ -0,0 +1,53 @@
+package ecr
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSNoPublicAccess_FailureExamples(t *testing.T) {
+	expectedCode := "aws-ecr-no-public-access"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSNoPublicAccess_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-ecr-no-public-access"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/launch/no_sensitive_info_rule_test.go b/internal/app/tfsec/rules/aws/launch/no_sensitive_info_rule_test.go
new file mode 100644
index 000000000..54e32c67d
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/launch/no_sensitive_info_rule_test.go
@@ -0,0 +1,53 @@
+package launch
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSNoSensitiveInfo_FailureExamples(t *testing.T) {
+	expectedCode := "aws-launch-no-sensitive-info"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSNoSensitiveInfo_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-launch-no-sensitive-info"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/mq/enable_audit_logging_rule_test.go b/internal/app/tfsec/rules/aws/mq/enable_audit_logging_rule_test.go
new file mode 100644
index 000000000..3ba4dbdaa
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/mq/enable_audit_logging_rule_test.go
@@ -0,0 +1,53 @@
+package mq
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSEnableAuditLogging_FailureExamples(t *testing.T) {
+	expectedCode := "aws-mq-enable-audit-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSEnableAuditLogging_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-mq-enable-audit-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/mq/enable_general_logging_rule_test.go b/internal/app/tfsec/rules/aws/mq/enable_general_logging_rule_test.go
new file mode 100644
index 000000000..4db4e9ede
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/mq/enable_general_logging_rule_test.go
@@ -0,0 +1,53 @@
+package mq
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSEnableGeneralLogging_FailureExamples(t *testing.T) {
+	expectedCode := "aws-mq-enable-general-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSEnableGeneralLogging_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-mq-enable-general-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/mq/no_public_access_rule_test.go b/internal/app/tfsec/rules/aws/mq/no_public_access_rule_test.go
new file mode 100644
index 000000000..2bd11ac84
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/mq/no_public_access_rule_test.go
@@ -0,0 +1,53 @@
+package mq
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSNoPublicAccess_FailureExamples(t *testing.T) {
+	expectedCode := "aws-mq-no-public-access"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSNoPublicAccess_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-mq-no-public-access"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/msk/enable_logging_rule_test.go b/internal/app/tfsec/rules/aws/msk/enable_logging_rule_test.go
new file mode 100644
index 000000000..0dd6aee7f
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/msk/enable_logging_rule_test.go
@@ -0,0 +1,53 @@
+package msk
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSEnableLogging_FailureExamples(t *testing.T) {
+	expectedCode := "aws-msk-enable-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSEnableLogging_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-msk-enable-logging"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/neptune/enable_log_export_rule_test.go b/internal/app/tfsec/rules/aws/neptune/enable_log_export_rule_test.go
new file mode 100644
index 000000000..fb4996755
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/neptune/enable_log_export_rule_test.go
@@ -0,0 +1,53 @@
+package neptune
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSEnableLogExport_FailureExamples(t *testing.T) {
+	expectedCode := "aws-neptune-enable-log-export"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSEnableLogExport_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-neptune-enable-log-export"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/aws/neptune/enable_storage_encryption_rule_test.go b/internal/app/tfsec/rules/aws/neptune/enable_storage_encryption_rule_test.go
new file mode 100644
index 000000000..177aac63a
--- /dev/null
+++ b/internal/app/tfsec/rules/aws/neptune/enable_storage_encryption_rule_test.go
@@ -0,0 +1,53 @@
+package neptune
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+)
+
+func Test_AWSEnableStorageEncryption_FailureExamples(t *testing.T) {
+	expectedCode := "aws-neptune-enable-storage-encryption"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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_AWSEnableStorageEncryption_SuccessExamples(t *testing.T) {
+	expectedCode := "aws-neptune-enable-storage-encryption"
+
+	rule, err := scanner.GetRuleById(expectedCode)
+	if err != nil {
+		t.FailNow()
+	}
+	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/google/iam/no_project_level_default_service_account_assignment_rule_test.go b/internal/app/tfsec/rules/google/iam/no_project_level_default_service_account_assignment_rule_test.go
index ddad9f33c..76b03dd5a 100644
--- a/internal/app/tfsec/rules/google/iam/no_project_level_default_service_account_assignment_rule_test.go
+++ b/internal/app/tfsec/rules/google/iam/no_project_level_default_service_account_assignment_rule_test.go
@@ -9,7 +9,7 @@ import (
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
 )
 
-func Test_GoogleNoDefaultServiceAccountAssignment_FailureExamples(t *testing.T) {
+func Test_GoogleNoDefaultServiceAccountAtProjectAssignment_FailureExamples(t *testing.T) {
 	expectedCode := "google-iam-no-project-level-default-service-account-assignment"
 
 	check, err := scanner.GetRuleById(expectedCode)
@@ -31,7 +31,7 @@ func Test_GoogleNoDefaultServiceAccountAssignment_FailureExamples(t *testing.T)
 	}
 }
 
-func Test_GoogleNoDefaultServiceAccountAssignment_SuccessExamples(t *testing.T) {
+func Test_GoogleNoDefaultServiceAccountAtProjectAssignment_SuccessExamples(t *testing.T) {
 	expectedCode := "google-iam-no-project-level-default-service-account-assignment"
 
 	check, err := scanner.GetRuleById(expectedCode)