Repository: aquasecurity/tfsec (go)

Issue:
AWS Elasticsearch - convert tfsec checks to use defsec logic
Adapt AWS Elasticsearch Domains to Go structs based on #1194 instructions:

Remove tfsec logic from `internal/app/tfsec/rules/aws/elasticsearch/enable_domain_encryption_rule.go`
`internal/app/tfsec/rules/aws/elasticsearch/enable_domain_logging_rule.go`
`internal/app/tfsec/rules/aws/elasticsearch/enable_in_transit_encryption_rule.go`
`internal/app/tfsec/rules/aws/elasticsearch/enforce_https_rule.go`
`internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule.go`

Create adapt functions to populate the Go structs in `internal/app/tfsec/adapter/aws/elasticsearch/adapt.go`

Pull request description:
AWS Elasticsearch - adapt to use defsec
Closes #1302 

Create adapter.
Update test to expect alert when `domain_endpoint_options` block is missing.

Patch:
diff --git a/internal/app/tfsec/adapter/aws/elasticsearch/adapt.go b/internal/app/tfsec/adapter/aws/elasticsearch/adapt.go
index 904d70a91..15d4a03fc 100644
--- a/internal/app/tfsec/adapter/aws/elasticsearch/adapt.go
+++ b/internal/app/tfsec/adapter/aws/elasticsearch/adapt.go
@@ -2,9 +2,83 @@ package elasticsearch
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/elasticsearch"
+	"github.com/aquasecurity/defsec/types"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 )
 
 func Adapt(modules []block.Module) elasticsearch.Elasticsearch {
-	return elasticsearch.Elasticsearch{}
+	return elasticsearch.Elasticsearch{
+		Domains: adaptDomains(modules),
+	}
+}
+
+func adaptDomains(modules []block.Module) []elasticsearch.Domain {
+	var domains []elasticsearch.Domain
+	for _, module := range modules {
+		for _, resource := range module.GetResourcesByType("aws_elasticsearch_domain") {
+			domains = append(domains, adaptDomain(resource))
+		}
+	}
+	return domains
+}
+
+func adaptDomain(resource block.Block) elasticsearch.Domain {
+	nameAttr := resource.GetAttribute("domain_name")
+	nameVal := nameAttr.AsStringValueOrDefault("", resource)
+
+	auditEnabled := types.BoolDefault(false, *resource.GetMetadata())
+	transitEncryptionVal := types.BoolDefault(false, *resource.GetMetadata())
+	atRestEncryptionVal := types.BoolDefault(false, *resource.GetMetadata())
+	enforceHTTPSVal := types.BoolDefault(false, *resource.GetMetadata())
+	TLSPolicyVal := types.StringDefault("", *resource.GetMetadata())
+
+	if resource.HasChild("log_publishing_options") {
+		logOptionsBlock := resource.GetBlock("log_publishing_options")
+		enabledAttr := logOptionsBlock.GetAttribute("enabled")
+		enabledVal := enabledAttr.AsBoolValueOrDefault(true, logOptionsBlock)
+
+		logTypeAttr := logOptionsBlock.GetAttribute("log_type")
+		if logTypeAttr.Equals("AUDIT_LOGS") {
+			auditEnabled = enabledVal
+		}
+	}
+
+	if resource.HasChild("node_to_node_encryption") {
+		transitEncryptBlock := resource.GetBlock("node_to_node_encryption")
+		enabledAttr := transitEncryptBlock.GetAttribute("enabled")
+		transitEncryptionVal = enabledAttr.AsBoolValueOrDefault(false, transitEncryptBlock)
+	}
+
+	if resource.HasChild("encrypt_at_rest") {
+		atRestEncryptBlock := resource.GetBlock("encrypt_at_rest")
+		enabledAttr := atRestEncryptBlock.GetAttribute("enabled")
+		atRestEncryptionVal = enabledAttr.AsBoolValueOrDefault(false, atRestEncryptBlock)
+	}
+
+	if resource.HasChild("domain_endpoint_options") {
+		endpointBlock := resource.GetBlock("domain_endpoint_options")
+		enforceHTTPSAttr := endpointBlock.GetAttribute("enforce_https")
+		enforceHTTPSVal = enforceHTTPSAttr.AsBoolValueOrDefault(true, endpointBlock)
+
+		TLSPolicyAttr := endpointBlock.GetAttribute("tls_security_policy")
+		TLSPolicyVal = TLSPolicyAttr.AsStringValueOrDefault("", endpointBlock)
+	}
+
+	return elasticsearch.Domain{
+		Metadata:   *resource.GetMetadata(),
+		DomainName: nameVal,
+		LogPublishing: elasticsearch.LogPublishing{
+			AuditEnabled: auditEnabled,
+		},
+		TransitEncryption: elasticsearch.TransitEncryption{
+			Enabled: transitEncryptionVal,
+		},
+		AtRestEncryption: elasticsearch.AtRestEncryption{
+			Enabled: atRestEncryptionVal,
+		},
+		Endpoint: elasticsearch.Endpoint{
+			EnforceHTTPS: enforceHTTPSVal,
+			TLSPolicy:    TLSPolicyVal,
+		},
+	}
 }
diff --git a/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_encryption_rule.go b/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_encryption_rule.go
index f867ef1ca..64a932834 100644
--- a/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_encryption_rule.go
+++ b/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_encryption_rule.go
@@ -1,9 +1,7 @@
 package elasticsearch
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/elasticsearch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -35,25 +33,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_elasticsearch_domain"},
 		Base:           elasticsearch.CheckEnableDomainEncryption,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			encryptionBlock := resourceBlock.GetBlock("encrypt_at_rest")
-			if encryptionBlock.IsNil() {
-				results.Add("Resource defines an unencrypted Elasticsearch domain (missing encrypt_at_rest block).", resourceBlock)
-				return
-			}
-
-			enabledAttr := encryptionBlock.GetAttribute("enabled")
-			if enabledAttr.IsNil() {
-				results.Add("Resource defines an unencrypted Elasticsearch domain (missing enabled attribute).", encryptionBlock)
-				return
-			}
-
-			if enabledAttr.IsFalse() {
-				results.Add("Resource defines an unencrypted Elasticsearch domain (enabled attribute set to false).", enabledAttr)
-			}
-
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_logging_rule.go b/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_logging_rule.go
index 6d6049825..67e128d54 100644
--- a/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_logging_rule.go
+++ b/internal/app/tfsec/rules/aws/elasticsearch/enable_domain_logging_rule.go
@@ -1,9 +1,7 @@
 package elasticsearch
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/elasticsearch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -46,32 +44,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_elasticsearch_domain"},
 		Base:           elasticsearch.CheckEnableDomainLogging,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			if resourceBlock.MissingChild("log_publishing_options") {
-				results.Add("Resource does not configure logging at rest on the domain.", resourceBlock)
-				return
-			}
-
-			logOptions := resourceBlock.GetBlocks("log_publishing_options")
-			for _, logOption := range logOptions {
-
-				if logTypeAttr := logOption.GetAttribute("log_type"); logTypeAttr.IsNil() || logTypeAttr.NotEqual("AUDIT_LOGS") {
-					continue
-				}
-
-				enabledAttr := logOption.GetAttribute("enabled")
-				if enabledAttr.IsNotNil() && enabledAttr.IsFalse() {
-					results.Add("Resource explicitly disables logging on the domain.", enabledAttr)
-					return
-				} else {
-					// we have audit logs enabled
-					return
-				}
-			}
-
-			results.Add("Audit logging is not enabled for the domain.", resourceBlock)
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/aws/elasticsearch/enable_in_transit_encryption_rule.go b/internal/app/tfsec/rules/aws/elasticsearch/enable_in_transit_encryption_rule.go
index 0996d634d..e84a427f8 100644
--- a/internal/app/tfsec/rules/aws/elasticsearch/enable_in_transit_encryption_rule.go
+++ b/internal/app/tfsec/rules/aws/elasticsearch/enable_in_transit_encryption_rule.go
@@ -1,9 +1,7 @@
 package elasticsearch
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/elasticsearch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -35,25 +33,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_elasticsearch_domain"},
 		Base:           elasticsearch.CheckEnableInTransitEncryption,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			encryptionBlock := resourceBlock.GetBlock("node_to_node_encryption")
-			if encryptionBlock.IsNil() {
-				results.Add("Resource defines an Elasticsearch domain with plaintext traffic (missing node_to_node_encryption block).", resourceBlock)
-				return
-			}
-
-			enabledAttr := encryptionBlock.GetAttribute("enabled")
-			if enabledAttr.IsNil() {
-				results.Add("Resource defines an Elasticsearch domain with plaintext traffic (missing enabled attribute).", encryptionBlock)
-				return
-			}
-
-			if enabledAttr.IsFalse() {
-				results.Add("Resource defines an Elasticsearch domain with plaintext traffic (enabled attribute set to false).", enabledAttr)
-			}
-
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/aws/elasticsearch/enforce_https_rule.go b/internal/app/tfsec/rules/aws/elasticsearch/enforce_https_rule.go
index 4cb43bcb2..fae7983ce 100644
--- a/internal/app/tfsec/rules/aws/elasticsearch/enforce_https_rule.go
+++ b/internal/app/tfsec/rules/aws/elasticsearch/enforce_https_rule.go
@@ -1,9 +1,7 @@
 package elasticsearch
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/elasticsearch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -35,25 +33,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_elasticsearch_domain"},
 		Base:           elasticsearch.CheckEnforceHttps,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			endpointBlock := resourceBlock.GetBlock("domain_endpoint_options")
-			if endpointBlock.IsNil() {
-				results.Add("Resource defines an Elasticsearch domain with plaintext traffic (missing domain_endpoint_options block).", resourceBlock)
-				return
-			}
-
-			enforceHTTPSAttr := endpointBlock.GetAttribute("enforce_https")
-			if enforceHTTPSAttr.IsNil() {
-				results.Add("Resource defines an Elasticsearch domain with plaintext traffic (missing enforce_https attribute).", endpointBlock)
-				return
-			}
-
-			if enforceHTTPSAttr.IsFalse() {
-				results.Add("Resource defines an Elasticsearch domain with plaintext traffic (enabled attribute set to false).", enforceHTTPSAttr)
-			}
-
-			return results
-		},
 	})
 }
diff --git a/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule.go b/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule.go
index 10ef80a0f..1e385af79 100644
--- a/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule.go
+++ b/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule.go
@@ -1,9 +1,7 @@
 package elasticsearch
 
 import (
-	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/elasticsearch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
 	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
@@ -37,24 +35,5 @@ func init() {
 		RequiredTypes:  []string{"resource"},
 		RequiredLabels: []string{"aws_elasticsearch_domain"},
 		Base:           elasticsearch.CheckUseSecureTlsPolicy,
-		CheckTerraform: func(resourceBlock block.Block, _ block.Module) (results rules.Results) {
-
-			endpointBlock := resourceBlock.GetBlock("domain_endpoint_options")
-			if endpointBlock.IsNil() {
-				return
-			}
-
-			tlsPolicyAttr := endpointBlock.GetAttribute("tls_security_policy")
-			if tlsPolicyAttr.IsNil() {
-				results.Add("Resource defines an Elasticsearch domain with an outdated TLS policy (defaults to Policy-Min-TLS-1-0-2019-07).", endpointBlock)
-				return
-			}
-
-			if tlsPolicyAttr.Equals("Policy-Min-TLS-1-0-2019-07") {
-				results.Add("Resource defines an Elasticsearch domain with an outdated TLS policy (set to Policy-Min-TLS-1-0-2019-07).", tlsPolicyAttr)
-			}
-
-			return results
-		},
 	})
 }


Test patch:
diff --git a/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule_test.go b/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule_test.go
index 07efa88c6..88cf5846f 100644
--- a/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule_test.go
+++ b/internal/app/tfsec/rules/aws/elasticsearch/use_secure_tls_policy_rule_test.go
@@ -21,7 +21,7 @@ func Test_AWSOutdatedTLSPolicyElasticsearchDomainEndpoint(t *testing.T) {
  resource "aws_elasticsearch_domain" "my_elasticsearch_domain" {
  	
  }`,
-			mustExcludeResultCode: expectedCode,
+			mustIncludeResultCode: expectedCode,
 		},
 		{
 			name: "check tls_security_policy for aws_elasticsearch_domain isn't the default",