Skip to content

Commit

Permalink
First round of new checks (#970)
Browse files Browse the repository at this point in the history
Co-authored-by: Liam Galvin <liam.galvin@aquasec.com>
  • Loading branch information
Owen Rumney and liamg committed Jul 29, 2021
1 parent 4b60c5e commit d2a92a0
Show file tree
Hide file tree
Showing 17 changed files with 945 additions and 1 deletion.
2 changes: 1 addition & 1 deletion cmd/tfsec-skeleton/requirements/requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func buildStringSliceComparison(values []string, comparison Comparison) string {
case ComparisonAnyOf:
return fmt.Sprintf(`IsAny(%s)`, sprintGo(values))
case ComparisonNotAnyOf:
return fmt.Sprintf(`IsNone(%s)`, sprintGo(values))
return fmt.Sprintf(`IsNotAny(%s)`, sprintGo(values))
}
panic(fmt.Sprintf("Comparison '%s' not supported for string slice", comparison))
}
Expand Down
1 change: 1 addition & 0 deletions internal/app/tfsec/block/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Attribute interface {
NotEqual(checkValue interface{}, equalityOptions ...EqualityOption) bool
RegexMatches(pattern interface{}) bool
IsAny(options ...interface{}) bool
IsNotAny(options ...interface{}) bool
IsNone(options ...interface{}) bool
IsTrue() bool
IsFalse() bool
Expand Down
4 changes: 4 additions & 0 deletions internal/app/tfsec/block/hclattribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@ func (attr *HCLAttribute) RegexMatches(pattern interface{}) bool {
return false
}

func (attr *HCLAttribute) IsNotAny(options ...interface{}) bool {
return !attr.IsAny(options...)
}

func (attr *HCLAttribute) IsAny(options ...interface{}) bool {
if attr == nil {
return false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package apigateway

// 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: "apigateway",
ShortCode: "enable-cache-encryption",
Documentation: rule.RuleDocumentation{
Summary: "API Gateway must have cache enabled",
Explanation: `Method cache encryption ensures that any sensitive data in the cache is not vulnerable to compromise in the event of interception`,
Impact: "Data stored in the cache that is unencrypted may be vulnerable to compromise",
Resolution: "Enable cache encryption",
BadExample: []string{ `
resource "aws_api_gateway_method_settings" "bad_example" {
rest_api_id = aws_api_gateway_rest_api.example.id
stage_name = aws_api_gateway_stage.example.stage_name
method_path = "path1/GET"
settings {
metrics_enabled = true
logging_level = "INFO"
cache_data_encrypted = false
}
}
`},
GoodExample: []string{ `
resource "aws_api_gateway_method_settings" "good_example" {
rest_api_id = aws_api_gateway_rest_api.example.id
stage_name = aws_api_gateway_stage.example.stage_name
method_path = "path1/GET"
settings {
metrics_enabled = true
logging_level = "INFO"
cache_data_encrypted = true
}
}
`},
Links: []string{
"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings#cache_data_encrypted",
},
},
RequiredTypes: []string{
"resource",
},
RequiredLabels: []string{
"aws_api_gateway_method_settings",
},
DefaultSeverity: severity.Medium,
CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
if cacheDataEncryptedAttr := resourceBlock.GetBlock("settings").GetAttribute("cache_data_encrypted"); cacheDataEncryptedAttr.IsNil() { // alert on use of default value
set.AddResult().
WithDescription("Resource '%s' uses default value for settings.cache_data_encrypted", resourceBlock.FullName())
} else if cacheDataEncryptedAttr.IsFalse() {
set.AddResult().
WithDescription("Resource '%s' does not have settings.cache_data_encrypted set to true", resourceBlock.FullName()).
WithAttribute(cacheDataEncryptedAttr)
}
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package apigateway

import (
"strings"
"testing"

"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
)

func Test_AWSEnableCacheEncryption_FailureExamples(t *testing.T) {
expectedCode := "aws-apigateway-enable-cache-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_AWSEnableCacheEncryption_SuccessExamples(t *testing.T) {
expectedCode := "aws-apigateway-enable-cache-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)
}
}
65 changes: 65 additions & 0 deletions internal/app/tfsec/rules/aws/apigateway/enable_tracing_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package apigateway

// 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: "api-gateway",
ShortCode: "enable-tracing",
Documentation: rule.RuleDocumentation{
Summary: "API Gateway must have X-Ray tracing enabled",
Explanation: `X-Ray tracing enables end-to-end debugging and analysis of all API Gateway HTTP requests.`,
Impact: "WIthout full tracing enabled it is difficult to trace the flow of logs",
Resolution: "Enable tracing",
BadExample: []string{ `
resource "aws_api_gateway_stage" "bad_example" {
stage_name = "prod"
rest_api_id = aws_api_gateway_rest_api.test.id
deployment_id = aws_api_gateway_deployment.test.id
xray_tracing_enabled = false
}
`},
GoodExample: []string{ `
resource "aws_api_gateway_stage" "good_example" {
stage_name = "prod"
rest_api_id = aws_api_gateway_rest_api.test.id
deployment_id = aws_api_gateway_deployment.test.id
xray_tracing_enabled = true
}
`},
Links: []string{
"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage#xray_tracing_enabled",
},
},
RequiredTypes: []string{
"resource",
},
RequiredLabels: []string{
"aws_api_gateway_stage",
},
DefaultSeverity: severity.Low,
CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context){
if xrayTracingEnabledAttr := resourceBlock.GetAttribute("xray_tracing_enabled"); xrayTracingEnabledAttr.IsNil() { // alert on use of default value
set.AddResult().
WithDescription("Resource '%s' uses default value for xray_tracing_enabled", resourceBlock.FullName())
} else if xrayTracingEnabledAttr.IsFalse() {
set.AddResult().
WithDescription("Resource '%s' does not have xray_tracing_enabled set to true", resourceBlock.FullName()).
WithAttribute(xrayTracingEnabledAttr)
}
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package apigateway

import (
"strings"
"testing"

"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
)

func Test_AWSEnableTracing_FailureExamples(t *testing.T) {
expectedCode := "aws-api-gateway-enable-tracing"

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_AWSEnableTracing_SuccessExamples(t *testing.T) {
expectedCode := "aws-api-gateway-enable-tracing"

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)
}
}
73 changes: 73 additions & 0 deletions internal/app/tfsec/rules/aws/documentdb/enable_log_export_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package documentdb

// 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: "documentdb",
ShortCode: "enable-log-export",
Documentation: rule.RuleDocumentation{
Summary: "DocumentDB logs export should be enabled",
Explanation: `Document DB does not have auditing by default. To ensure that you are able to accurately audit the usage of your DocumentDB cluster you should enable export logs.`,
Impact: "Limited visibility of audit trail for changes to the DocumentDB",
Resolution: "Enable export logs",
BadExample: []string{`
resource "aws_docdb_cluster" "bad_example" {
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
enabled_cloudwatch_logs_exports = "something"
}
`},
GoodExample: []string{`
resource "aws_docdb_cluster" "good_example" {
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
enabled_cloudwatch_logs_exports = "audit"
}
`},
Links: []string{
"https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/docdb_cluster#enabled_cloudwatch_logs_exports",
},
},
RequiredTypes: []string{
"resource",
},
RequiredLabels: []string{
"aws_docdb_cluster",
},
DefaultSeverity: severity.Medium,
CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) {
if enabledCloudwatchLogsExportsAttr := resourceBlock.GetAttribute("enabled_cloudwatch_logs_exports"); enabledCloudwatchLogsExportsAttr.IsNil() { // alert on use of default value
set.AddResult().
WithDescription("Resource '%s' uses default value for enabled_cloudwatch_logs_exports", resourceBlock.FullName())
} else if enabledCloudwatchLogsExportsAttr.IsNotAny("audit", "profiler") {
set.AddResult().
WithDescription("Resource '%s' does not have enabled_cloudwatch_logs_exports set to one of [audit profiler]", resourceBlock.FullName()).
WithAttribute(enabledCloudwatchLogsExportsAttr)
}
},
})
}

0 comments on commit d2a92a0

Please sign in to comment.