Repository: tfsec/tfsec
Pull request #667 (2021-03-27 22:37:20)

Adding some S3 based checks


Patch:
diff --git a/go.mod b/go.mod
index 09d4faa00..236b35491 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.16
 
 require (
 	github.com/hashicorp/hcl/v2 v2.9.1
-	github.com/hashicorp/terraform v0.14.8
+	github.com/hashicorp/terraform v0.14.9
 	github.com/liamg/clinch v1.5.6
 	github.com/liamg/tml v0.4.0
 	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
diff --git a/go.sum b/go.sum
index 2ad3e929f..4ca1fe41d 100644
--- a/go.sum
+++ b/go.sum
@@ -274,6 +274,8 @@ github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZa
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/hashicorp/terraform v0.14.8 h1:m2ytUbgJCAfySARVCd5cjbcMHhtfaozNaDDOFxpZBXk=
 github.com/hashicorp/terraform v0.14.8/go.mod h1:K/LAcRZgbGdSBY+3NB9qdLSPkkFdZ+bTrbzpZ65p4BY=
+github.com/hashicorp/terraform v0.14.9 h1:hZ8s+YuOee7A1o3kOVyBNQs7C4bVqzSHg5TiS6jOkps=
+github.com/hashicorp/terraform v0.14.9/go.mod h1:K/LAcRZgbGdSBY+3NB9qdLSPkkFdZ+bTrbzpZ65p4BY=
 github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A=
 github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
diff --git a/internal/app/tfsec/checks/aws034.go b/internal/app/tfsec/checks/aws034.go
index 50e719f44..e5302c005 100644
--- a/internal/app/tfsec/checks/aws034.go
+++ b/internal/app/tfsec/checks/aws034.go
@@ -66,8 +66,6 @@ func init() {
 						scanner.SeverityError,
 					),
 				}
-
-				return nil
 			}
 
 			if tlsPolicyAttr.Value().Equals(cty.StringVal("Policy-Min-TLS-1-0-2019-07")).True() {
diff --git a/internal/app/tfsec/checks/aws048.go b/internal/app/tfsec/checks/aws048.go
index bd8c9b17c..23f1ab1c9 100644
--- a/internal/app/tfsec/checks/aws048.go
+++ b/internal/app/tfsec/checks/aws048.go
@@ -2,6 +2,7 @@ package checks
 
 import (
 	"fmt"
+
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 	"github.com/zclconf/go-cty/cty"
@@ -65,8 +66,6 @@ func init() {
 				}
 			}
 			return nil
-
-			return nil
 		},
 	})
 }
diff --git a/internal/app/tfsec/checks/aws071.go b/internal/app/tfsec/checks/aws071.go
index ea4178cf4..59a82f91f 100644
--- a/internal/app/tfsec/checks/aws071.go
+++ b/internal/app/tfsec/checks/aws071.go
@@ -2,6 +2,7 @@ package checks
 
 import (
 	"fmt"
+
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 )
@@ -49,7 +50,7 @@ func init() {
 			if block.MissingChild("logging_config") {
 				return []scanner.Result{
 					check.NewResult(
-						fmt.Sprintf("Cloudfront distribution '%s' does not have Access Logging configured", block.FullName()),
+						fmt.Sprintf("Resource '%s' does not have Access Logging configured", block.FullName()),
 						block.Range(),
 						scanner.SeverityError,
 					),
diff --git a/internal/app/tfsec/checks/aws072.go b/internal/app/tfsec/checks/aws072.go
index 82f69bfbe..885d8ae78 100644
--- a/internal/app/tfsec/checks/aws072.go
+++ b/internal/app/tfsec/checks/aws072.go
@@ -2,6 +2,7 @@ package checks
 
 import (
 	"fmt"
+
 	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
 	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
 )
@@ -79,7 +80,7 @@ func init() {
 			if defaultCacheBlock.GetAttribute("viewer_protocol_policy").Equals("allow-all", parser.IgnoreCase) {
 				return []scanner.Result{
 					check.NewResult(
-						fmt.Sprintf("Cloudfront distribution cache '%s' does not use HTTPS in Viewer Protocol Policy", block.FullName()),
+						fmt.Sprintf("Resource '%s' does not use HTTPS in Viewer Protocol Policy", block.FullName()),
 						defaultCacheBlock.Range(),
 						scanner.SeverityError,
 					),
@@ -91,7 +92,7 @@ func init() {
 				if orderedCacheBlock.GetAttribute("viewer_protocol_policy").Equals("allow-all", parser.IgnoreCase) {
 					return []scanner.Result{
 						check.NewResult(
-							fmt.Sprintf("Cloudfront distribution cache '%s' does not use HTTPS in Viewer Protocol Policy", block.FullName()),
+							fmt.Sprintf("Resource '%s' does not use HTTPS in Viewer Protocol Policy", block.FullName()),
 							orderedCacheBlock.Range(),
 							scanner.SeverityError,
 						),
diff --git a/internal/app/tfsec/checks/aws073.go b/internal/app/tfsec/checks/aws073.go
new file mode 100644
index 000000000..5813ab4ab
--- /dev/null
+++ b/internal/app/tfsec/checks/aws073.go
@@ -0,0 +1,76 @@
+package checks
+
+import (
+	"fmt"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+const AWSIngorePublicAclS3 scanner.RuleCode = "AWS073"
+const AWSIngorePublicAclS3Description scanner.RuleSummary = "S3 Access Block should Ignore Public Acl"
+const AWSIngorePublicAclS3Explanation = `
+S3 buckets should ignore public ACLs on buckets and any objects they contain. By ignoring rather than blocking, PUT calls with public ACLs will still be applied but the ACL will be ignored.
+`
+const AWSIngorePublicAclS3BadExample = `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	ignore_public_acls = false
+}
+`
+const AWSIngorePublicAclS3GoodExample = `
+resource "aws_s3_bucket_public_access_block" "good_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	ignore_public_acls = true
+}
+`
+
+func init() {
+	scanner.RegisterCheck(scanner.Check{
+		Code: AWSIngorePublicAclS3,
+		Documentation: scanner.CheckDocumentation{
+			Summary:     AWSIngorePublicAclS3Description,
+			Explanation: AWSIngorePublicAclS3Explanation,
+			BadExample:  AWSIngorePublicAclS3BadExample,
+			GoodExample: AWSIngorePublicAclS3GoodExample,
+			Links: []string{
+				"https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html",
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block#ignore_public_acls",
+			},
+		},
+		Provider:       scanner.AWSProvider,
+		RequiredTypes:  []string{"resource"},
+		RequiredLabels: []string{"aws_s3_bucket_public_access_block"},
+		CheckFunc: func(check *scanner.Check, block *parser.Block, _ *scanner.Context) []scanner.Result {
+
+			if block.MissingChild("ignore_public_acls") {
+				return []scanner.Result{
+					check.NewResult(
+						fmt.Sprintf("Resource '%s' does not specify ignore_public_acls, defaults to false", block.FullName()),
+						block.Range(),
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			attr := block.GetAttribute("ignore_public_acls")
+			if attr.IsFalse() {
+				return []scanner.Result{
+					check.NewResultWithValueAnnotation(
+						fmt.Sprintf("Resource '%s' sets ignore_public_acls explicitly to false", block.FullName()),
+						attr.Range(),
+						attr,
+						scanner.SeverityError,
+					),
+				}
+			}
+			return nil
+		},
+	})
+}
diff --git a/internal/app/tfsec/checks/aws074.go b/internal/app/tfsec/checks/aws074.go
new file mode 100644
index 000000000..077207f22
--- /dev/null
+++ b/internal/app/tfsec/checks/aws074.go
@@ -0,0 +1,75 @@
+package checks
+
+import (
+	"fmt"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+const AWSBlockPublicAclS3 scanner.RuleCode = "AWS074"
+const AWSBlockPublicAclS3Description scanner.RuleSummary = "S3 Access block should block public ACL"
+const AWSBlockPublicAclS3Explanation = `
+S3 buckets should block public ACLs on buckets and any objects they contain. By blocking, PUTs with fail if the object has any public ACL a.
+`
+const AWSBlockPublicAclS3BadExample = `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	block_public_acls = false
+}
+`
+const AWSBlockPublicAclS3GoodExample = `
+resource "aws_s3_bucket_public_access_block" "good_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	block_public_acls = true
+}
+`
+
+func init() {
+	scanner.RegisterCheck(scanner.Check{
+		Code: AWSBlockPublicAclS3,
+		Documentation: scanner.CheckDocumentation{
+			Summary:     AWSBlockPublicAclS3Description,
+			Explanation: AWSBlockPublicAclS3Explanation,
+			BadExample:  AWSBlockPublicAclS3BadExample,
+			GoodExample: AWSBlockPublicAclS3GoodExample,
+			Links: []string{
+				"https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html",
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block#block_public_acls",
+			},
+		},
+		Provider:       scanner.AWSProvider,
+		RequiredTypes:  []string{"resource"},
+		RequiredLabels: []string{"aws_s3_bucket_public_access_block"},
+		CheckFunc: func(check *scanner.Check, block *parser.Block, _ *scanner.Context) []scanner.Result {
+			if block.MissingChild("block_public_acls") {
+				return []scanner.Result{
+					check.NewResult(
+						fmt.Sprintf("Resource '%s' does not specify block_public_acls, defaults to false", block.FullName()),
+						block.Range(),
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			attr := block.GetAttribute("block_public_acls")
+			if attr.IsFalse() {
+				return []scanner.Result{
+					check.NewResultWithValueAnnotation(
+						fmt.Sprintf("Resource '%s' sets block_public_acls explicitly to false", block.FullName()),
+						attr.Range(),
+						attr,
+						scanner.SeverityError,
+					),
+				}
+			}
+			return nil
+		},
+	})
+}
diff --git a/internal/app/tfsec/checks/aws075.go b/internal/app/tfsec/checks/aws075.go
new file mode 100644
index 000000000..e03f6ba4d
--- /dev/null
+++ b/internal/app/tfsec/checks/aws075.go
@@ -0,0 +1,75 @@
+package checks
+
+import (
+	"fmt"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+const AWSRestrictPublicBucketS3 scanner.RuleCode = "AWS075"
+const AWSRestrictPublicBucketS3Description scanner.RuleSummary = "S3 Access block should restrict public bucket to limit access"
+const AWSRestrictPublicBucketS3Explanation = `
+S3 buckets should restrict public policies for the bucket. By enabling, the restrict_public_buckets, only the bucket owner and AWS Services can access if it has a public policy.
+`
+const AWSRestrictPublicBucketS3BadExample = `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	restrict_public_buckets = false
+}
+`
+const AWSRestrictPublicBucketS3GoodExample = `
+resource "aws_s3_bucket_public_access_block" "good_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	restrict_public_buckets = true
+}
+`
+
+func init() {
+	scanner.RegisterCheck(scanner.Check{
+		Code: AWSRestrictPublicBucketS3,
+		Documentation: scanner.CheckDocumentation{
+			Summary:     AWSRestrictPublicBucketS3Description,
+			Explanation: AWSRestrictPublicBucketS3Explanation,
+			BadExample:  AWSRestrictPublicBucketS3BadExample,
+			GoodExample: AWSRestrictPublicBucketS3GoodExample,
+			Links: []string{
+				"https://docs.aws.amazon.com/AmazonS3/latest/dev-retired/access-control-block-public-access.html",
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block#restrict_public_buckets¡",
+			},
+		},
+		Provider:       scanner.AWSProvider,
+		RequiredTypes:  []string{"resource"},
+		RequiredLabels: []string{"aws_s3_bucket_public_access_block"},
+		CheckFunc: func(check *scanner.Check, block *parser.Block, _ *scanner.Context) []scanner.Result {
+			if block.MissingChild("restrict_public_buckets") {
+				return []scanner.Result{
+					check.NewResult(
+						fmt.Sprintf("Resource '%s' does not specify restrict_public_buckets, defaults to false", block.FullName()),
+						block.Range(),
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			attr := block.GetAttribute("restrict_public_buckets")
+			if attr.IsFalse() {
+				return []scanner.Result{
+					check.NewResultWithValueAnnotation(
+						fmt.Sprintf("Resource '%s' sets restrict_public_buckets explicitly to false", block.FullName()),
+						attr.Range(),
+						attr,
+						scanner.SeverityError,
+					),
+				}
+			}
+			return nil
+		},
+	})
+}
diff --git a/internal/app/tfsec/checks/aws076.go b/internal/app/tfsec/checks/aws076.go
new file mode 100644
index 000000000..de2f3492b
--- /dev/null
+++ b/internal/app/tfsec/checks/aws076.go
@@ -0,0 +1,75 @@
+package checks
+
+import (
+	"fmt"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+const AWSBlockPublicPolicyS3 scanner.RuleCode = "AWS076"
+const AWSBlockPublicPolicyS3Description scanner.RuleSummary = "S3 Access block should block public policy"
+const AWSBlockPublicPolicyS3Explanation = `
+S3 bucket policy should have block public policy to prevent users from PUTing a policy that enable public access.
+`
+const AWSBlockPublicPolicyS3BadExample = `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	block_public_policy = false
+}
+`
+const AWSBlockPublicPolicyS3GoodExample = `
+resource "aws_s3_bucket_public_access_block" "good_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	block_public_policy = true
+}
+`
+
+func init() {
+	scanner.RegisterCheck(scanner.Check{
+		Code: AWSBlockPublicPolicyS3,
+		Documentation: scanner.CheckDocumentation{
+			Summary:     AWSBlockPublicPolicyS3Description,
+			Explanation: AWSBlockPublicPolicyS3Explanation,
+			BadExample:  AWSBlockPublicPolicyS3BadExample,
+			GoodExample: AWSBlockPublicPolicyS3GoodExample,
+			Links: []string{
+				"https://docs.aws.amazon.com/AmazonS3/latest/dev-retired/access-control-block-public-access.html",
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block#block_public_policy",
+			},
+		},
+		Provider:       scanner.AWSProvider,
+		RequiredTypes:  []string{"resource"},
+		RequiredLabels: []string{"aws_s3_bucket_public_access_block"},
+		CheckFunc: func(check *scanner.Check, block *parser.Block, _ *scanner.Context) []scanner.Result {
+			if block.MissingChild("block_public_policy") {
+				return []scanner.Result{
+					check.NewResult(
+						fmt.Sprintf("Resource '%s' does not specify block_public_policy, defaults to false", block.FullName()),
+						block.Range(),
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			attr := block.GetAttribute("block_public_policy")
+			if attr.IsFalse() {
+				return []scanner.Result{
+					check.NewResultWithValueAnnotation(
+						fmt.Sprintf("Resource '%s' sets block_public_policy explicitly to false", block.FullName()),
+						attr.Range(),
+						attr,
+						scanner.SeverityError,
+					),
+				}
+			}
+			return nil
+		},
+	})
+}
diff --git a/internal/app/tfsec/checks/aws077.go b/internal/app/tfsec/checks/aws077.go
new file mode 100644
index 000000000..8d92816f3
--- /dev/null
+++ b/internal/app/tfsec/checks/aws077.go
@@ -0,0 +1,73 @@
+package checks
+
+import (
+	"fmt"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/parser"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+const AWSS3DataShouldBeVersioned scanner.RuleCode = "AWS077"
+const AWSS3DataShouldBeVersionedDescription scanner.RuleSummary = "S3 Data should be versioned"
+const AWSS3DataShouldBeVersionedExplanation = `
+Versioning in Amazon S3 is a means of keeping multiple variants of an object in the same bucket. 
+You can use the S3 Versioning feature to preserve, retrieve, and restore every version of every object stored in your buckets. 
+With versioning you can recover more easily from both unintended user actions and application failures.
+`
+const AWSS3DataShouldBeVersionedBadExample = `
+resource "aws_s3_bucket" "bad_example" {
+
+}
+`
+const AWSS3DataShouldBeVersionedGoodExample = `
+resource "aws_s3_bucket" "good_example" {
+
+	versioning {
+		enabled = true
+	}
+}
+`
+
+func init() {
+	scanner.RegisterCheck(scanner.Check{
+		Code: AWSS3DataShouldBeVersioned,
+		Documentation: scanner.CheckDocumentation{
+			Summary:     AWSS3DataShouldBeVersionedDescription,
+			Explanation: AWSS3DataShouldBeVersionedExplanation,
+			BadExample:  AWSS3DataShouldBeVersionedBadExample,
+			GoodExample: AWSS3DataShouldBeVersionedGoodExample,
+			Links: []string{
+				"https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html",
+				"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket#versioning",
+			},
+		},
+		Provider:       scanner.AWSProvider,
+		RequiredTypes:  []string{"resource"},
+		RequiredLabels: []string{"aws_s3_bucket"},
+		CheckFunc: func(check *scanner.Check, block *parser.Block, _ *scanner.Context) []scanner.Result {
+
+			if block.MissingChild("versioning") {
+				return []scanner.Result{
+					check.NewResult(
+						fmt.Sprintf("Resource '%s' does not have versioning enabled", block.FullName()),
+						block.Range(),
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			versioningBlock := block.GetBlock("versioning")
+			if versioningBlock.HasChild("enabled") && versioningBlock.GetAttribute("enabled").IsFalse() {
+				return []scanner.Result{
+					check.NewResult(
+						fmt.Sprintf("Resource '%s' has versioning block but is disabled", block.FullName()),
+						block.Range(),
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			return nil
+		},
+	})
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index bb529c18b..ab416e5a9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -24,7 +24,7 @@ github.com/hashicorp/hcl/v2/ext/tryfunc
 github.com/hashicorp/hcl/v2/hclparse
 github.com/hashicorp/hcl/v2/hclsyntax
 github.com/hashicorp/hcl/v2/json
-# github.com/hashicorp/terraform v0.14.8
+# github.com/hashicorp/terraform v0.14.9
 ## explicit
 github.com/hashicorp/terraform/lang/funcs
 github.com/hashicorp/terraform/tfdiags


Test patch:
diff --git a/internal/app/tfsec/test/aws073_test.go b/internal/app/tfsec/test/aws073_test.go
new file mode 100644
index 000000000..8fa4d4753
--- /dev/null
+++ b/internal/app/tfsec/test/aws073_test.go
@@ -0,0 +1,58 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/checks"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+func Test_AWSIngorePublicAclS3(t *testing.T) {
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode scanner.RuleCode
+		mustExcludeResultCode scanner.RuleCode
+	}{
+		{
+			name: "Check fails when ignore public acls not set (default false)",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+`,
+			mustIncludeResultCode: checks.AWSIngorePublicAclS3,
+		},
+		{
+			name: "Check fails when ignore public acls explicitly set to false",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	ignore_public_acls = false
+}
+`,
+			mustIncludeResultCode: checks.AWSIngorePublicAclS3,
+		},
+		{
+			name: "Check passes when ignore_public_acls present and set to true",
+			source: `
+resource "aws_s3_bucket_public_access_block" "good_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	ignore_public_acls = true
+}
+`,
+			mustExcludeResultCode: checks.AWSIngorePublicAclS3,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			results := scanSource(test.source)
+			assertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+
+}
diff --git a/internal/app/tfsec/test/aws074_test.go b/internal/app/tfsec/test/aws074_test.go
new file mode 100644
index 000000000..e3575cd7a
--- /dev/null
+++ b/internal/app/tfsec/test/aws074_test.go
@@ -0,0 +1,58 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/checks"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+func Test_AWSBlockPublicAclS3(t *testing.T) {
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode scanner.RuleCode
+		mustExcludeResultCode scanner.RuleCode
+	}{
+		{
+			name: "Check fails when block_public_acls not set, defaults to false",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+`,
+			mustIncludeResultCode: checks.AWSBlockPublicAclS3,
+		},
+		{
+			name: "Check fails when block_public_acls set but false",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	block_public_acls = false
+}
+`,
+			mustIncludeResultCode: checks.AWSBlockPublicAclS3,
+		},
+		{
+			name: "Check passes when block_public_acls set to true",
+			source: `
+resource "aws_s3_bucket_public_access_block" "good_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	block_public_acls = true
+}
+`,
+			mustExcludeResultCode: checks.AWSBlockPublicAclS3,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			results := scanSource(test.source)
+			assertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+
+}
diff --git a/internal/app/tfsec/test/aws075_test.go b/internal/app/tfsec/test/aws075_test.go
new file mode 100644
index 000000000..100b3413b
--- /dev/null
+++ b/internal/app/tfsec/test/aws075_test.go
@@ -0,0 +1,58 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/checks"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+func Test_AWSRestrictPublicBucketS3(t *testing.T) {
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode scanner.RuleCode
+		mustExcludeResultCode scanner.RuleCode
+	}{
+		{
+			name: "Check fails when restrict public buckets is not set, defaults to false",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+`,
+			mustIncludeResultCode: checks.AWSRestrictPublicBucketS3,
+		},
+		{
+			name: "Check fails when restrict public buckets is set but is false",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	restrict_public_buckets = false
+}
+`,
+			mustIncludeResultCode: checks.AWSRestrictPublicBucketS3,
+		},
+		{
+			name: "Check passes when restrict public buckets is set to true",
+			source: `
+resource "aws_s3_bucket_public_access_block" "good_example" {
+	bucket = aws_s3_bucket.example.id
+  
+	restrict_public_buckets = true
+}
+`,
+			mustExcludeResultCode: checks.AWSRestrictPublicBucketS3,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			results := scanSource(test.source)
+			assertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+
+}
diff --git a/internal/app/tfsec/test/aws076_test.go b/internal/app/tfsec/test/aws076_test.go
new file mode 100644
index 000000000..a77805490
--- /dev/null
+++ b/internal/app/tfsec/test/aws076_test.go
@@ -0,0 +1,58 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/checks"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+func Test_AWSBlockPublicPolicyS3(t *testing.T) {
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode scanner.RuleCode
+		mustExcludeResultCode scanner.RuleCode
+	}{
+		{
+			name: "Check fails when block_public_policy not set, defaults to false",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+}
+`,
+			mustIncludeResultCode: checks.AWSBlockPublicPolicyS3,
+		},
+		{
+			name: "Check fails when block_public_policy set but is false",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+
+	block_public_policy = false
+}
+`,
+			mustIncludeResultCode: checks.AWSBlockPublicPolicyS3,
+		},
+		{
+			name: "Check passes when block_public_policy is true",
+			source: `
+resource "aws_s3_bucket_public_access_block" "bad_example" {
+	bucket = aws_s3_bucket.example.id
+
+	block_public_policy = true
+}
+`,
+			mustExcludeResultCode: checks.AWSBlockPublicPolicyS3,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			results := scanSource(test.source)
+			assertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+
+}
diff --git a/internal/app/tfsec/test/aws077_test.go b/internal/app/tfsec/test/aws077_test.go
new file mode 100644
index 000000000..5c7061d68
--- /dev/null
+++ b/internal/app/tfsec/test/aws077_test.go
@@ -0,0 +1,47 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/tfsec/tfsec/internal/app/tfsec/checks"
+	"github.com/tfsec/tfsec/internal/app/tfsec/scanner"
+)
+
+func Test_AWSS3DataShouldBeVersioned(t *testing.T) {
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode scanner.RuleCode
+		mustExcludeResultCode scanner.RuleCode
+	}{
+		{
+			name: "Check fails if bucket has no versioning block",
+			source: `
+resource "aws_s3_bucket" "bad_example" {
+
+}
+`,
+			mustIncludeResultCode: checks.AWSS3DataShouldBeVersioned,
+		},
+		{
+			name: "Check passes if versioning block present and enabled",
+			source: `
+resource "aws_s3_bucket" "good_example" {
+	versioning {
+		
+	}
+}
+`,
+			mustExcludeResultCode: checks.AWSS3DataShouldBeVersioned,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			results := scanSource(test.source)
+			assertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+
+}