Repository: liamg/tfsec
Pull request #145 (2020-08-06 20:35:16)

Add check for missing or outdated SSL/TLS protocol in AWS API gateway domain names


Patch:
diff --git a/README.md b/README.md
index 387ae3b77..ce76f0329 100644
--- a/README.md
+++ b/README.md
@@ -156,6 +156,7 @@ there are also checks which are provider agnostic.
 | AWS022  | aws      | A MSK cluster allows unencrypted data in transit.
 | AWS023  | aws      | ECR repository has image scans disabled
 | AWS024  | aws      | Kinesis stream is unencrypted
+| AWS025  | aws      | API Gateway domain name uses outdated SSL/TLS protocols.
 | AZU001  | azurerm  | An inbound network security rule allows traffic from `/0`.
 | AZU002  | azurerm  | An outbound network security rule allows traffic to `/0`.
 | AZU003  | azurerm  | Unencrypted managed disk.
diff --git a/example/main.tf b/example/main.tf
index adcfa14c0..21e080043 100644
--- a/example/main.tf
+++ b/example/main.tf
@@ -22,3 +22,18 @@ resource "azurerm_managed_disk" "source" {
         enabled = var.enableEncryption
     }
 }
+
+resource "aws_api_gateway_domain_name" "missing_security_policy" {
+}
+
+resource "aws_api_gateway_domain_name" "empty_security_policy" {
+    security_policy = ""
+}
+
+resource "aws_api_gateway_domain_name" "outdated_security_policy" {
+    security_policy = "TLS_1_0"
+}
+
+resource "aws_api_gateway_domain_name" "valid_security_policy" {
+    security_policy = "TLS_1_2"
+}
diff --git a/internal/app/tfsec/checks/aws_api_gateway_domain_name_missing_security_policy.go b/internal/app/tfsec/checks/aws_api_gateway_domain_name_missing_security_policy.go
new file mode 100644
index 000000000..ef5a2ad0e
--- /dev/null
+++ b/internal/app/tfsec/checks/aws_api_gateway_domain_name_missing_security_policy.go
@@ -0,0 +1,45 @@
+package checks
+
+import (
+	"fmt"
+	"github.com/liamg/tfsec/internal/app/tfsec/parser"
+	"github.com/liamg/tfsec/internal/app/tfsec/scanner"
+	"github.com/zclconf/go-cty/cty"
+)
+
+// AWSApiGatewayDomainNameOutdatedSecurityPolicy See https://github.com/liamg/tfsec#included-checks for check info
+const AWSApiGatewayDomainNameOutdatedSecurityPolicy scanner.RuleID = "AWS025"
+
+func init() {
+	scanner.RegisterCheck(scanner.Check{
+		Code:           AWSApiGatewayDomainNameOutdatedSecurityPolicy,
+		RequiredTypes:  []string{"resource"},
+		RequiredLabels: []string{"aws_api_gateway_domain_name"},
+		CheckFunc: func(check *scanner.Check, block *parser.Block, _ *scanner.Context) []scanner.Result {
+
+			securityPolicyAttr := block.GetAttribute("security_policy")
+			if securityPolicyAttr == nil {
+				return []scanner.Result{
+					check.NewResult(
+						fmt.Sprintf("Resource '%s' should include security_policy (defauls to outdated SSL/TLS policy).", block.Name()),
+						block.Range(),
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			if securityPolicyAttr.Type() == cty.String && securityPolicyAttr.Value().AsString() != "TLS_1_2" {
+				return []scanner.Result{
+					check.NewResultWithValueAnnotation(
+						fmt.Sprintf("Resource '%s' defines outdated SSL/TLS policies (not using TLS_1_2).", block.Name()),
+						securityPolicyAttr.Range(),
+						securityPolicyAttr,
+						scanner.SeverityError,
+					),
+				}
+			}
+
+			return nil
+		},
+	})
+}


Test patch:
diff --git a/internal/app/tfsec/aws_api_gateway_domain_name_missing_security_policy_test.go b/internal/app/tfsec/aws_api_gateway_domain_name_missing_security_policy_test.go
new file mode 100644
index 000000000..45bced26a
--- /dev/null
+++ b/internal/app/tfsec/aws_api_gateway_domain_name_missing_security_policy_test.go
@@ -0,0 +1,60 @@
+package tfsec
+
+import (
+	"testing"
+
+	"github.com/liamg/tfsec/internal/app/tfsec/scanner"
+
+	"github.com/liamg/tfsec/internal/app/tfsec/checks"
+)
+
+func Test_AWSMissingSecurityPolicy(t *testing.T) {
+
+	var tests = []struct {
+		name                  string
+		source                string
+		mustIncludeResultCode scanner.RuleID
+		mustExcludeResultCode scanner.RuleID
+	}{
+		{
+			name: "check aws_api_gateway_domain_name with outdated policy",
+			source: `
+resource "aws_api_gateway_domain_name" "my-resource" {
+	security_policy = "TLS_1_0"
+}`,
+			mustIncludeResultCode: checks.AWSApiGatewayDomainNameOutdatedSecurityPolicy,
+		},
+		{
+			name: "check aws_api_gateway_domain_name with empty security policy",
+			source: `
+resource "aws_api_gateway_domain_name" "my-resource" {
+	security_policy = ""
+}`,
+			mustIncludeResultCode: checks.AWSApiGatewayDomainNameOutdatedSecurityPolicy,
+		},
+		{
+			name: "check aws_api_gateway_domain_name without security policy",
+			source: `
+resource "aws_api_gateway_domain_name" "my-resource" {
+ domain=""
+}`,
+			mustIncludeResultCode: checks.AWSApiGatewayDomainNameOutdatedSecurityPolicy,
+		},
+		{
+			name: "check aws_api_gateway_domain_name with ok policy",
+			source: `
+resource "aws_api_gateway_domain_name" "my-resource" {
+	security_policy = "TLS_1_2"
+}`,
+			mustExcludeResultCode: checks.AWSApiGatewayDomainNameOutdatedSecurityPolicy,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			results := scanSource(test.source)
+			assertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results)
+		})
+	}
+
+}