Repository: aquasecurity/tfsec
Pull request #1329 (2022-01-14 13:57:13)

AWS DynamoDB adapt to use defsec
Since SSE is checked by https://github.com/aquasecurity/defsec/blob/master/rules/aws/dynamodb/enable_at_rest_encryption.go
case `"DynamoDB Table with disabled server side encryption fails check"` has been moved to the test file that corresponds to the mentioned check.

Closes #1313 


Patch:
diff --git a/internal/app/tfsec/adapter/aws/dynamodb/adapt.go b/internal/app/tfsec/adapter/aws/dynamodb/adapt.go
index 711e9cb20..74d8b3e80 100644
--- a/internal/app/tfsec/adapter/aws/dynamodb/adapt.go
+++ b/internal/app/tfsec/adapter/aws/dynamodb/adapt.go
@@ -2,9 +2,64 @@ package dynamodb
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/dynamodb"
+	"github.com/aquasecurity/defsec/types"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 )
 
 func Adapt(modules []block.Module) dynamodb.DynamoDB {
-	return dynamodb.DynamoDB{}
+	return dynamodb.DynamoDB{
+		DAXClusters: adaptClusters(modules),
+	}
+}
+
+func adaptClusters(modules []block.Module) []dynamodb.DAXCluster {
+	var clusters []dynamodb.DAXCluster
+	for _, module := range modules {
+		for _, resource := range module.GetResourcesByType("aws_dax_cluster") {
+			clusters = append(clusters, adaptCluster(resource, module))
+		}
+		for _, resource := range module.GetResourcesByType("aws_dynamodb_table") {
+			clusters = append(clusters, adaptCluster(resource, module))
+		}
+	}
+	return clusters
+}
+
+func adaptCluster(resource block.Block, module block.Module) dynamodb.DAXCluster {
+	sseEnabledVal := types.BoolDefault(false, *resource.GetMetadata())
+	kmsKeyIdVal := types.StringDefault("", *resource.GetMetadata())
+	recoveryEnabledVal := types.BoolDefault(false, *resource.GetMetadata())
+
+	if resource.HasChild("server_side_encryption") {
+		ssEncryptionBlock := resource.GetBlock("server_side_encryption")
+		enabledAttr := ssEncryptionBlock.GetAttribute("enabled")
+		sseEnabledVal = enabledAttr.AsBoolValueOrDefault(false, ssEncryptionBlock)
+
+		if resource.TypeLabel() == "aws_dynamodb_table" {
+			kmsKeyIdAttr := ssEncryptionBlock.GetAttribute("kms_key_arn")
+
+			kmsData, err := module.GetReferencedBlock(kmsKeyIdAttr, resource)
+			if err == nil && kmsData.IsNotNil() && kmsData.GetAttribute("key_id").IsNotNil() {
+				kmsKeyIdAttr = kmsData.GetAttribute("key_id")
+			}
+
+			kmsKeyIdVal = kmsKeyIdAttr.AsStringValueOrDefault("alias/aws/dynamodb", ssEncryptionBlock)
+		}
+	}
+
+	if resource.HasChild("point_in_time_recovery") {
+		recoveryBlock := resource.GetBlock("point_in_time_recovery")
+		recoveryEnabledAttr := recoveryBlock.GetAttribute("enabled")
+		recoveryEnabledVal = recoveryEnabledAttr.AsBoolValueOrDefault(false, recoveryBlock)
+	}
+
+	return dynamodb.DAXCluster{
+		Metadata: *resource.GetMetadata(),
+		ServerSideEncryption: dynamodb.ServerSideEncryption{
+			Enabled:  sseEnabledVal,
+			KMSKeyID: kmsKeyIdVal,
+		},
+		PointInTimeRecovery: recoveryEnabledVal,
+	}
+
 }
diff --git a/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule.go b/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule.go
index 13bbd8def..750a4cc67 100644
--- a/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule.go
+++ b/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule.go
@@ -1,9 +1,7 @@
 package dynamodb
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/dynamodb"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -47,22 +45,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_dax_cluster"},
 		Base:           dynamodb.CheckEnableAtRestEncryption,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-			if resourceBlock.MissingChild("server_side_encryption") {
-				results.Add("DAX cluster '%s' does not have server side encryption configured. By default it is disabled.", resourceBlock)
-				return
-			}
-
-			sseBlock := resourceBlock.GetBlock("server_side_encryption")
-			if sseBlock.MissingChild("enabled") {
-				results.Add("DAX cluster '%s' server side encryption block is empty. By default SSE is disabled.", sseBlock)
-			}
-
-			if sseEnabledAttr := sseBlock.GetAttribute("enabled"); sseEnabledAttr.IsFalse() {
-				results.Add("DAX cluster '%s' has disabled server side encryption", sseEnabledAttr)
-			}
-
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/aws/dynamodb/enable_recovery_rule.go b/internal/app/tfsec/rules/aws/dynamodb/enable_recovery_rule.go
index 70d75130a..f5f3a12d9 100644
--- a/internal/app/tfsec/rules/aws/dynamodb/enable_recovery_rule.go
+++ b/internal/app/tfsec/rules/aws/dynamodb/enable_recovery_rule.go
@@ -1,9 +1,7 @@
 package dynamodb
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/dynamodb"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -49,24 +47,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_dynamodb_table"},
 		Base:           dynamodb.CheckEnableRecovery,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			if resourceBlock.MissingChild("point_in_time_recovery") {
-				results.Add("Resource doesn't have point in time recovery", resourceBlock)
-				return
-			}
-
-			pointBlock := resourceBlock.GetBlock("point_in_time_recovery")
-			if pointBlock.MissingChild("enabled") {
-				results.Add("Resource doesn't have point in time recovery enabled", pointBlock)
-				return
-			}
-			enabledAttr := pointBlock.GetAttribute("enabled")
-			if enabledAttr.IsFalse() {
-				results.Add("Resource doesn't have point in time recovery enabled", enabledAttr)
-			}
-
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule.go b/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule.go
index 56c241b99..a22d75baf 100644
--- a/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule.go
+++ b/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule.go
@@ -1,9 +1,7 @@
 package dynamodb
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/dynamodb"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -70,27 +68,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_dynamodb_table"},
 		Base:           dynamodb.CheckTableCustomerKey,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			if resourceBlock.MissingChild("server_side_encryption") {
-				results.Add("Resource is not using KMS CMK for encryption", resourceBlock)
-				return
-			}
-
-			sseBlock := resourceBlock.GetBlock("server_side_encryption")
-			enabledAttr := sseBlock.GetAttribute("enabled")
-			if enabledAttr.IsFalse() {
-				results.Add("Resource has server side encryption configured but disabled", enabledAttr)
-			}
-
-			if sseBlock.HasChild("kms_key_arn") {
-				keyIdAttr := sseBlock.GetAttribute("kms_key_arn")
-				if keyIdAttr.Equals("alias/aws/dynamodb") {
-					results.Add("Resource has KMS encryption configured but is using the default aws key", keyIdAttr)
-				}
-			}
-
-			return results
-		},
 	})
 }


Test patch:
diff --git a/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule_test.go b/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule_test.go
index 9e1c20adb..e376de693 100644
--- a/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule_test.go
+++ b/internal/app/tfsec/rules/aws/dynamodb/enable_at_rest_encryption_rule_test.go
@@ -62,6 +62,37 @@ func Test_AWSDAXEncryptedAtRest(t *testing.T) {
  `,
 			mustExcludeResultCode: expectedCode,
 		},
+		{
+			name: "DynamoDB Table with disabled server side encryption fails check",
+			source: `
+ resource "aws_dynamodb_table" "bad_example" {
+ 	name             = "example"
+ 	hash_key         = "TestTableHashKey"
+ 	billing_mode     = "PAY_PER_REQUEST"
+ 	stream_enabled   = true
+ 	stream_view_type = "NEW_AND_OLD_IMAGES"
+   
+ 	attribute {
+ 	  name = "TestTableHashKey"
+ 	  type = "S"
+ 	}
+   
+ 	replica {
+ 	  region_name = "us-east-2"
+ 	}
+   
+ 	replica {
+ 	  region_name = "us-west-2"
+ 	}
+ 
+ 	server_side_encryption {
+ 		enabled     = false
+ 		kms_key_arn = aws_kms_key.dynamo_db_kms
+ 	}
+   }
+ `,
+			mustIncludeResultCode: expectedCode,
+		},
 	}
 
 	for _, test := range tests {
diff --git a/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule_test.go b/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule_test.go
index 57ace9062..33675383f 100644
--- a/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule_test.go
+++ b/internal/app/tfsec/rules/aws/dynamodb/table_customer_key_rule_test.go
@@ -41,37 +41,7 @@ func Test_AWSDynamoDBTableEncryption(t *testing.T) {
  `,
 			mustIncludeResultCode: expectedCode,
 		},
-		{
-			name: "DynamoDB Table with disabled server side encryption fails check",
-			source: `
- resource "aws_dynamodb_table" "bad_example" {
- 	name             = "example"
- 	hash_key         = "TestTableHashKey"
- 	billing_mode     = "PAY_PER_REQUEST"
- 	stream_enabled   = true
- 	stream_view_type = "NEW_AND_OLD_IMAGES"
-   
- 	attribute {
- 	  name = "TestTableHashKey"
- 	  type = "S"
- 	}
-   
- 	replica {
- 	  region_name = "us-east-2"
- 	}
-   
- 	replica {
- 	  region_name = "us-west-2"
- 	}
- 
- 	server_side_encryption {
- 		enabled     = false
- 		kms_key_arn = aws_kms_key.dynamo_db_kms
- 	}
-   }
- `,
-			mustIncludeResultCode: expectedCode,
-		},
+
 		{
 			name: "DynamoDB Table with enabled server side encryption using default key fails check",
 			source: `