From 20c7b6ec75f44fd61b1f1c6ba8c9a3561e70ed0f Mon Sep 17 00:00:00 2001 From: Owen Rumney Date: Thu, 29 Jul 2021 14:00:04 +0100 Subject: [PATCH] Fix inline ignore issue (#964) - Fixed inline ignore issue - Simplified adding results to set in rule functions - Added Printf style function for descriptions - Added check for missing nested attributes Co-authored-by: Liam Galvin --- CONTRIBUTING.md | 5 +- example/main.tf | 4 + internal/app/tfsec/block/attribute.go | 3 + internal/app/tfsec/block/block.go | 3 + internal/app/tfsec/block/hclattribute.go | 120 +++++++- internal/app/tfsec/block/hclblock.go | 282 ++++++++++-------- internal/app/tfsec/cidr/cidr.go | 2 +- internal/app/tfsec/custom/processing.go | 32 +- internal/app/tfsec/parser/evaluator.go | 4 +- .../apigateway/enable_access_logging_rule.go | 9 +- .../apigateway/use_secure_tls_policy_rule.go | 24 +- .../athena/enable_at_rest_encryption_rule.go | 8 +- .../aws/athena/no_encryption_override_rule.go | 26 +- .../enable_at_rest_encryption_rule.go | 35 +-- .../aws/autoscaling/no_public_ip_rule.go | 20 +- .../aws/cloudfront/enable_logging_rule.go | 8 +- .../rules/aws/cloudfront/enable_waf_rule.go | 10 +- .../aws/cloudfront/enforce_https_rule.go | 59 ++-- .../cloudfront/use_secure_tls_policy_rule.go | 34 +-- .../aws/cloudtrail/enable_all_regions_rule.go | 17 +- .../enable_at_rest_encryption_rule.go | 16 +- .../cloudtrail/enable_log_validation_rule.go | 16 +- .../cloudwatch/log_group_customer_key_rule.go | 9 +- .../aws/codebuild/enable_encryption_rule.go | 26 +- .../codebuild/enable_encryption_rule_test.go | 1 - .../aws/config/aggregate_all_regions_rule.go | 24 +- .../config/aggregate_all_regions_rule_test.go | 44 +-- .../enable_at_rest_encryption_rule.go | 20 +- .../aws/dynamodb/enable_recovery_rule.go | 29 +- .../aws/dynamodb/table_customer_key_rule.go | 26 +- .../aws/ec2/enforce_http_token_imds_rule.go | 23 +- .../ec2/enforce_http_token_imds_rule_test.go | 42 +-- .../aws/ec2/no_secrets_in_user_data_rule.go | 18 +- .../rules/aws/ecr/enable_image_scans_rule.go | 31 +- .../aws/ecr/enable_image_scans_rule_test.go | 12 + .../ecr/enforce_immutable_repository_rule.go | 20 +- .../aws/ecr/repository_customer_key_rule.go | 22 +- .../aws/ecs/enable_container_insight_rule.go | 20 +- .../ecs/enable_in_transit_encryption_rule.go | 18 +- .../aws/ecs/no_plaintext_secrets_rule.go | 18 +- .../aws/ecs/no_plaintext_secrets_rule_test.go | 40 +-- .../aws/efs/enable_at_rest_encryption_rule.go | 23 +- .../eks/enable_control_plane_logging_rule.go | 16 +- .../rules/aws/eks/encrypt_secrets_rule.go | 43 +-- .../aws/eks/no_public_cluster_access_rule.go | 23 +- .../no_public_cluster_access_to_cidr_rule.go | 22 +- .../enable_backup_retention_rule.go | 22 +- .../enable_in_transit_encryption_rule.go | 18 +- .../enable_domain_logging_rule.go | 18 +- .../enable_in_transit_encryption_rule.go | 33 +- .../enable_in_transit_encryption_rule_test.go | 12 + .../aws/elasticsearch/enable_logging_rule.go | 29 +- .../encrypt_replication_group_rule.go | 18 +- .../aws/elasticsearch/enforce_https_rule.go | 32 +- .../use_secure_tls_policy_rule.go | 25 +- .../enable_domain_encryption_rule.go | 34 +-- .../aws/elb/drop_invalid_headers_rule.go | 18 +- .../rules/aws/elbv2/alb_not_public_rule.go | 18 +- .../rules/aws/elbv2/http_not_used_rule.go | 17 +- .../aws/iam/block_kms_policy_wildcard_rule.go | 20 +- .../rules/aws/iam/no_password_reuse_rule.go | 16 +- .../rules/aws/iam/no_policy_wildcards_rule.go | 59 ++-- .../require_lowercase_in_passwords_rule.go | 16 +- .../iam/require_numbers_in_passwords_rule.go | 16 +- .../iam/require_symbols_in_passwords_rule.go | 16 +- .../require_uppercase_in_passwords_rule.go | 16 +- .../aws/iam/set_max_password_age_rule.go | 18 +- .../iam/set_minimum_password_length_rule.go | 16 +- .../enable_in_transit_encryption_rule.go | 25 +- .../rules/aws/kms/auto_rotate_keys_rule.go | 20 +- .../aws/lambda/restrict_source_arn_rule.go | 8 +- .../no_exposing_plaintext_credentials_rule.go | 22 +- .../msk/enable_in_transit_encryption_rule.go | 42 +-- .../rds/backup_retention_specified_rule.go | 16 +- .../rds/enable_performance_insights_rule.go | 16 +- .../rds/encrypt_cluster_storage_data_rule.go | 29 +- .../rds/encrypt_instance_storage_data_rule.go | 16 +- .../aws/rds/no_classic_resources_rule.go | 8 +- .../rules/aws/rds/no_public_db_access_rule.go | 19 +- .../redshift/encryption_customer_key_rule.go | 22 +- .../non_default_vpc_deployment_rule.go | 8 +- .../rules/aws/s3/block_public_acls_rule.go | 20 +- .../rules/aws/s3/block_public_policy_rule.go | 16 +- .../aws/s3/enable_bucket_encryption_rule.go | 28 +- .../aws/s3/enable_bucket_logging_rule.go | 13 +- .../rules/aws/s3/enable_versioning_rule.go | 15 +- .../rules/aws/s3/ignore_public_acls_rule.go | 20 +- .../aws/s3/no_public_access_with_acl_rule.go | 27 +- .../s3/no_public_access_with_acl_rule_test.go | 8 + .../rules/aws/s3/no_public_buckets_rule.go | 20 +- .../s3/specify_public_access_block_rule.go | 9 +- .../aws/sns/enable_topic_encryption_rule.go | 28 +- .../aws/sqs/enable_queue_encryption_rule.go | 22 +- .../no_wildcards_in_policy_documents_rule.go | 18 +- .../aws/ssm/secret_use_customer_key_rule.go | 18 +- .../add_decription_to_security_group_rule.go | 16 +- .../rules/aws/vpc/no_default_vpc_rule.go | 8 +- .../aws/vpc/no_excessive_port_access_rule.go | 31 +- .../rules/aws/vpc/no_public_egress_sg_rule.go | 22 +- .../aws/vpc/no_public_egress_sgr_rule.go | 30 +- .../rules/aws/vpc/no_public_ingress_rule.go | 24 +- .../aws/vpc/no_public_ingress_sg_rule.go | 22 +- .../aws/vpc/no_public_ingress_sgr_rule.go | 30 +- .../aws/vpc/use_secure_tls_policy_rule.go | 16 +- .../workspace/enable_disk_encryption_rule.go | 36 +-- .../azure/appservice/enforce_https_rule.go | 16 +- .../disable_password_authentication_rule.go | 12 +- .../compute/enable_disk_encryption_rule.go | 21 +- .../compute/no_secrets_in_custom_data_rule.go | 22 +- .../azure/compute/ssh_authentication_rule.go | 23 +- .../configured_network_policy_rule.go | 12 +- .../container/limit_authorized_ips_rule.go | 10 +- .../rules/azure/container/logging_rule.go | 41 +-- .../container/use_rbac_permissions_rule.go | 27 +- .../rules/azure/database/enable_audit_rule.go | 10 +- .../database/enable_ssl_enforcement_rule.go | 16 +- .../azure/database/no_public_access_rule.go | 16 +- .../no_public_firewall_access_rule.go | 17 +- .../database/retention_period_set_rule.go | 8 +- .../azure/database/secure_tls_policy_rule.go | 18 +- .../datafactory/no_public_access_rule.go | 17 +- .../enable_at_rest_encryption_rule.go | 20 +- .../keyvault/content_type_for_secret_rule.go | 8 +- .../azure/keyvault/ensure_key_expiry_rule.go | 8 +- .../keyvault/ensure_secret_expiry_rule.go | 8 +- .../rules/azure/keyvault/no_purge_rule.go | 23 +- .../keyvault/specify_network_acl_rule.go | 37 +-- .../keyvault/specify_network_acl_rule_test.go | 40 +-- .../activity_log_retention_set_rule.go | 22 +- .../monitor/capture_all_activities_rule.go | 18 +- .../azure/monitor/capture_all_regions_rule.go | 24 +- .../network/disable_rdp_from_internet_rule.go | 11 +- .../azure/network/no_public_egress_rule.go | 31 +- .../azure/network/no_public_ingress_rule.go | 33 +- .../network/retention_policy_set_rule.go | 26 +- .../network/ssh_blocked_from_internet_rule.go | 8 +- .../alert_on_severe_notifications_rule.go | 14 +- .../enable_standard_subscription_rule.go | 17 +- .../set_required_contact_details_rule.go | 16 +- .../allow_microsoft_service_bypass_rule.go | 13 +- .../azure/storage/default_action_deny_rule.go | 12 +- .../rules/azure/storage/enforce_https_rule.go | 15 +- .../rules/azure/storage/ensure_https_rule.go | 68 ----- .../azure/storage/ensure_https_rule_test.go | 52 ---- .../azure/storage/no_public_access_rule.go | 23 +- .../queue_services_logging_enabled_rule.go | 17 +- .../storage/use_secure_tls_policy_rule.go | 17 +- .../synapse/virtual_network_enabled_rule.go | 16 +- .../compute/no_public_egress_rule.go | 10 +- .../compute/no_public_ingress_rule.go | 10 +- .../digitalocean/droplet/use_ssh_keys_rule.go | 16 +- .../loadbalancing/enforce_https_rule.go | 8 +- .../spaces/acl_no_public_read_rule.go | 8 +- .../spaces/disable_force_destroy_rule.go | 8 +- .../spaces/versioning_enabled_rule.go | 16 +- .../spaces/versioning_enabled_rule_test.go | 16 +- .../secrets/sensitive_in_attribute_rule.go | 8 +- .../sensitive_in_attribute_value_rule.go | 10 +- .../secrets/sensitive_in_local_rule.go | 8 +- .../secrets/sensitive_in_variable_rule.go | 8 +- .../rules/github/repositories/private_rule.go | 28 +- .../disk_encryption_customer_keys_rule.go | 11 +- .../compute/disk_encryption_required_rule.go | 18 +- .../google/compute/no_public_egress_rule.go | 12 +- .../google/compute/no_public_ingress_rule.go | 12 +- .../gke/enforce_pod_security_policy_rule.go | 21 +- .../gke/metadata_endpoints_disabled_rule.go | 12 +- .../gke/no_legacy_authentication_rule.go | 36 +-- .../google/gke/node_metadata_security_rule.go | 27 +- .../google/gke/node_shielding_enabled_rule.go | 16 +- .../google/gke/use_rbac_permissions_rule.go | 12 +- .../google/gke/use_service_account_rule.go | 17 +- ...default_service_account_assignment_rule.go | 39 +-- .../no_privileged_service_accounts_rule.go | 25 +- ...evel_service_account_impersonation_rule.go | 14 +- .../iam/no_user_granted_permissions_rule.go | 13 +- .../rules/google/sql/enable_backup_rule.go | 32 +- .../sql/enable_pg_temp_file_logging_rule.go | 33 +- .../sql/encrypt_in_transit_data_rule.go | 28 +- .../google/sql/mysql_no_local_infile_rule.go | 23 +- .../google/sql/no_contained_db_auth_rule.go | 43 +-- .../no_cross_db_ownership_chaining_rule.go | 43 +-- .../rules/google/sql/no_public_access_rule.go | 44 +-- .../google/sql/no_public_access_rule_test.go | 33 +- .../google/sql/pg_log_checkpoints_rule.go | 35 +-- .../google/sql/pg_log_connections_rule.go | 35 +-- .../google/sql/pg_log_disconnections_rule.go | 35 +-- .../rules/google/sql/pg_log_errors_rule.go | 23 +- .../google/sql/pg_log_lock_waits_rule.go | 35 +-- .../sql/pg_no_min_statement_logging_rule.go | 24 +- .../enable_uniform_bucket_level_access.go | 20 +- .../google/storage/no_public_access_rule.go | 16 +- .../compute/no_plaintext_password_rule.go | 13 +- .../openstack/fw/no_public_access_rule.go | 38 ++- .../rules/oracle/compute/no_public_ip_rule.go | 14 +- internal/app/tfsec/scanner/scanner.go | 6 +- internal/app/tfsec/test/ignore_test.go | 21 +- internal/app/tfsec/test/module_scan_test.go | 5 +- internal/app/tfsec/test/wildcard_test.go | 5 +- internal/app/tfsec/testutil/util.go | 6 +- pkg/result/ignores.go | 1 - pkg/result/result.go | 15 +- pkg/result/set.go | 41 +-- pkg/rule/check.go | 6 +- 204 files changed, 1776 insertions(+), 2761 deletions(-) delete mode 100644 internal/app/tfsec/rules/azure/storage/ensure_https_rule.go delete mode 100644 internal/app/tfsec/rules/azure/storage/ensure_https_rule_test.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b98363733f..c11f5d8e38 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,9 +110,8 @@ CheckFunc: func(set result.Set, block *parser.Block, _ *hclcontext.Context) { if attr := block.GetAttribute("hackable"); attr != nil && attr.Value().Type() == cty.Bool { if attr.Value().True() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("The Gibson '%s' is configured to be hackable.", block.Name())). + set.Add(). + WithDescription("The Gibson '%s' is configured to be hackable.", block.Name()). WithAttribute(attr). , ) diff --git a/example/main.tf b/example/main.tf index 26e9e45fb7..5665c69290 100644 --- a/example/main.tf +++ b/example/main.tf @@ -62,3 +62,7 @@ resource "aws_dynamodb_table" "bad_example" { enabled = true } } + +resource "aws_instance" "my_project" { + +} diff --git a/internal/app/tfsec/block/attribute.go b/internal/app/tfsec/block/attribute.go index 24e69b35fe..9148e1a355 100644 --- a/internal/app/tfsec/block/attribute.go +++ b/internal/app/tfsec/block/attribute.go @@ -14,12 +14,15 @@ type Attribute interface { StartsWith(prefix interface{}) bool EndsWith(suffix interface{}) bool Equals(checkValue interface{}, equalityOptions ...EqualityOption) bool + NotEqual(checkValue interface{}, equalityOptions ...EqualityOption) bool RegexMatches(pattern interface{}) bool IsAny(options ...interface{}) bool IsNone(options ...interface{}) bool IsTrue() bool IsFalse() bool IsEmpty() bool + IsNil() bool + IsNotNil() bool MapValue(mapKey string) cty.Value LessThan(checkValue interface{}) bool LessThanOrEqualTo(checkValue interface{}) bool diff --git a/internal/app/tfsec/block/block.go b/internal/app/tfsec/block/block.go index 394fa0f655..bc9ee64a88 100644 --- a/internal/app/tfsec/block/block.go +++ b/internal/app/tfsec/block/block.go @@ -30,6 +30,7 @@ type Block interface { IsCountExpanded() bool HasChild(childElement string) bool MissingChild(childElement string) bool + MissingNestedChild(childElement string) bool InModule() bool Label() string HasBlock(childElement string) bool @@ -38,4 +39,6 @@ type Block interface { Values() cty.Value Context() *hcl.EvalContext ReadLines() (lines []string, comments []string, err error) + IsNil() bool + IsNotNil() bool } diff --git a/internal/app/tfsec/block/hclattribute.go b/internal/app/tfsec/block/hclattribute.go index 8bb6177195..a20342430d 100644 --- a/internal/app/tfsec/block/hclattribute.go +++ b/internal/app/tfsec/block/hclattribute.go @@ -25,22 +25,37 @@ func NewHCLAttribute(attr *hcl.Attribute, ctx *hcl.EvalContext) *HCLAttribute { } func (attr *HCLAttribute) IsLiteral() bool { + if attr == nil { + return false + } return len(attr.hclAttribute.Expr.Variables()) == 0 } func (attr *HCLAttribute) IsResolvable() bool { + if attr == nil { + return false + } return attr.Value() != cty.NilVal } func (attr *HCLAttribute) Type() cty.Type { + if attr == nil { + return cty.NilType + } return attr.Value().Type() } func (attr *HCLAttribute) IsIterable() bool { + if attr == nil { + return false + } return attr.Value().Type().IsCollectionType() || attr.Value().Type().IsObjectType() || attr.Value().Type().IsMapType() || attr.Value().Type().IsListType() || attr.Value().Type().IsSetType() || attr.Value().Type().IsTupleType() } func (attr *HCLAttribute) Each(f func(key cty.Value, val cty.Value)) { + if attr == nil { + return + } val := attr.Value() val.ForEachElement(func(key cty.Value, val cty.Value) (stop bool) { f(key, val) @@ -49,14 +64,23 @@ func (attr *HCLAttribute) Each(f func(key cty.Value, val cty.Value)) { } func (attr *HCLAttribute) IsString() bool { + if attr == nil { + return false + } return !attr.Value().IsNull() && attr.Value().IsKnown() && attr.Value().Type() == cty.String } func (attr *HCLAttribute) IsNumber() bool { + if attr == nil { + return false + } return !attr.Value().IsNull() && attr.Value().IsKnown() && attr.Value().Type() == cty.Number } func (attr *HCLAttribute) IsBool() bool { + if attr == nil { + return false + } return !attr.Value().IsNull() && attr.Value().IsKnown() && attr.Value().Type() == cty.Bool } @@ -77,6 +101,9 @@ func (attr *HCLAttribute) Value() (ctyVal cty.Value) { } func (attr *HCLAttribute) Range() Range { + if attr == nil { + return Range{} + } return Range{ Filename: attr.hclAttribute.Range.Filename, StartLine: attr.hclAttribute.Range.Start.Line, @@ -85,10 +112,16 @@ func (attr *HCLAttribute) Range() Range { } func (attr *HCLAttribute) Name() string { + if attr == nil { + return "" + } return attr.hclAttribute.Name } func (attr *HCLAttribute) ValueAsStrings() []string { + if attr == nil { + return nil + } return getStrings(attr.hclAttribute.Expr, attr.ctx) } @@ -119,6 +152,9 @@ func getStrings(expr hcl.Expression, ctx *hcl.EvalContext) []string { } func (attr *HCLAttribute) listContains(val cty.Value, stringToLookFor string, ignoreCase bool) bool { + if attr == nil { + return false + } valueSlice := val.AsValueSlice() for _, value := range valueSlice { stringToTest := value @@ -140,6 +176,9 @@ func (attr *HCLAttribute) listContains(val cty.Value, stringToLookFor string, ig } func (attr *HCLAttribute) mapContains(checkValue interface{}, val cty.Value) bool { + if attr == nil { + return false + } valueMap := val.AsValueMap() switch t := checkValue.(type) { case map[interface{}]interface{}: @@ -173,6 +212,9 @@ func (attr *HCLAttribute) mapContains(checkValue interface{}, val cty.Value) boo } func (attr *HCLAttribute) Contains(checkValue interface{}, equalityOptions ...EqualityOption) bool { + if attr == nil { + return false + } ignoreCase := false for _, option := range equalityOptions { if option == IgnoreCase { @@ -206,6 +248,9 @@ func containsIgnoreCase(left, substring string) bool { } func (attr *HCLAttribute) StartsWith(prefix interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.String { return strings.HasPrefix(attr.Value().AsString(), fmt.Sprintf("%v", prefix)) } @@ -213,6 +258,9 @@ func (attr *HCLAttribute) StartsWith(prefix interface{}) bool { } func (attr *HCLAttribute) EndsWith(suffix interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.String { return strings.HasSuffix(attr.Value().AsString(), fmt.Sprintf("%v", suffix)) } @@ -226,13 +274,17 @@ const ( ) func (attr *HCLAttribute) Equals(checkValue interface{}, equalityOptions ...EqualityOption) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.String { for _, option := range equalityOptions { if option == IgnoreCase { return strings.EqualFold(strings.ToLower(attr.Value().AsString()), strings.ToLower(fmt.Sprintf("%v", checkValue))) } } - return strings.EqualFold(attr.Value().AsString(), fmt.Sprintf("%v", checkValue)) + result := strings.EqualFold(attr.Value().AsString(), fmt.Sprintf("%v", checkValue)) + return result } if attr.Value().Type() == cty.Bool { return attr.Value().True() == checkValue @@ -248,7 +300,14 @@ func (attr *HCLAttribute) Equals(checkValue interface{}, equalityOptions ...Equa return false } +func (attr *HCLAttribute) NotEqual(checkValue interface{}, equalityOptions ...EqualityOption) bool { + return !attr.Equals(checkValue, equalityOptions...) +} + func (attr *HCLAttribute) RegexMatches(pattern interface{}) bool { + if attr == nil { + return false + } patternVal := fmt.Sprintf("%v", pattern) re, err := regexp.Compile(patternVal) if err != nil { @@ -263,6 +322,9 @@ func (attr *HCLAttribute) RegexMatches(pattern interface{}) bool { } func (attr *HCLAttribute) IsAny(options ...interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.String { value := attr.Value().AsString() for _, option := range options { @@ -287,6 +349,9 @@ func (attr *HCLAttribute) IsAny(options ...interface{}) bool { } func (attr *HCLAttribute) IsNone(options ...interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.String { for _, option := range options { if option == attr.Value().AsString() { @@ -312,6 +377,9 @@ func (attr *HCLAttribute) IsNone(options ...interface{}) bool { } func (attr *HCLAttribute) IsTrue() bool { + if attr == nil { + return false + } switch attr.Value().Type() { case cty.Bool: return attr.Value().True() @@ -328,6 +396,9 @@ func (attr *HCLAttribute) IsTrue() bool { } func (attr *HCLAttribute) IsFalse() bool { + if attr == nil { + return false + } switch attr.Value().Type() { case cty.Bool: return attr.Value().False() @@ -340,6 +411,9 @@ func (attr *HCLAttribute) IsFalse() bool { } func (attr *HCLAttribute) IsEmpty() bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.String { return len(attr.Value().AsString()) == 0 } @@ -360,6 +434,9 @@ func (attr *HCLAttribute) IsEmpty() bool { } func (attr *HCLAttribute) isNullAttributeEmpty() bool { + if attr == nil { + return false + } switch t := attr.hclAttribute.Expr.(type) { case *hclsyntax.FunctionCallExpr, *hclsyntax.ScopeTraversalExpr, *hclsyntax.ConditionalExpr, *hclsyntax.LiteralValueExpr: @@ -381,6 +458,9 @@ func (attr *HCLAttribute) isNullAttributeEmpty() bool { } func (attr *HCLAttribute) MapValue(mapKey string) cty.Value { + if attr == nil { + return cty.NilVal + } if attr.Type().IsObjectType() || attr.Type().IsMapType() { attrMap := attr.Value().AsValueMap() for key, value := range attrMap { @@ -393,6 +473,9 @@ func (attr *HCLAttribute) MapValue(mapKey string) cty.Value { } func (attr *HCLAttribute) LessThan(checkValue interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.Number { checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number) if err != nil { @@ -406,6 +489,9 @@ func (attr *HCLAttribute) LessThan(checkValue interface{}) bool { } func (attr *HCLAttribute) LessThanOrEqualTo(checkValue interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.Number { checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number) if err != nil { @@ -419,6 +505,9 @@ func (attr *HCLAttribute) LessThanOrEqualTo(checkValue interface{}) bool { } func (attr *HCLAttribute) GreaterThan(checkValue interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.Number { checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number) if err != nil { @@ -432,6 +521,9 @@ func (attr *HCLAttribute) GreaterThan(checkValue interface{}) bool { } func (attr *HCLAttribute) GreaterThanOrEqualTo(checkValue interface{}) bool { + if attr == nil { + return false + } if attr.Value().Type() == cty.Number { checkNumber, err := gocty.ToCtyValue(checkValue, cty.Number) if err != nil { @@ -445,6 +537,9 @@ func (attr *HCLAttribute) GreaterThanOrEqualTo(checkValue interface{}) bool { } func (attr *HCLAttribute) IsDataBlockReference() bool { + if attr == nil { + return false + } switch t := attr.hclAttribute.Expr.(type) { case *hclsyntax.ScopeTraversalExpr: split := t.Traversal.SimpleSplit() @@ -470,6 +565,9 @@ func createDotReferenceFromTraversal(traversals ...hcl.Traversal) (*Reference, e } func (attr *HCLAttribute) Reference() (*Reference, error) { + if attr == nil { + return nil, fmt.Errorf("attribute is nil") + } switch t := attr.hclAttribute.Expr.(type) { case *hclsyntax.RelativeTraversalExpr: switch s := t.Source.(type) { @@ -498,6 +596,9 @@ func (attr *HCLAttribute) Reference() (*Reference, error) { } func (attr *HCLAttribute) AllReferences() []*Reference { + if attr == nil { + return nil + } refs := attr.referencesInTemplate() if len(refs) > 0 { return refs @@ -510,6 +611,9 @@ func (attr *HCLAttribute) AllReferences() []*Reference { } func (attr *HCLAttribute) referencesInTemplate() []*Reference { + if attr == nil { + return nil + } var refs []*Reference switch t := attr.hclAttribute.Expr.(type) { case *hclsyntax.TemplateExpr: @@ -525,6 +629,9 @@ func (attr *HCLAttribute) referencesInTemplate() []*Reference { } func (attr *HCLAttribute) IsResourceBlockReference(resourceType string) bool { + if attr == nil { + return false + } switch t := attr.hclAttribute.Expr.(type) { case *hclsyntax.ScopeTraversalExpr: split := t.Traversal.SimpleSplit() @@ -534,6 +641,9 @@ func (attr *HCLAttribute) IsResourceBlockReference(resourceType string) bool { } func (attr *HCLAttribute) ReferencesBlock(b Block) bool { + if attr == nil { + return false + } for _, ref := range attr.AllReferences() { if ref.RefersTo(b) { return true @@ -556,3 +666,11 @@ func getRawValue(value cty.Value) interface{} { return value } + +func (attr *HCLAttribute) IsNil() bool { + return attr == nil +} + +func (attr *HCLAttribute) IsNotNil() bool { + return !attr.IsNil() +} diff --git a/internal/app/tfsec/block/hclblock.go b/internal/app/tfsec/block/hclblock.go index 6572f5b156..2149b6c265 100644 --- a/internal/app/tfsec/block/hclblock.go +++ b/internal/app/tfsec/block/hclblock.go @@ -29,18 +29,18 @@ func NewHCLBlock(hclBlock *hcl.Block, ctx *hcl.EvalContext, moduleBlock Block) B } } -func (block *HCLBlock) markCountExpanded() { - block.expanded = true +func (b *HCLBlock) markCountExpanded() { + b.expanded = true } -func (block *HCLBlock) IsCountExpanded() bool { - return block.expanded +func (b *HCLBlock) IsCountExpanded() bool { + return b.expanded } -func (block *HCLBlock) Clone(index cty.Value) Block { +func (b *HCLBlock) Clone(index cty.Value) Block { var childCtx *hcl.EvalContext - if block.evalContext != nil { - childCtx = block.evalContext.NewChild() + if b.evalContext != nil { + childCtx = b.evalContext.NewChild() } else { childCtx = &hcl.EvalContext{} } @@ -48,9 +48,9 @@ func (block *HCLBlock) Clone(index cty.Value) Block { if childCtx.Variables == nil { childCtx.Variables = make(map[string]cty.Value) } - cloneHCL := *block.hclBlock + cloneHCL := *b.hclBlock - clone := NewHCLBlock(&cloneHCL, childCtx, block.moduleBlock).(*HCLBlock) + clone := NewHCLBlock(&cloneHCL, childCtx, b.moduleBlock).(*HCLBlock) if len(clone.hclBlock.Labels) > 0 { position := len(clone.hclBlock.Labels) - 1 labels := make([]string, len(clone.hclBlock.Labels)) @@ -69,7 +69,7 @@ func (block *HCLBlock) Clone(index cty.Value) Block { labels[position] = fmt.Sprintf("%s[%#v]", clone.hclBlock.Labels[position], index) } } else { - labels[position] = fmt.Sprintf("%s[%d]", clone.hclBlock.Labels[position], block.cloneIndex) + labels[position] = fmt.Sprintf("%s[%d]", clone.hclBlock.Labels[position], b.cloneIndex) } clone.hclBlock.Labels = labels } @@ -78,48 +78,51 @@ func (block *HCLBlock) Clone(index cty.Value) Block { "index": indexVal, }) clone.markCountExpanded() - block.cloneIndex++ + b.cloneIndex++ return clone } -func (block *HCLBlock) Context() *hcl.EvalContext { - return block.evalContext +func (b *HCLBlock) Context() *hcl.EvalContext { + return b.evalContext } -func (block *HCLBlock) AttachEvalContext(ctx *hcl.EvalContext) { - block.evalContext = ctx +func (b *HCLBlock) AttachEvalContext(ctx *hcl.EvalContext) { + b.evalContext = ctx } -func (block *HCLBlock) HasModuleBlock() bool { - return block.moduleBlock != nil +func (b *HCLBlock) HasModuleBlock() bool { + if b == nil { + return false + } + return b.moduleBlock != nil } -func (block *HCLBlock) GetModuleBlock() (Block, error) { - if block.HasModuleBlock() { - return block.moduleBlock, nil +func (b *HCLBlock) GetModuleBlock() (Block, error) { + if b.HasModuleBlock() { + return b.moduleBlock, nil } return nil, fmt.Errorf("the block does not have an associated module block") } -func (block *HCLBlock) Type() string { - return block.hclBlock.Type +func (b *HCLBlock) Type() string { + return b.hclBlock.Type } -func (block *HCLBlock) Labels() []string { - return block.hclBlock.Labels +func (b *HCLBlock) Labels() []string { + return b.hclBlock.Labels } -func (block *HCLBlock) Range() Range { - if block == nil || block.hclBlock == nil { +func (b *HCLBlock) Range() Range { + if b == nil || b.hclBlock == nil { return Range{} } var r hcl.Range - switch body := block.hclBlock.Body.(type) { + switch body := b.hclBlock.Body.(type) { case *hclsyntax.Body: r = body.SrcRange default: - r = block.hclBlock.DefRange - r.End = block.hclBlock.Body.MissingItemRange().End + r = b.hclBlock.DefRange + r.End = b.hclBlock.Body.MissingItemRange().End } return Range{ Filename: r.Filename, @@ -128,25 +131,26 @@ func (block *HCLBlock) Range() Range { } } -func (block *HCLBlock) GetFirstMatchingBlock(names ...string) Block { +func (b *HCLBlock) GetFirstMatchingBlock(names ...string) Block { + var returnBlock *HCLBlock for _, name := range names { - b := block.GetBlock(name) - if b != nil { - return b + childBlock := b.GetBlock(name) + if childBlock.IsNotNil() { + return childBlock } } - return nil + return returnBlock } -func (block *HCLBlock) getHCLBlocks() hcl.Blocks { +func (b *HCLBlock) getHCLBlocks() hcl.Blocks { var blocks hcl.Blocks - switch body := block.hclBlock.Body.(type) { + switch body := b.hclBlock.Body.(type) { case *hclsyntax.Body: for _, b := range body.Blocks { blocks = append(blocks, b.AsHCLBlock()) } default: - content, _, diag := block.hclBlock.Body.PartialContent(schema.TerraformSchema_0_12) + content, _, diag := b.hclBlock.Body.PartialContent(schema.TerraformSchema_0_12) if diag == nil { blocks = content.Blocks } @@ -154,8 +158,8 @@ func (block *HCLBlock) getHCLBlocks() hcl.Blocks { return blocks } -func (block *HCLBlock) getHCLAttributes() hcl.Attributes { - switch body := block.hclBlock.Body.(type) { +func (b *HCLBlock) getHCLAttributes() hcl.Attributes { + switch body := b.hclBlock.Body.(type) { case *hclsyntax.Body: attributes := make(hcl.Attributes) for _, a := range body.Attributes { @@ -163,7 +167,7 @@ func (block *HCLBlock) getHCLAttributes() hcl.Attributes { } return attributes default: - _, body, diag := block.hclBlock.Body.PartialContent(schema.TerraformSchema_0_12) + _, body, diag := b.hclBlock.Body.PartialContent(schema.TerraformSchema_0_12) if diag != nil { return nil } @@ -175,47 +179,48 @@ func (block *HCLBlock) getHCLAttributes() hcl.Attributes { } } -func (block *HCLBlock) GetBlock(name string) Block { - if block == nil || block.hclBlock == nil { - return nil +func (b *HCLBlock) GetBlock(name string) Block { + var returnBlock *HCLBlock + if b == nil || b.hclBlock == nil { + return returnBlock } - for _, child := range block.getHCLBlocks() { + for _, child := range b.getHCLBlocks() { if child.Type == name { - return NewHCLBlock(child, block.evalContext, block.moduleBlock) + return NewHCLBlock(child, b.evalContext, b.moduleBlock) } if child.Type == "dynamic" && len(child.Labels) == 1 && child.Labels[0] == name { - blocks := block.parseDynamicBlockResult(child) + blocks := b.parseDynamicBlockResult(child) if len(blocks) > 0 { return blocks[0] } - return nil + return returnBlock } } - return nil + return returnBlock } -func (block *HCLBlock) AllBlocks() Blocks { - if block == nil || block.hclBlock == nil { +func (b *HCLBlock) AllBlocks() Blocks { + if b == nil || b.hclBlock == nil { return nil } var results []Block - for _, child := range block.getHCLBlocks() { - results = append(results, NewHCLBlock(child, block.evalContext, block.moduleBlock)) + for _, child := range b.getHCLBlocks() { + results = append(results, NewHCLBlock(child, b.evalContext, b.moduleBlock)) } return results } -func (block *HCLBlock) GetBlocks(name string) Blocks { - if block == nil || block.hclBlock == nil { +func (b *HCLBlock) GetBlocks(name string) Blocks { + if b == nil || b.hclBlock == nil { return nil } var results []Block - for _, child := range block.getHCLBlocks() { + for _, child := range b.getHCLBlocks() { if child.Type == name { - results = append(results, NewHCLBlock(child, block.evalContext, block.moduleBlock)) + results = append(results, NewHCLBlock(child, b.evalContext, b.moduleBlock)) } if child.Type == "dynamic" && len(child.Labels) == 1 && child.Labels[0] == name { - dynamics := block.parseDynamicBlockResult(child) + dynamics := b.parseDynamicBlockResult(child) results = append(results, dynamics...) } @@ -223,11 +228,11 @@ func (block *HCLBlock) GetBlocks(name string) Blocks { return results } -func (block *HCLBlock) parseDynamicBlockResult(dynamic *hcl.Block) Blocks { +func (b *HCLBlock) parseDynamicBlockResult(dynamic *hcl.Block) Blocks { var results Blocks - wrapped := NewHCLBlock(dynamic, block.evalContext, block.moduleBlock) + wrapped := NewHCLBlock(dynamic, b.evalContext, b.moduleBlock) forEach := wrapped.GetAttribute("for_each") if forEach == nil { @@ -260,38 +265,41 @@ func (block *HCLBlock) parseDynamicBlockResult(dynamic *hcl.Block) Blocks { return results } -func (block *HCLBlock) GetAttributes() []Attribute { +func (b *HCLBlock) GetAttributes() []Attribute { var results []Attribute - if block == nil || block.hclBlock == nil { + if b == nil || b.hclBlock == nil { return nil } - for _, attr := range block.getHCLAttributes() { - results = append(results, NewHCLAttribute(attr, block.evalContext)) + for _, attr := range b.getHCLAttributes() { + results = append(results, NewHCLAttribute(attr, b.evalContext)) } return results } -func (block *HCLBlock) GetAttribute(name string) Attribute { - if block == nil || block.hclBlock == nil { - return nil +func (b *HCLBlock) GetAttribute(name string) Attribute { + var attr *HCLAttribute + if b == nil || b.hclBlock == nil { + return attr } - for _, attr := range block.getHCLAttributes() { + for _, attr := range b.getHCLAttributes() { if attr.Name == name { - return NewHCLAttribute(attr, block.evalContext) + return NewHCLAttribute(attr, b.evalContext) } } - return nil + return attr } -func (block *HCLBlock) GetNestedAttribute(name string) Attribute { - parts := strings.Split(name, "/") +func (b *HCLBlock) GetNestedAttribute(name string) Attribute { + + var returnAttr *HCLAttribute + parts := strings.Split(name, ".") blocks := parts[:len(parts)-1] attrName := parts[len(parts)-1] - var working Block = block - for _, b := range blocks { - if checkBlock := working.GetBlock(b); checkBlock == nil { - return nil + var working Block = b + for _, subBlock := range blocks { + if checkBlock := working.GetBlock(subBlock); checkBlock == nil { + return returnAttr } else { working = checkBlock } @@ -301,112 +309,148 @@ func (block *HCLBlock) GetNestedAttribute(name string) Attribute { return working.GetAttribute(attrName) } - return nil + return returnAttr } -func (block *HCLBlock) Reference() *Reference { +func (b *HCLBlock) Reference() *Reference { var parts []string - if block.Type() != "resource" { - parts = append(parts, block.Type()) + if b.Type() != "resource" { + parts = append(parts, b.Type()) } - parts = append(parts, block.Labels()...) + parts = append(parts, b.Labels()...) ref, _ := newReference(parts) return ref } -func (block *HCLBlock) ReadLines() (lines []string, comments []string, err error) { - return block.Range().ReadLines(false) +func (b *HCLBlock) ReadLines() (lines []string, comments []string, err error) { + return b.Range().ReadLines(false) } // LocalName is the name relative to the current module -func (block *HCLBlock) LocalName() string { - return block.Reference().String() +func (b *HCLBlock) LocalName() string { + return b.Reference().String() } -func (block *HCLBlock) FullName() string { +func (b *HCLBlock) FullName() string { - if block.moduleBlock != nil { + if b.moduleBlock != nil { return fmt.Sprintf( "%s:%s", - block.moduleBlock.FullName(), - block.LocalName(), + b.moduleBlock.FullName(), + b.LocalName(), ) } - return block.LocalName() + return b.LocalName() } -func (block *HCLBlock) UniqueName() string { - if block.moduleBlock != nil { - return fmt.Sprintf("%s:%s:%s", block.FullName(), block.Range().Filename, block.moduleBlock.UniqueName()) +func (b *HCLBlock) UniqueName() string { + if b.moduleBlock != nil { + return fmt.Sprintf("%s:%s:%s", b.FullName(), b.Range().Filename, b.moduleBlock.UniqueName()) } - return fmt.Sprintf("%s:%s", block.FullName(), block.Range().Filename) + return fmt.Sprintf("%s:%s", b.FullName(), b.Range().Filename) } -func (block *HCLBlock) TypeLabel() string { - if len(block.Labels()) > 0 { - return block.Labels()[0] +func (b *HCLBlock) TypeLabel() string { + if len(b.Labels()) > 0 { + return b.Labels()[0] } return "" } -func (block *HCLBlock) NameLabel() string { - if len(block.Labels()) > 1 { - return block.Labels()[1] +func (b *HCLBlock) NameLabel() string { + if len(b.Labels()) > 1 { + return b.Labels()[1] } return "" } -func (block *HCLBlock) HasChild(childElement string) bool { - return block.GetAttribute(childElement) != nil || block.GetBlock(childElement) != nil +func (b *HCLBlock) HasChild(childElement string) bool { + return b.GetAttribute(childElement).IsNotNil() || b.GetBlock(childElement).IsNotNil() } -func (block *HCLBlock) MissingChild(childElement string) bool { - return !block.HasChild(childElement) +func (b *HCLBlock) MissingChild(childElement string) bool { + if b == nil { + return true + } + + return !b.HasChild(childElement) +} + +func (b *HCLBlock) MissingNestedChild(name string) bool { + if b == nil { + return true + } + + parts := strings.Split(name, ".") + blocks := parts[:len(parts)-1] + last := parts[len(parts)-1] + + var working Block = b + for _, subBlock := range blocks { + if checkBlock := working.GetBlock(subBlock); checkBlock == nil { + return true + } else { + working = checkBlock + } + } + return !working.HasChild(last) + } -func (block *HCLBlock) InModule() bool { - return block.moduleBlock != nil +func (b *HCLBlock) InModule() bool { + if b == nil { + return false + } + return b.moduleBlock != nil } -func (block *HCLBlock) Label() string { - return strings.Join(block.hclBlock.Labels, ".") +func (b *HCLBlock) Label() string { + return strings.Join(b.hclBlock.Labels, ".") } -func (block *HCLBlock) HasBlock(childElement string) bool { - return block.GetBlock(childElement) != nil +func (b *HCLBlock) HasBlock(childElement string) bool { + return b.GetBlock(childElement).IsNil() } -func (block *HCLBlock) IsResourceType(resourceType string) bool { - return block.TypeLabel() == resourceType +func (b *HCLBlock) IsResourceType(resourceType string) bool { + return b.TypeLabel() == resourceType } -func (block *HCLBlock) IsEmpty() bool { - return len(block.AllBlocks()) == 0 && len(block.GetAttributes()) == 0 +func (b *HCLBlock) IsEmpty() bool { + return len(b.AllBlocks()) == 0 && len(b.GetAttributes()) == 0 } -func (block *HCLBlock) Attributes() map[string]Attribute { +func (b *HCLBlock) Attributes() map[string]Attribute { attributes := make(map[string]Attribute) - for name, attr := range block.getHCLAttributes() { - attributes[name] = NewHCLAttribute(attr, block.evalContext) + for name, attr := range b.getHCLAttributes() { + attributes[name] = NewHCLAttribute(attr, b.evalContext) } return attributes } -func (block *HCLBlock) Values() cty.Value { +func (b *HCLBlock) Values() cty.Value { values := make(map[string]cty.Value) - for _, attribute := range block.getHCLAttributes() { + for _, attribute := range b.getHCLAttributes() { func() { defer func() { if err := recover(); err != nil { return } }() - val, _ := attribute.Expr.Value(block.evalContext) + val, _ := attribute.Expr.Value(b.evalContext) values[attribute.Name] = val }() } return cty.ObjectVal(values) } + +func (b *HCLBlock) IsNil() bool { + return b == nil +} + +func (b *HCLBlock) IsNotNil() bool { + return !b.IsNil() +} diff --git a/internal/app/tfsec/cidr/cidr.go b/internal/app/tfsec/cidr/cidr.go index 4d205b2ccd..dd3af7801e 100644 --- a/internal/app/tfsec/cidr/cidr.go +++ b/internal/app/tfsec/cidr/cidr.go @@ -8,7 +8,7 @@ import ( ) func IsOpen(attr block.Attribute) bool { - if attr.Value().IsNull() { + if attr.IsNil() || attr.Value().IsNull() { return false } diff --git a/internal/app/tfsec/custom/processing.go b/internal/app/tfsec/custom/processing.go index 1a02c92dd4..a5ee14a683 100644 --- a/internal/app/tfsec/custom/processing.go +++ b/internal/app/tfsec/custom/processing.go @@ -37,70 +37,70 @@ var matchFunctions = map[CheckAction]func(block.Block, *MatchSpec) bool{ }, StartsWith: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.StartsWith(spec.MatchValue) }, EndsWith: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.EndsWith(spec.MatchValue) }, Contains: func(b block.Block, spec *MatchSpec) bool { attribute := b.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.Contains(spec.MatchValue, block.IgnoreCase) }, NotContains: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return !attribute.Contains(spec.MatchValue) }, Equals: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.Equals(spec.MatchValue) }, LessThan: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.LessThan(spec.MatchValue) }, LessThanOrEqualTo: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.LessThanOrEqualTo(spec.MatchValue) }, GreaterThan: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.GreaterThan(spec.MatchValue) }, GreaterThanOrEqualTo: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.GreaterThanOrEqualTo(spec.MatchValue) }, RegexMatches: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.RegexMatches(spec.MatchValue) @@ -111,7 +111,7 @@ var matchFunctions = map[CheckAction]func(block.Block, *MatchSpec) bool{ }, IsNone: func(block block.Block, spec *MatchSpec) bool { attribute := block.GetAttribute(spec.Name) - if attribute == nil { + if attribute.IsNil() { return spec.IgnoreUndefined } return attribute.IsNone(unpackInterfaceToInterfaceSlice(spec.MatchValue)...) @@ -139,11 +139,9 @@ func processFoundChecks(checks ChecksFile) { CheckFunc: func(set result.Set, rootBlock block.Block, ctx *hclcontext.Context) { matchSpec := customCheck.MatchSpec if !evalMatchSpec(rootBlock, matchSpec, ctx) { - set.Add( - result.New(rootBlock). - WithDescription(fmt.Sprintf("Custom check failed for resource %s. %s", rootBlock.FullName(), customCheck.ErrorMessage)). - WithSeverity(customCheck.Severity), - ) + set.AddResult(). + WithDescription("Custom check failed for resource %s. %s", rootBlock.FullName(), customCheck.ErrorMessage). + WithSeverity(customCheck.Severity) } }, }) @@ -152,7 +150,7 @@ func processFoundChecks(checks ChecksFile) { } func evalMatchSpec(b block.Block, spec *MatchSpec, ctx *hclcontext.Context) bool { - if b == nil { + if b.IsNil() { return false } var evalResult bool diff --git a/internal/app/tfsec/parser/evaluator.go b/internal/app/tfsec/parser/evaluator.go index ccfcb473c8..34454d4a86 100644 --- a/internal/app/tfsec/parser/evaluator.go +++ b/internal/app/tfsec/parser/evaluator.go @@ -207,7 +207,7 @@ func (e *Evaluator) expandBlockCounts(blocks block.Blocks) block.Blocks { var forEachFiltered block.Blocks for _, block := range blocks { forEachAttr := block.GetAttribute("for_each") - if forEachAttr == nil || block.IsCountExpanded() || (block.Type() != "resource" && block.Type() != "module") { + if forEachAttr.IsNil() || block.IsCountExpanded() || (block.Type() != "resource" && block.Type() != "module") { forEachFiltered = append(forEachFiltered, block) continue } @@ -237,7 +237,7 @@ func (e *Evaluator) expandBlockForEaches(blocks block.Blocks) block.Blocks { var countFiltered block.Blocks for _, block := range blocks { countAttr := block.GetAttribute("count") - if countAttr == nil || block.IsCountExpanded() || (block.Type() != "resource" && block.Type() != "module") { + if countAttr.IsNil() || block.IsCountExpanded() || (block.Type() != "resource" && block.Type() != "module") { countFiltered = append(countFiltered, block) continue } diff --git a/internal/app/tfsec/rules/aws/apigateway/enable_access_logging_rule.go b/internal/app/tfsec/rules/aws/apigateway/enable_access_logging_rule.go index 7301f69626..5bd92442fc 100644 --- a/internal/app/tfsec/rules/aws/apigateway/enable_access_logging_rule.go +++ b/internal/app/tfsec/rules/aws/apigateway/enable_access_logging_rule.go @@ -1,8 +1,6 @@ package apigateway import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -75,12 +73,9 @@ resource "aws_api_gateway_stage" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("access_log_settings") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing access log settings block.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is missing access log settings block.", resourceBlock.FullName()) } - }, }) } diff --git a/internal/app/tfsec/rules/aws/apigateway/use_secure_tls_policy_rule.go b/internal/app/tfsec/rules/aws/apigateway/use_secure_tls_policy_rule.go index dd3112a206..ce0c0634bb 100644 --- a/internal/app/tfsec/rules/aws/apigateway/use_secure_tls_policy_rule.go +++ b/internal/app/tfsec/rules/aws/apigateway/use_secure_tls_policy_rule.go @@ -1,8 +1,6 @@ package apigateway import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -53,22 +49,16 @@ resource "aws_api_gateway_domain_name" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { securityPolicyAttr := resourceBlock.GetAttribute("security_policy") - if securityPolicyAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should include security_policy (defaults to outdated SSL/TLS policy).", resourceBlock.FullName())), - ) + if securityPolicyAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' should include security_policy (defaults to outdated SSL/TLS policy).", resourceBlock.FullName()) return } - - if securityPolicyAttr.Type() == cty.String && securityPolicyAttr.Value().AsString() != "TLS_1_2" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines outdated SSL/TLS policies (not using TLS_1_2).", resourceBlock.FullName())). - WithAttribute(securityPolicyAttr), - ) + if securityPolicyAttr.NotEqual("TLS_1_2") { + set.AddResult(). + WithDescription("Resource '%s' defines outdated SSL/TLS policies (not using TLS_1_2).", resourceBlock.FullName()). + WithAttribute(securityPolicyAttr) } - }, }) } diff --git a/internal/app/tfsec/rules/aws/athena/enable_at_rest_encryption_rule.go b/internal/app/tfsec/rules/aws/athena/enable_at_rest_encryption_rule.go index 6be7738744..eb87608c44 100644 --- a/internal/app/tfsec/rules/aws/athena/enable_at_rest_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/athena/enable_at_rest_encryption_rule.go @@ -1,7 +1,6 @@ package athena import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -92,7 +91,6 @@ resource "aws_athena_workgroup" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { blockName := resourceBlock.FullName() - if strings.EqualFold(resourceBlock.TypeLabel(), "aws_athena_workgroup") { if !resourceBlock.HasChild("configuration") { return @@ -105,10 +103,8 @@ resource "aws_athena_workgroup" "good_example" { } if resourceBlock.MissingChild("encryption_configuration") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' missing encryption configuration block.", blockName)), - ) + set.AddResult(). + WithDescription("Resource '%s' missing encryption configuration block.", blockName) } }, diff --git a/internal/app/tfsec/rules/aws/athena/no_encryption_override_rule.go b/internal/app/tfsec/rules/aws/athena/no_encryption_override_rule.go index 8ba5569c30..96469eb338 100644 --- a/internal/app/tfsec/rules/aws/athena/no_encryption_override_rule.go +++ b/internal/app/tfsec/rules/aws/athena/no_encryption_override_rule.go @@ -1,8 +1,6 @@ package athena import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -84,20 +82,24 @@ resource "aws_athena_workgroup" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("configuration") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing the configuration block.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is missing the configuration block.", resourceBlock.FullName()) return } configBlock := resourceBlock.GetBlock("configuration") - if configBlock.HasChild("enforce_workgroup_configuration") && - configBlock.GetAttribute("enforce_workgroup_configuration").IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has enforce_workgroup_configuration set to false.", resourceBlock.FullName())), - ) + + configBlock.HasChild("enforce_workgroup_configuration") + enforceWorkgroupConfigAttr := configBlock.GetAttribute("enforce_workgroup_configuration") + + if enforceWorkgroupConfigAttr.IsNil() { + return + } + + if enforceWorkgroupConfigAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' has enforce_workgroup_configuration set to false.", resourceBlock.FullName()). + WithAttribute(enforceWorkgroupConfigAttr) } }, diff --git a/internal/app/tfsec/rules/aws/autoscaling/enable_at_rest_encryption_rule.go b/internal/app/tfsec/rules/aws/autoscaling/enable_at_rest_encryption_rule.go index 216fc55fab..20eb97c4ec 100644 --- a/internal/app/tfsec/rules/aws/autoscaling/enable_at_rest_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/autoscaling/enable_at_rest_encryption_rule.go @@ -1,8 +1,6 @@ package autoscaling import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -60,18 +56,16 @@ resource "aws_launch_configuration" "good_example" { for _, defaultEncryptionBlock := range context.GetResourcesByType("aws_ebs_encryption_by_default") { enabledAttr := defaultEncryptionBlock.GetAttribute("enabled") - if enabledAttr == nil || (enabledAttr.Type() == cty.Bool && enabledAttr.Value().True()) { + if enabledAttr.IsTrue() { encryptionByDefault = true } } rootDeviceBlock := resourceBlock.GetBlock("root_block_device") - if rootDeviceBlock == nil && !encryptionByDefault { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' uses an unencrypted root EBS block device. Consider adding root_block_device{ encrypted = true }", resourceBlock.FullName())), - ) - } else if rootDeviceBlock != nil { + if rootDeviceBlock.IsNil() && !encryptionByDefault { + set.AddResult(). + WithDescription("Resource '%s' uses an unencrypted root EBS block device. Consider adding root_block_device{ encrypted = true }", resourceBlock.FullName()) + } else if rootDeviceBlock.IsNotNil() { checkDeviceEncryption(rootDeviceBlock, encryptionByDefault, set, resourceBlock) } @@ -79,23 +73,18 @@ resource "aws_launch_configuration" "good_example" { for _, ebsDeviceBlock := range ebsDeviceBlocks { checkDeviceEncryption(ebsDeviceBlock, encryptionByDefault, set, resourceBlock) } - }, }) } func checkDeviceEncryption(deviceBlock block.Block, encryptionByDefault bool, set result.Set, resourceBlock block.Block) { encryptedAttr := deviceBlock.GetAttribute("encrypted") - if encryptedAttr == nil && !encryptionByDefault { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' uses an unencrypted EBS block device. Consider adding encrypted = true", resourceBlock.FullName())), - ) - } else if encryptedAttr != nil && encryptedAttr.Type() == cty.Bool && encryptedAttr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' uses an unencrypted root EBS block device.", resourceBlock.FullName())). - WithAttribute(encryptedAttr), - ) + if encryptedAttr.IsNil() && !encryptionByDefault { + set.AddResult(). + WithDescription("Resource '%s' uses an unencrypted EBS block device. Consider adding encrypted = true", resourceBlock.FullName()) + } else if encryptedAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' uses an unencrypted root EBS block device.", resourceBlock.FullName()). + WithAttribute(encryptedAttr) } } diff --git a/internal/app/tfsec/rules/aws/autoscaling/no_public_ip_rule.go b/internal/app/tfsec/rules/aws/autoscaling/no_public_ip_rule.go index 75284d042a..c2282dff28 100644 --- a/internal/app/tfsec/rules/aws/autoscaling/no_public_ip_rule.go +++ b/internal/app/tfsec/rules/aws/autoscaling/no_public_ip_rule.go @@ -1,8 +1,6 @@ package autoscaling import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -53,16 +49,16 @@ resource "aws_launch_configuration" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if publicAttr := resourceBlock.GetAttribute("associate_public_ip_address"); publicAttr != nil && publicAttr.Type() == cty.Bool { - if publicAttr.Value().True() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a public IP address associated.", resourceBlock.FullName())). - WithAttribute(publicAttr), - ) - } + if resourceBlock.MissingChild("associate_public_ip_address") { + return } + publicAttr := resourceBlock.GetAttribute("associate_public_ip_address") + if publicAttr.IsTrue() { + set.AddResult(). + WithDescription("Resource '%s' has a public IP address associated.", resourceBlock.FullName()). + WithAttribute(publicAttr) + } }, }) } diff --git a/internal/app/tfsec/rules/aws/cloudfront/enable_logging_rule.go b/internal/app/tfsec/rules/aws/cloudfront/enable_logging_rule.go index ca3e94efdd..ca33920995 100644 --- a/internal/app/tfsec/rules/aws/cloudfront/enable_logging_rule.go +++ b/internal/app/tfsec/rules/aws/cloudfront/enable_logging_rule.go @@ -1,8 +1,6 @@ package cloudfront import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,10 +55,8 @@ resource "aws_cloudfront_distribution" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("logging_config") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have Access Logging configured", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have Access Logging configured", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/aws/cloudfront/enable_waf_rule.go b/internal/app/tfsec/rules/aws/cloudfront/enable_waf_rule.go index 940fce7234..47feba5292 100644 --- a/internal/app/tfsec/rules/aws/cloudfront/enable_waf_rule.go +++ b/internal/app/tfsec/rules/aws/cloudfront/enable_waf_rule.go @@ -1,8 +1,6 @@ package cloudfront import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -106,11 +104,9 @@ resource "aws_cloudfront_distribution" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { wafAclIdBlock := resourceBlock.GetAttribute("web_acl_id") - if wafAclIdBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have a WAF in front of it.", resourceBlock.FullName())), - ) + if wafAclIdBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have a WAF in front of it.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/aws/cloudfront/enforce_https_rule.go b/internal/app/tfsec/rules/aws/cloudfront/enforce_https_rule.go index 59c5cb9fbf..fe25d01af7 100644 --- a/internal/app/tfsec/rules/aws/cloudfront/enforce_https_rule.go +++ b/internal/app/tfsec/rules/aws/cloudfront/enforce_https_rule.go @@ -1,8 +1,6 @@ package cloudfront import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -59,41 +55,36 @@ resource "aws_cloudfront_distribution" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { defaultBehaviorBlock := resourceBlock.GetBlock("default_cache_behavior") - if defaultBehaviorBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a CloudFront distribution that allows unencrypted communications (missing default_cache_behavior block).", resourceBlock.FullName())), - ) - } else { - protocolPolicyAttr := defaultBehaviorBlock.GetAttribute("viewer_protocol_policy") - if protocolPolicyAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a CloudFront distribution that allows unencrypted communications (missing viewer_protocol_policy block).", resourceBlock.FullName())), - ) - } else if protocolPolicyAttr.Type() == cty.String && protocolPolicyAttr.Value().AsString() == "allow-all" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a CloudFront distribution that allows unencrypted communications.", resourceBlock.FullName())). - WithAttribute(protocolPolicyAttr), - ) - } + if defaultBehaviorBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines a CloudFront distribution that allows unencrypted communications (missing default_cache_behavior block).", resourceBlock.FullName()) + return + } + + protocolPolicyAttr := defaultBehaviorBlock.GetAttribute("viewer_protocol_policy") + if protocolPolicyAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines a CloudFront distribution that allows unencrypted communications (missing viewer_protocol_policy block).", resourceBlock.FullName()). + WithBlock(defaultBehaviorBlock) + return + } + if protocolPolicyAttr.Equals("allow-all") { + set.AddResult(). + WithDescription("Resource '%s' defines a CloudFront distribution that allows unencrypted communications.", resourceBlock.FullName()). + WithAttribute(protocolPolicyAttr) + return } orderedBehaviorBlocks := resourceBlock.GetBlocks("ordered_cache_behavior") for _, orderedBehaviorBlock := range orderedBehaviorBlocks { orderedProtocolPolicyAttr := orderedBehaviorBlock.GetAttribute("viewer_protocol_policy") - if orderedProtocolPolicyAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a CloudFront distribution that allows unencrypted communications (missing viewer_protocol_policy block).", resourceBlock.FullName())), - ) - } else if orderedProtocolPolicyAttr.Type() == cty.String && orderedProtocolPolicyAttr.Value().AsString() == "allow-all" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a CloudFront distribution that allows unencrypted communications.", resourceBlock.FullName())). - WithAttribute(orderedProtocolPolicyAttr), - ) + if orderedProtocolPolicyAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines a CloudFront distribution that allows unencrypted communications (missing viewer_protocol_policy block).", resourceBlock.FullName()) + } else if orderedProtocolPolicyAttr.Equals("allow-all") { + set.AddResult(). + WithDescription("Resource '%s' defines a CloudFront distribution that allows unencrypted communications.", resourceBlock.FullName()). + WithAttribute(orderedProtocolPolicyAttr) } } diff --git a/internal/app/tfsec/rules/aws/cloudfront/use_secure_tls_policy_rule.go b/internal/app/tfsec/rules/aws/cloudfront/use_secure_tls_policy_rule.go index cb3b261ded..ae10a91433 100644 --- a/internal/app/tfsec/rules/aws/cloudfront/use_secure_tls_policy_rule.go +++ b/internal/app/tfsec/rules/aws/cloudfront/use_secure_tls_policy_rule.go @@ -1,8 +1,6 @@ package cloudfront import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -59,24 +55,24 @@ resource "aws_cloudfront_distribution" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { viewerCertificateBlock := resourceBlock.GetBlock("viewer_certificate") - if viewerCertificateBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines outdated SSL/TLS policies (missing viewer_certificate block)", resourceBlock.FullName())), - ) + if viewerCertificateBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines outdated SSL/TLS policies (missing viewer_certificate block)", resourceBlock.FullName()) + return + } + + minVersionAttr := viewerCertificateBlock.GetAttribute("minimum_protocol_version") + if minVersionAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines outdated SSL/TLS policies (missing minimum_protocol_version attribute)", resourceBlock.FullName()). + WithBlock(viewerCertificateBlock) return } - if minVersion := viewerCertificateBlock.GetAttribute("minimum_protocol_version"); minVersion == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines outdated SSL/TLS policies (missing minimum_protocol_version attribute)", resourceBlock.FullName())), - ) - } else if minVersion.Type() == cty.String && minVersion.Value().AsString() != "TLSv1.2_2021" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines outdated SSL/TLS policies (not using TLSv1.2_2021)", resourceBlock.FullName())), - ) + if minVersionAttr.NotEqual("TLSv1.2_2021") { + set.AddResult(). + WithDescription("Resource '%s' defines outdated SSL/TLS policies (not using TLSv1.2_2021)", resourceBlock.FullName()). + WithAttribute(minVersionAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/cloudtrail/enable_all_regions_rule.go b/internal/app/tfsec/rules/aws/cloudtrail/enable_all_regions_rule.go index fd509c6dbd..986a2478ec 100644 --- a/internal/app/tfsec/rules/aws/cloudtrail/enable_all_regions_rule.go +++ b/internal/app/tfsec/rules/aws/cloudtrail/enable_all_regions_rule.go @@ -1,8 +1,6 @@ package cloudtrail import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -67,21 +65,18 @@ resource "aws_cloudtrail" "good_example" { RequiredLabels: []string{"aws_cloudtrail"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + if resourceBlock.MissingChild("is_multi_region_trail") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not set multi region trail config.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not set multi region trail config.", resourceBlock.FullName()) return } multiRegionAttr := resourceBlock.GetAttribute("is_multi_region_trail") if multiRegionAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not enable multi region trail.", resourceBlock.FullName())). - WithAttribute(multiRegionAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' does not enable multi region trail.", resourceBlock.FullName()). + WithAttribute(multiRegionAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/cloudtrail/enable_at_rest_encryption_rule.go b/internal/app/tfsec/rules/aws/cloudtrail/enable_at_rest_encryption_rule.go index 72b7872c90..757cf2d143 100644 --- a/internal/app/tfsec/rules/aws/cloudtrail/enable_at_rest_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/cloudtrail/enable_at_rest_encryption_rule.go @@ -1,8 +1,6 @@ package cloudtrail import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -73,20 +71,16 @@ resource "aws_cloudtrail" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("kms_key_id") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have a kms_key_id set.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have a kms_key_id set.", resourceBlock.FullName()) return } kmsKeyIdAttr := resourceBlock.GetAttribute("kms_key_id") if kmsKeyIdAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a kms_key_id but it is not set.", resourceBlock.FullName())). - WithAttribute(kmsKeyIdAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has a kms_key_id but it is not set.", resourceBlock.FullName()). + WithAttribute(kmsKeyIdAttr) } }, diff --git a/internal/app/tfsec/rules/aws/cloudtrail/enable_log_validation_rule.go b/internal/app/tfsec/rules/aws/cloudtrail/enable_log_validation_rule.go index c612dbee66..143f9870d6 100644 --- a/internal/app/tfsec/rules/aws/cloudtrail/enable_log_validation_rule.go +++ b/internal/app/tfsec/rules/aws/cloudtrail/enable_log_validation_rule.go @@ -1,8 +1,6 @@ package cloudtrail import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -71,20 +69,16 @@ resource "aws_cloudtrail" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("enable_log_file_validation") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not enable log file validation.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not enable log file validation.", resourceBlock.FullName()) return } logFileValidationAttr := resourceBlock.GetAttribute("enable_log_file_validation") if logFileValidationAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not enable log file validation.", resourceBlock.FullName())). - WithAttribute(logFileValidationAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' does not enable log file validation.", resourceBlock.FullName()). + WithAttribute(logFileValidationAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/cloudwatch/log_group_customer_key_rule.go b/internal/app/tfsec/rules/aws/cloudwatch/log_group_customer_key_rule.go index dc92a327e3..70804eff7f 100644 --- a/internal/app/tfsec/rules/aws/cloudwatch/log_group_customer_key_rule.go +++ b/internal/app/tfsec/rules/aws/cloudwatch/log_group_customer_key_rule.go @@ -1,8 +1,6 @@ package cloudwatch import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -52,11 +50,10 @@ resource "aws_cloudwatch_log_group" "good_example" { RequiredLabels: []string{"aws_cloudwatch_log_group"}, DefaultSeverity: severity.Low, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + if resourceBlock.MissingChild("kms_key_id") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is only using default encryption", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is only using default encryption", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule.go b/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule.go index 9b44288c56..77b060f6e8 100644 --- a/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule.go @@ -1,8 +1,6 @@ package codebuild import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -102,26 +100,24 @@ resource "aws_codebuild_project" "codebuild" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { blocks := resourceBlock.GetBlocks("secondary_artifacts") - if artifact := resourceBlock.GetBlock("artifacts"); artifact != nil { + + if artifact := resourceBlock.GetBlock("artifacts"); artifact.IsNotNil() { blocks = append(blocks, artifact) } for _, artifactBlock := range blocks { - if encryptionDisabledAttr := artifactBlock.GetAttribute("encryption_disabled"); encryptionDisabledAttr != nil && encryptionDisabledAttr.IsTrue() { + encryptionDisabledAttr := artifactBlock.GetAttribute("encryption_disabled") + if encryptionDisabledAttr.IsTrue() { artifactTypeAttr := artifactBlock.GetAttribute("type") - if artifactTypeAttr != nil && artifactTypeAttr.Equals("NO_ARTIFACTS", block.IgnoreCase) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("CodeBuild project '%s' is configured to disable artifact encryption while no artifacts are produced", resourceBlock.FullName())). - WithAttribute(artifactTypeAttr), - ) + if artifactTypeAttr.Equals("NO_ARTIFACTS", block.IgnoreCase) { + set.AddResult(). + WithDescription("CodeBuild project '%s' is configured to disable artifact encryption while no artifacts are produced", resourceBlock.FullName()). + WithAttribute(artifactTypeAttr) } else { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("CodeBuild project '%s' does not encrypt produced artifacts", resourceBlock.FullName())). - WithAttribute(encryptionDisabledAttr), - ) + set.AddResult(). + WithDescription("CodeBuild project '%s' does not encrypt produced artifacts", resourceBlock.FullName()). + WithAttribute(encryptionDisabledAttr) } } } diff --git a/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule_test.go b/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule_test.go index 7d1085b02a..7aaa1f2269 100644 --- a/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule_test.go +++ b/internal/app/tfsec/rules/aws/codebuild/enable_encryption_rule_test.go @@ -8,7 +8,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/severity" - "github.com/stretchr/testify/assert" ) diff --git a/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule.go b/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule.go index 6a266edcd1..a9a32bfc5d 100644 --- a/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule.go +++ b/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule.go @@ -1,8 +1,6 @@ package config import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -63,29 +61,23 @@ resource "aws_config_configuration_aggregator" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { aggBlock := resourceBlock.GetFirstMatchingBlock("account_aggregation_source", "organization_aggregation_source") - if aggBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have account aggregation sources set", resourceBlock.FullName())), - ) + if aggBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' should have account aggregation sources set", resourceBlock.FullName()) return } if aggBlock.MissingChild("all_regions") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have account aggregation sources to all regions", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have account aggregation sources to all regions", resourceBlock.FullName()) return } allRegionsAttr := aggBlock.GetAttribute("all_regions") if allRegionsAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has all_regions set to false", resourceBlock.FullName())). - WithAttribute(allRegionsAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has all_regions set to false", resourceBlock.FullName()). + WithAttribute(allRegionsAttr) } }, diff --git a/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule_test.go b/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule_test.go index a0431cb1ae..aecafcbb51 100644 --- a/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule_test.go +++ b/internal/app/tfsec/rules/aws/config/aggregate_all_regions_rule_test.go @@ -18,37 +18,37 @@ func Test_AWSConfigAggregatorCoveringAllRegions(t *testing.T) { { name: "Account aggregation not set fails check", source: ` -resource "aws_config_configuration_aggregator" "bad_example" { - name = "example" -} -`, + resource "aws_config_configuration_aggregator" "bad_example" { + name = "example" + } + `, mustIncludeResultCode: expectedCode, }, { name: "Account aggregation using specific regions fails check", source: ` -resource "aws_config_configuration_aggregator" "bad_example" { - name = "example" - - account_aggregation_source { - account_ids = ["123456789012"] - regions = ["us-west-2", "eu-west-1"] - } -} -`, + resource "aws_config_configuration_aggregator" "bad_example" { + name = "example" + + account_aggregation_source { + account_ids = ["123456789012"] + regions = ["us-west-2", "eu-west-1"] + } + } + `, mustIncludeResultCode: expectedCode, }, { name: "All regions set to false fails check", source: ` -resource "aws_config_configuration_aggregator" "bad_example" { - name = "example" - - account_aggregation_source { - account_ids = ["123456789012"] - all_regions = false - } -} -`, + resource "aws_config_configuration_aggregator" "bad_example" { + name = "example" + + account_aggregation_source { + account_ids = ["123456789012"] + all_regions = false + } + } + `, mustIncludeResultCode: expectedCode, }, { 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 bc109654b8..477af3d9fe 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,8 +1,6 @@ package dynamodb import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -70,27 +68,23 @@ resource "aws_dax_cluster" "good_example" { RequiredLabels: []string{"aws_dax_cluster"}, DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.MissingChild("server_side_encryption") { - res := result.New(resourceBlock). - WithDescription(fmt.Sprintf("DAX cluster '%s' does not have server side encryption configured. By default it is disabled.", resourceBlock.FullName())) - set.Add(res) + set.AddResult(). + WithDescription("DAX cluster '%s' does not have server side encryption configured. By default it is disabled.", resourceBlock.FullName()) return } sseBlock := resourceBlock.GetBlock("server_side_encryption") if sseBlock.MissingChild("enabled") { - res := result.New(resourceBlock). - WithDescription(fmt.Sprintf("DAX cluster '%s' server side encryption block is empty. By default SSE is disabled.", resourceBlock.FullName())) - set.Add(res) - return + set.AddResult(). + WithDescription("DAX cluster '%s' server side encryption block is empty. By default SSE is disabled.", resourceBlock.FullName()). + WithBlock(sseBlock) } if sseEnabledAttr := sseBlock.GetAttribute("enabled"); sseEnabledAttr.IsFalse() { - res := result.New(resourceBlock). - WithDescription(fmt.Sprintf("DAX cluster '%s' has disabled server side encryption", resourceBlock.FullName())). + set.AddResult(). + WithDescription("DAX cluster '%s' has disabled server side encryption", resourceBlock.FullName()). WithAttribute(sseEnabledAttr) - set.Add(res) } }, 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 699702b0f1..e79243396e 100644 --- a/internal/app/tfsec/rules/aws/dynamodb/enable_recovery_rule.go +++ b/internal/app/tfsec/rules/aws/dynamodb/enable_recovery_rule.go @@ -1,8 +1,6 @@ package dynamodb import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -75,28 +73,23 @@ resource "aws_dynamodb_table" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("point_in_time_recovery") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' doesn't have point in time recovery", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' doesn't have point in time recovery", resourceBlock.FullName()) return } - poitBlock := resourceBlock.GetBlock("point_in_time_recovery") - if poitBlock.MissingChild("enabled") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' doesn't have point in time recovery enabled", resourceBlock.FullName())), - ) + pointBlock := resourceBlock.GetBlock("point_in_time_recovery") + if pointBlock.MissingChild("enabled") { + set.AddResult(). + WithDescription("Resource '%s' doesn't have point in time recovery enabled", resourceBlock.FullName()). + WithBlock(pointBlock) return } - enabledAttr := poitBlock.GetAttribute("enabled") + enabledAttr := pointBlock.GetAttribute("enabled") if enabledAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' doesn't have point in time recovery enabled", resourceBlock.FullName())). - WithAttribute(enabledAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' doesn't have point in time recovery enabled", resourceBlock.FullName()). + WithAttribute(enabledAttr) } }, 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 889275aa9d..3b6bf7c05e 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,8 +1,6 @@ package dynamodb import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -94,31 +92,25 @@ resource "aws_dynamodb_table" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("server_side_encryption") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not using KMS CMK for encryption", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is not using KMS CMK for encryption", resourceBlock.FullName()) return } sseBlock := resourceBlock.GetBlock("server_side_encryption") enabledAttr := sseBlock.GetAttribute("enabled") - if enabledAttr != nil && enabledAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has server side encryption configured but disabled", resourceBlock.FullName())). - WithAttribute(enabledAttr), - ) + if enabledAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' has server side encryption configured but disabled", resourceBlock.FullName()). + WithBlock(sseBlock) } if sseBlock.HasChild("kms_key_arn") { keyIdAttr := sseBlock.GetAttribute("kms_key_arn") if keyIdAttr.Equals("alias/aws/dynamodb") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has KMS encryption configured but is using the default aws key", resourceBlock.FullName())). - WithAttribute(keyIdAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has KMS encryption configured but is using the default aws key", resourceBlock.FullName()). + WithAttribute(keyIdAttr) } } diff --git a/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule.go b/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule.go index b2213a4772..a1e600b5fd 100644 --- a/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule.go +++ b/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule.go @@ -1,8 +1,6 @@ package ec2 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,16 +56,14 @@ resource "aws_instance" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { metaDataOptions := resourceBlock.GetBlock("metadata_options") - if metaDataOptions == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing `metadata_options` block - it is required with `http_tokens` set to `required` to make Instance Metadata Service more secure.", resourceBlock.FullName())), - ) + if metaDataOptions.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is missing `metadata_options` block - it is required with `http_tokens` set to `required` to make Instance Metadata Service more secure.", resourceBlock.FullName()) return } httpEndpointAttr := metaDataOptions.GetAttribute("http_endpoint") - if httpEndpointAttr != nil { + if httpEndpointAttr.IsNotNil() { if httpEndpointAttr.Equals("disabled") { // IMDS disabled and we don't need to check if http_tokens are correctly set up return @@ -75,12 +71,11 @@ resource "aws_instance" "good_example" { } httpTokensAttr := metaDataOptions.GetAttribute("http_tokens") - if httpTokensAttr != nil { - if !httpTokensAttr.Equals("required") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' `metadata_options` `http_tokens` attribute - should be set to `required` to make Instance Metadata Service more secure.", resourceBlock.FullName())), - ) + if httpTokensAttr.IsNotNil() { + if httpTokensAttr.NotEqual("required") { + set.AddResult(). + WithDescription("Resource '%s' `metadata_options` `http_tokens` attribute - should be set to `required` to make Instance Metadata Service more secure.", resourceBlock.FullName()). + WithAttribute(httpTokensAttr) } } diff --git a/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule_test.go b/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule_test.go index 1704d7c25d..5564139e62 100644 --- a/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule_test.go +++ b/internal/app/tfsec/rules/aws/ec2/enforce_http_token_imds_rule_test.go @@ -18,37 +18,37 @@ func Test_AWSInstanceMetadataChec(t *testing.T) { { name: "should fire as http_tokens not specified and by default are optional", source: ` -resource "aws_instance" "working example"{ - ami = "ami-005e54dee72cc1d00" - instance_type = "t2.micro" -} -`, + resource "aws_instance" "working example"{ + ami = "ami-005e54dee72cc1d00" + instance_type = "t2.micro" + } + `, mustIncludeResultCode: expectedCode, }, { name: "should fire as http_tokens explicitly set to optional and should be required", source: ` -resource "aws_instance" "working example"{ - ami = "ami-005e54dee72cc1d00" - instance_type = "t2.micro" - metadata_options { - http_tokens = "optional" - } -} -`, + resource "aws_instance" "working example"{ + ami = "ami-005e54dee72cc1d00" + instance_type = "t2.micro" + metadata_options { + http_tokens = "optional" + } + } + `, mustIncludeResultCode: expectedCode, }, { name: "should not fire when http_tokens set to required", source: ` -resource "aws_instance" "working example"{ - ami = "ami-005e54dee72cc1d00" - instance_type = "t2.micro" - metadata_options { - http_tokens = "required" - } -} -`, + resource "aws_instance" "working example"{ + ami = "ami-005e54dee72cc1d00" + instance_type = "t2.micro" + metadata_options { + http_tokens = "required" + } + } + `, mustExcludeResultCode: expectedCode, }, { diff --git a/internal/app/tfsec/rules/aws/ec2/no_secrets_in_user_data_rule.go b/internal/app/tfsec/rules/aws/ec2/no_secrets_in_user_data_rule.go index c3fce57212..d5c813e021 100644 --- a/internal/app/tfsec/rules/aws/ec2/no_secrets_in_user_data_rule.go +++ b/internal/app/tfsec/rules/aws/ec2/no_secrets_in_user_data_rule.go @@ -1,8 +1,6 @@ package ec2 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -76,20 +74,16 @@ EOF userDataAttr := resourceBlock.GetAttribute("user_data") if userDataAttr.Contains("AWS_ACCESS_KEY_ID", block.IgnoreCase) && userDataAttr.RegexMatches("(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has userdata with access key id defined.", resourceBlock.FullName())). - WithAttribute(userDataAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has userdata with access key id defined.", resourceBlock.FullName()). + WithAttribute(userDataAttr) } if userDataAttr.Contains("AWS_SECRET_ACCESS_KEY", block.IgnoreCase) && userDataAttr.RegexMatches("(?i)aws_secre.+[=:]\\s{0,}[A-Za-z0-9\\/+=]{40}.?") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has userdata with access secret key defined.", resourceBlock.FullName())). - WithAttribute(userDataAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has userdata with access secret key defined.", resourceBlock.FullName()). + WithAttribute(userDataAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule.go b/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule.go index 32beb57f86..f9a7e05464 100644 --- a/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule.go +++ b/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule.go @@ -1,8 +1,6 @@ package ecr import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -63,27 +59,20 @@ resource "aws_ecr_repository" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { if resourceBlock.MissingChild("image_scanning_configuration") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a disabled ECR image scan.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a disabled ECR image scan.", resourceBlock.FullName()) return } - ecrScanStatusBlock := resourceBlock.GetBlock("image_scanning_configuration") - ecrScanStatusAttr := ecrScanStatusBlock.GetAttribute("scan_on_push") + ecrScanStatusAttr := resourceBlock.GetNestedAttribute("image_scanning_configuration.scan_on_push") - if ecrScanStatusAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a disabled ECR image scan.", resourceBlock.FullName())), - ) - } else if ecrScanStatusAttr.Type() == cty.Bool && ecrScanStatusAttr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a disabled ECR image scan.", resourceBlock.FullName())). - WithAttribute(ecrScanStatusAttr), - ) + if ecrScanStatusAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines a disabled ECR image scan.", resourceBlock.FullName()) + } else if ecrScanStatusAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines a disabled ECR image scan.", resourceBlock.FullName()). + WithAttribute(ecrScanStatusAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule_test.go b/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule_test.go index 53f3284eca..f007e44aba 100644 --- a/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule_test.go +++ b/internal/app/tfsec/rules/aws/ecr/enable_image_scans_rule_test.go @@ -29,6 +29,18 @@ resource "aws_ecr_repository" "foo" { image_scanning_configuration { scan_on_push = false } +}`, + mustIncludeResultCode: expectedCode, + }, + { + name: "check ECR Image Scan on push not set", + source: ` +resource "aws_ecr_repository" "foo" { + name = "bar" + image_tag_mutability = "MUTABLE" + + image_scanning_configuration { + } }`, mustIncludeResultCode: expectedCode, }, diff --git a/internal/app/tfsec/rules/aws/ecr/enforce_immutable_repository_rule.go b/internal/app/tfsec/rules/aws/ecr/enforce_immutable_repository_rule.go index dca4022873..95a31dc447 100644 --- a/internal/app/tfsec/rules/aws/ecr/enforce_immutable_repository_rule.go +++ b/internal/app/tfsec/rules/aws/ecr/enforce_immutable_repository_rule.go @@ -1,8 +1,6 @@ package ecr import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -63,20 +61,16 @@ resource "aws_ecr_repository" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { imageTagMutabilityAttr := resourceBlock.GetAttribute("image_tag_mutability") - if imageTagMutabilityAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing `image_tag_mutability` attribute - it is required to make ecr image tag immutable.", resourceBlock.FullName())), - ) + if imageTagMutabilityAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is missing `image_tag_mutability` attribute - it is required to make ecr image tag immutable.", resourceBlock.FullName()) return } - if !imageTagMutabilityAttr.Equals("IMMUTABLE") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has `image_tag_mutability` attribute not set to `IMMUTABLE`", resourceBlock.FullName())). - WithAttribute(imageTagMutabilityAttr), - ) + if imageTagMutabilityAttr.NotEqual("IMMUTABLE") { + set.AddResult(). + WithDescription("Resource '%s' has `image_tag_mutability` attribute not set to `IMMUTABLE`", resourceBlock.FullName()). + WithAttribute(imageTagMutabilityAttr) } }, diff --git a/internal/app/tfsec/rules/aws/ecr/repository_customer_key_rule.go b/internal/app/tfsec/rules/aws/ecr/repository_customer_key_rule.go index d01f40f925..6d72052e99 100644 --- a/internal/app/tfsec/rules/aws/ecr/repository_customer_key_rule.go +++ b/internal/app/tfsec/rules/aws/ecr/repository_customer_key_rule.go @@ -1,8 +1,6 @@ package ecr import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -71,27 +69,23 @@ resource "aws_ecr_repository" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("encryption_configuration") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have CMK encryption configured", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have CMK encryption configured", resourceBlock.FullName()) return } encBlock := resourceBlock.GetBlock("encryption_configuration") if encBlock.MissingChild("kms_key") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' configures encryption without using CMK", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' configures encryption without using CMK", resourceBlock.FullName()). + WithBlock(encBlock) return } if encBlock.MissingChild("encryption_type") || encBlock.GetAttribute("encryption_type").Equals("AES256") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have the encryption type set to KMS", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have the encryption type set to KMS", resourceBlock.FullName()). + WithBlock(encBlock) } }, diff --git a/internal/app/tfsec/rules/aws/ecs/enable_container_insight_rule.go b/internal/app/tfsec/rules/aws/ecs/enable_container_insight_rule.go index abec39d48f..db84ae087a 100644 --- a/internal/app/tfsec/rules/aws/ecs/enable_container_insight_rule.go +++ b/internal/app/tfsec/rules/aws/ecs/enable_container_insight_rule.go @@ -1,8 +1,6 @@ package ecs import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,23 +55,19 @@ resource "aws_ecs_cluster" "good_example" { settingsBlock := resourceBlock.GetBlocks("setting") for _, setting := range settingsBlock { - if name := setting.GetAttribute("name"); name != nil && name.Equals("containerinsights", block.IgnoreCase) { - if valueAttr := setting.GetAttribute("value"); valueAttr != nil { + if name := setting.GetAttribute("name"); name.IsNotNil() && name.Equals("containerinsights", block.IgnoreCase) { + if valueAttr := setting.GetAttribute("value"); valueAttr.IsNotNil() { if !valueAttr.Equals("enabled", block.IgnoreCase) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has containerInsights set to disabled", resourceBlock.FullName())). - WithAttribute(valueAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has containerInsights set to disabled", resourceBlock.FullName()). + WithAttribute(valueAttr) } return } } } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have containerInsights enabled", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have containerInsights enabled", resourceBlock.FullName()) }, }) } diff --git a/internal/app/tfsec/rules/aws/ecs/enable_in_transit_encryption_rule.go b/internal/app/tfsec/rules/aws/ecs/enable_in_transit_encryption_rule.go index 8291a35d45..0a030d12ef 100644 --- a/internal/app/tfsec/rules/aws/ecs/enable_in_transit_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/ecs/enable_in_transit_encryption_rule.go @@ -1,8 +1,6 @@ package ecs import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -92,19 +90,15 @@ resource "aws_ecs_task_definition" "good_example" { } efsConfigBlock := v.GetBlock("efs_volume_configuration") if efsConfigBlock.MissingChild("transit_encryption") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has efs configuration with in transit encryption implicitly disabled", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has efs configuration with in transit encryption implicitly disabled", resourceBlock.FullName()) continue } transitAttr := efsConfigBlock.GetAttribute("transit_encryption") - if transitAttr != nil && transitAttr.Equals("disabled", block.IgnoreCase) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has efs configuration with transit encryption explicitly disabled", resourceBlock.FullName())). - WithAttribute(transitAttr), - ) + if transitAttr.Equals("disabled", block.IgnoreCase) { + set.AddResult(). + WithDescription("Resource '%s' has efs configuration with transit encryption explicitly disabled", resourceBlock.FullName()). + WithAttribute(transitAttr) } } diff --git a/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule.go b/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule.go index 6dcbf35640..ea3b46137e 100644 --- a/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule.go +++ b/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule.go @@ -2,10 +2,11 @@ package ecs import ( "encoding/json" - "fmt" + "strings" "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" + "github.com/zclconf/go-cty/cty" "github.com/aquasecurity/tfsec/pkg/provider" @@ -19,8 +20,6 @@ import ( "github.com/aquasecurity/tfsec/internal/app/tfsec/security" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -82,8 +81,8 @@ EOF DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if definitionsAttr := resourceBlock.GetAttribute("container_definitions"); definitionsAttr != nil && definitionsAttr.Type() == cty.String { - rawJSON := []byte(definitionsAttr.Value().AsString()) + if definitionsAttr := resourceBlock.GetAttribute("container_definitions"); definitionsAttr.IsNotNil() && definitionsAttr.Type() == cty.String { + rawJSON := strings.TrimSpace(definitionsAttr.Value().AsString()) var definitions []struct { EnvVars []struct { @@ -92,7 +91,8 @@ EOF } `json:"environment"` } - if err := json.Unmarshal(rawJSON, &definitions); err != nil { + err := json.Unmarshal([]byte(rawJSON), &definitions) + if err != nil { debug.Log("an error occurred processing container definition json: %s: %s", resourceBlock.Range(), err.Error()) return } @@ -100,10 +100,8 @@ EOF for _, definition := range definitions { for _, env := range definition.EnvVars { if security.IsSensitiveAttribute(env.Name) && env.Value != "" { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' includes a potentially sensitive environment variable '%s' in the container definition.", resourceBlock.FullName(), env.Name)). - WithAttribute(definitionsAttr), - ) + set.AddResult().WithDescription("Resource '%s' includes a potentially sensitive environment variable '%s' in the container definition.", resourceBlock.FullName(), env.Name). + WithAttribute(definitionsAttr) } } } diff --git a/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule_test.go b/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule_test.go index dead4268af..4508ee48e7 100644 --- a/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule_test.go +++ b/internal/app/tfsec/rules/aws/ecs/no_plaintext_secrets_rule_test.go @@ -15,27 +15,27 @@ func Test_AWSTaskDefinitionIncludesSensitiveData(t *testing.T) { mustIncludeResultCode string mustExcludeResultCode string }{ - { - name: "check aws_ecs_task_definition when sensitive env vars are included", - source: ` - resource "aws_ecs_task_definition" "my-task" { - container_definitions = < 0 { - auditLogFound := false - for _, logPublishingOption := range logPublishingOptions { - logType := logPublishingOption.GetAttribute("log_type") - if logType != nil { - if logType.Equals("AUDIT_LOGS") { - auditLogFound = true - } - } - } - if !auditLogFound { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing 'AUDIT_LOGS` in one of the `log_publishing_options`-`log_type` attributes so audit log is not enabled", resourceBlock.FullName())), - ) + auditLogFound := false + for _, logPublishingOption := range logPublishingOptions { + logType := logPublishingOption.GetAttribute("log_type") + if logType.IsNotNil() { + if logType.Equals("AUDIT_LOGS") { + auditLogFound = true + } } } + if !auditLogFound { + set.AddResult(). + WithDescription("Resource '%s' is missing 'AUDIT_LOGS` in one of the `log_publishing_options`-`log_type` attributes so audit log is not enabled", resourceBlock.FullName()) + } }, }) } diff --git a/internal/app/tfsec/rules/aws/elasticsearch/encrypt_replication_group_rule.go b/internal/app/tfsec/rules/aws/elasticsearch/encrypt_replication_group_rule.go index 4ddfdc8272..6f307fec7e 100644 --- a/internal/app/tfsec/rules/aws/elasticsearch/encrypt_replication_group_rule.go +++ b/internal/app/tfsec/rules/aws/elasticsearch/encrypt_replication_group_rule.go @@ -1,8 +1,6 @@ package elasticsearch import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,17 +55,13 @@ resource "aws_elasticache_replication_group" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { encryptionAttr := resourceBlock.GetAttribute("at_rest_encryption_enabled") - if encryptionAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted Elasticache Replication Group (missing at_rest_encryption_enabled attribute).", resourceBlock.FullName())), - ) + if encryptionAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted Elasticache Replication Group (missing at_rest_encryption_enabled attribute).", resourceBlock.FullName()) } else if !encryptionAttr.IsTrue() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted Elasticache Replication Group (at_rest_encryption_enabled set to false).", resourceBlock.FullName())). - WithAttribute(encryptionAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted Elasticache Replication Group (at_rest_encryption_enabled set to false).", resourceBlock.FullName()). + WithAttribute(encryptionAttr) } }, 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 4904c0eb4e..b45fbb089c 100644 --- a/internal/app/tfsec/rules/aws/elasticsearch/enforce_https_rule.go +++ b/internal/app/tfsec/rules/aws/elasticsearch/enforce_https_rule.go @@ -1,8 +1,6 @@ package elasticsearch import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -63,32 +59,22 @@ resource "aws_elasticsearch_domain" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { endpointBlock := resourceBlock.GetBlock("domain_endpoint_options") - if endpointBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an Elasticsearch domain with plaintext traffic (missing domain_endpoint_options block).", resourceBlock.FullName())), - ) + if endpointBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an Elasticsearch domain with plaintext traffic (missing domain_endpoint_options block).", resourceBlock.FullName()) return } enforceHTTPSAttr := endpointBlock.GetAttribute("enforce_https") - if enforceHTTPSAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an Elasticsearch domain with plaintext traffic (missing enforce_https attribute).", resourceBlock.FullName())), - ) + if enforceHTTPSAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an Elasticsearch domain with plaintext traffic (missing enforce_https attribute).", resourceBlock.FullName()) return } - isTrueBool := enforceHTTPSAttr.Type() == cty.Bool && enforceHTTPSAttr.Value().True() - isTrueString := enforceHTTPSAttr.Type() == cty.String && - enforceHTTPSAttr.Value().Equals(cty.StringVal("true")).True() - enforcedHTTPS := isTrueBool || isTrueString - if !enforcedHTTPS { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an Elasticsearch domain with plaintext traffic (enabled attribute set to false).", resourceBlock.FullName())), - ) + if enforceHTTPSAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines an Elasticsearch domain with plaintext traffic (enabled attribute set to false).", resourceBlock.FullName()) } }, 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 6ab7abfcea..4894a67642 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,8 +1,6 @@ package elasticsearch import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -63,26 +59,21 @@ resource "aws_elasticsearch_domain" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { endpointBlock := resourceBlock.GetBlock("domain_endpoint_options") - if endpointBlock == nil { - // Rule AWS033 covers this case. + if endpointBlock.IsNil() { return } tlsPolicyAttr := endpointBlock.GetAttribute("tls_security_policy") - if tlsPolicyAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an Elasticsearch domain with an outdated TLS policy (defaults to Policy-Min-TLS-1-0-2019-07).", resourceBlock.FullName())), - ) + if tlsPolicyAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an Elasticsearch domain with an outdated TLS policy (defaults to Policy-Min-TLS-1-0-2019-07).", resourceBlock.FullName()) return } - if tlsPolicyAttr.Value().Equals(cty.StringVal("Policy-Min-TLS-1-0-2019-07")).True() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an Elasticsearch domain with an outdated TLS policy (set to Policy-Min-TLS-1-0-2019-07).", resourceBlock.FullName())). - WithAttribute(tlsPolicyAttr), - ) + if tlsPolicyAttr.Equals("Policy-Min-TLS-1-0-2019-07") { + set.AddResult(). + WithDescription("Resource '%s' defines an Elasticsearch domain with an outdated TLS policy (set to Policy-Min-TLS-1-0-2019-07).", resourceBlock.FullName()). + WithAttribute(tlsPolicyAttr) } }, diff --git a/internal/app/tfsec/rules/aws/elasticservice/enable_domain_encryption_rule.go b/internal/app/tfsec/rules/aws/elasticservice/enable_domain_encryption_rule.go index 2814ef7733..b2d29f09a0 100644 --- a/internal/app/tfsec/rules/aws/elasticservice/enable_domain_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/elasticservice/enable_domain_encryption_rule.go @@ -1,8 +1,6 @@ package elasticservice import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -61,34 +57,24 @@ resource "aws_elasticsearch_domain" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { encryptionBlock := resourceBlock.GetBlock("encrypt_at_rest") - if encryptionBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted Elasticsearch domain (missing encrypt_at_rest block).", resourceBlock.FullName())), - ) + if encryptionBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted Elasticsearch domain (missing encrypt_at_rest block).", resourceBlock.FullName()) return } enabledAttr := encryptionBlock.GetAttribute("enabled") - if enabledAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted Elasticsearch domain (missing enabled attribute).", resourceBlock.FullName())), - ) + if enabledAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted Elasticsearch domain (missing enabled attribute).", resourceBlock.FullName()) return } - isTrueBool := enabledAttr.Type() == cty.Bool && enabledAttr.Value().True() - isTrueString := enabledAttr.Type() == cty.String && - enabledAttr.Value().Equals(cty.StringVal("true")).True() - encryptionEnabled := isTrueBool || isTrueString - if !encryptionEnabled { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted Elasticsearch domain (enabled attribute set to false).", resourceBlock.FullName())), - ) + if enabledAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted Elasticsearch domain (enabled attribute set to false).", resourceBlock.FullName()). + WithAttribute(enabledAttr) } - }, }) } diff --git a/internal/app/tfsec/rules/aws/elb/drop_invalid_headers_rule.go b/internal/app/tfsec/rules/aws/elb/drop_invalid_headers_rule.go index a8608bd2b4..a22bbe2fdc 100644 --- a/internal/app/tfsec/rules/aws/elb/drop_invalid_headers_rule.go +++ b/internal/app/tfsec/rules/aws/elb/drop_invalid_headers_rule.go @@ -1,8 +1,6 @@ package elb import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -72,26 +70,22 @@ resource "aws_alb" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.GetAttribute("load_balancer_type") == nil { + if resourceBlock.GetAttribute("load_balancer_type").IsNil() { return } if resourceBlock.GetAttribute("load_balancer_type").Equals("application", block.IgnoreCase) { if resourceBlock.MissingChild("drop_invalid_header_fields") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not drop invalid header fields", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not drop invalid header fields", resourceBlock.FullName()) return } attr := resourceBlock.GetAttribute("drop_invalid_header_fields") if attr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' sets the drop_invalid_header_fields to false", resourceBlock.FullName())). - WithAttribute(attr), - ) + set.AddResult(). + WithDescription("Resource '%s' sets the drop_invalid_header_fields to false", resourceBlock.FullName()). + WithAttribute(attr) } } diff --git a/internal/app/tfsec/rules/aws/elbv2/alb_not_public_rule.go b/internal/app/tfsec/rules/aws/elbv2/alb_not_public_rule.go index 19336df126..0596323b69 100644 --- a/internal/app/tfsec/rules/aws/elbv2/alb_not_public_rule.go +++ b/internal/app/tfsec/rules/aws/elbv2/alb_not_public_rule.go @@ -1,8 +1,6 @@ package elbv2 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,17 +51,13 @@ resource "aws_alb" "good_example" { if resourceBlock.HasChild("load_balancer_type") && resourceBlock.GetAttribute("load_balancer_type").Equals("gateway") { return } - if internalAttr := resourceBlock.GetAttribute("internal"); internalAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is exposed publicly.", resourceBlock.FullName())), - ) + if internalAttr := resourceBlock.GetAttribute("internal"); internalAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is exposed publicly.", resourceBlock.FullName()) } else if internalAttr.Type() == cty.Bool && internalAttr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is exposed publicly.", resourceBlock.FullName())). - WithAttribute(internalAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' is exposed publicly.", resourceBlock.FullName()). + WithAttribute(internalAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/elbv2/http_not_used_rule.go b/internal/app/tfsec/rules/aws/elbv2/http_not_used_rule.go index 810bc8cdeb..b06130b10e 100644 --- a/internal/app/tfsec/rules/aws/elbv2/http_not_used_rule.go +++ b/internal/app/tfsec/rules/aws/elbv2/http_not_used_rule.go @@ -1,8 +1,6 @@ package elbv2 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -59,14 +57,14 @@ resource "aws_alb_listener" "good_example" { protocolAttr := resourceBlock.GetAttribute("protocol") - if protocolAttr != nil { + if protocolAttr.IsNotNil() { if protocolAttr.IsResolvable() && (protocolAttr.Equals("HTTPS", block.IgnoreCase) || protocolAttr.Equals("TLS", block.IgnoreCase)) { return } if protocolAttr.IsResolvable() && protocolAttr.Equals("HTTP") { // check if this is a redirect to HTTPS - if it is, then no problem - if redirectProtocolAttr := resourceBlock.GetNestedAttribute("default_action/redirect/protocol"); redirectProtocolAttr != nil { + if redirectProtocolAttr := resourceBlock.GetNestedAttribute("default_action.redirect.protocol"); redirectProtocolAttr.IsNotNil() { if redirectProtocolAttr.IsResolvable() && redirectProtocolAttr.Equals("HTTPS") { return } @@ -74,14 +72,9 @@ resource "aws_alb_listener" "good_example" { } } - res := result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' uses plain HTTP instead of HTTPS.", resourceBlock.FullName())) - - if protocolAttr != nil { - res.WithAttribute(protocolAttr) - } - - set.Add(res) + set.AddResult(). + WithDescription("Resource '%s' uses plain HTTP instead of HTTPS.", resourceBlock.FullName()). + WithAttribute(protocolAttr) }, }) diff --git a/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go b/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go index b74d71e911..d6045fb6a9 100644 --- a/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go +++ b/internal/app/tfsec/rules/aws/iam/block_kms_policy_wildcard_rule.go @@ -167,7 +167,7 @@ data "aws_iam_policy_document" "kms_policy" { CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) { policyAttr := resourceBlock.GetAttribute("policy") - if policyAttr == nil { + if policyAttr.IsNil() { return } @@ -194,14 +194,12 @@ data "aws_iam_policy_document" "kms_policy" { } if statementBlock.HasChild("actions") && statementBlock.GetAttribute("actions").Contains("kms:*") { - if resources := statementBlock.GetAttribute("resources"); resources != nil { + if resources := statementBlock.GetAttribute("resources"); resources.IsNotNil() { resources.Each(func(key, value cty.Value) { if value.Type() == cty.String && strings.Contains(value.AsString(), ("*")) { - set.Add( - result.New(policyDocumentBlock). - WithDescription(fmt.Sprintf("Resource '%s' a policy with KMS actions for all KMS keys.", policyDocumentBlock.FullName())). - WithAttribute(resources), - ) + set.AddResult(). + WithDescription("Resource '%s' a policy with KMS actions for all KMS keys.", policyDocumentBlock.FullName()). + WithAttribute(resources) } }) @@ -228,11 +226,9 @@ func checkAWS097PolicyJSON(set result.Set, resourceBlock block.Block, policyAttr } for _, resource := range statement.Resource { if strings.Contains(resource, "*") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' a policy with KMS actions for all KMS keys.", resourceBlock.FullName())). - WithAttribute(policyAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' a policy with KMS actions for all KMS keys.", resourceBlock.FullName()). + WithAttribute(policyAttr) return } } diff --git a/internal/app/tfsec/rules/aws/iam/no_password_reuse_rule.go b/internal/app/tfsec/rules/aws/iam/no_password_reuse_rule.go index 38c4f5c11b..5379a50c1c 100644 --- a/internal/app/tfsec/rules/aws/iam/no_password_reuse_rule.go +++ b/internal/app/tfsec/rules/aws/iam/no_password_reuse_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,18 +55,14 @@ resource "aws_iam_account_password_policy" "good_example" { RequiredLabels: []string{"aws_iam_account_password_policy"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("password_reuse_prevention"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have a password reuse prevention count set.", resourceBlock.FullName())), - ) + if attr := resourceBlock.GetAttribute("password_reuse_prevention"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have a password reuse prevention count set.", resourceBlock.FullName()) } else if attr.Value().Type() == cty.Number { value, _ := attr.Value().AsBigFloat().Float64() if value < 5 { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a password reuse count less than 5.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has a password reuse count less than 5.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go b/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go index a8c73d598a..cc99e38492 100644 --- a/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go +++ b/internal/app/tfsec/rules/aws/iam/no_policy_wildcards_rule.go @@ -2,7 +2,6 @@ package iam import ( "encoding/json" - "fmt" "strings" "github.com/aquasecurity/tfsec/internal/app/tfsec/block" @@ -110,7 +109,7 @@ data "aws_iam_policy_document" "s3_policy" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) { policyAttr := resourceBlock.GetAttribute("policy") - if policyAttr == nil { + if policyAttr.IsNil() { return } @@ -142,36 +141,30 @@ func checkAWS099StatementBlock(set result.Set, statementBlock block.Block, polic actionsAttr := statementBlock.GetAttribute("actions") actionsAttr.Each(func(key, value cty.Value) { if value.Type() == cty.String && strings.Contains(value.AsString(), ("*")) { - set.Add( - result.New(policyDocumentBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a policy with wildcarded actions.", policyDocumentBlock.FullName())). - WithAttribute(actionsAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a policy with wildcarded actions.", policyDocumentBlock.FullName()). + WithAttribute(actionsAttr) } }) resourcesAttr := statementBlock.GetAttribute("resources") - if resourcesAttr != nil && resourcesAttr.Contains("*") && (actionsAttr == nil || !doActionsAllowWildcardResource(actionsAttr.ValueAsStrings())) { - set.Add( - result.New(policyDocumentBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a policy with wildcarded resources.", policyDocumentBlock.FullName())). - WithAttribute(resourcesAttr), - ) + if resourcesAttr.IsNotNil() && resourcesAttr.Contains("*") && (actionsAttr.IsNil() || !doActionsAllowWildcardResource(actionsAttr.ValueAsStrings())) { + set.AddResult(). + WithDescription("Resource '%s' defines a policy with wildcarded resources.", policyDocumentBlock.FullName()). + WithAttribute(resourcesAttr) } principalsBlock := statementBlock.GetBlock("principals") - if principalsBlock != nil { + if principalsBlock.IsNotNil() { principalTypeAttr := principalsBlock.GetAttribute("type") - if principalTypeAttr != nil && principalTypeAttr.Equals("AWS") { + if principalTypeAttr.IsNotNil() && principalTypeAttr.Equals("AWS") { identifiersAttr := principalsBlock.GetAttribute("identifiers") - if identifiersAttr != nil { + if identifiersAttr.IsNotNil() { for _, ident := range identifiersAttr.ValueAsStrings() { if strings.Contains(ident, "*") { - set.Add( - result.New(policyDocumentBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a policy with wildcarded principal identifiers.", policyDocumentBlock.FullName())). - WithAttribute(resourcesAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a policy with wildcarded principal identifiers.", policyDocumentBlock.FullName()). + WithAttribute(resourcesAttr) break } } @@ -200,29 +193,23 @@ func checkAWS099PolicyJSON(set result.Set, resourceBlock block.Block, policyAttr } for _, action := range statement.Action { if strings.Contains(action, "*") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a policy with wildcarded actions.", resourceBlock.FullName())). - WithAttribute(policyAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a policy with wildcarded actions.", resourceBlock.FullName()). + WithAttribute(policyAttr) } } for _, resource := range statement.Resource { if strings.Contains(resource, "*") && !doActionsAllowWildcardResource(statement.Action) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a policy with wildcarded resources.", resourceBlock.FullName())). - WithAttribute(policyAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a policy with wildcarded resources.", resourceBlock.FullName()). + WithAttribute(policyAttr) } } for _, identifier := range statement.Principal.AWS { if strings.Contains(identifier, "*") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a policy with wildcarded principal identifiers.", resourceBlock.FullName())). - WithAttribute(policyAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a policy with wildcarded principal identifiers.", resourceBlock.FullName()). + WithAttribute(policyAttr) } } } diff --git a/internal/app/tfsec/rules/aws/iam/require_lowercase_in_passwords_rule.go b/internal/app/tfsec/rules/aws/iam/require_lowercase_in_passwords_rule.go index 6e333780fd..8183b12a97 100644 --- a/internal/app/tfsec/rules/aws/iam/require_lowercase_in_passwords_rule.go +++ b/internal/app/tfsec/rules/aws/iam/require_lowercase_in_passwords_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -51,17 +49,13 @@ resource "aws_iam_account_password_policy" "good_example" { RequiredLabels: []string{"aws_iam_account_password_policy"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("require_lowercase_characters"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not require a lowercase character in the password.", resourceBlock.FullName())), - ) + if attr := resourceBlock.GetAttribute("require_lowercase_characters"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not require a lowercase character in the password.", resourceBlock.FullName()) } else if attr.Value().Type() == cty.Bool { if attr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' explicitly specifies not requiring at least lowercase character in the password.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' explicitly specifies not requiring at least lowercase character in the password.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/aws/iam/require_numbers_in_passwords_rule.go b/internal/app/tfsec/rules/aws/iam/require_numbers_in_passwords_rule.go index 84968418d9..0b25290b55 100644 --- a/internal/app/tfsec/rules/aws/iam/require_numbers_in_passwords_rule.go +++ b/internal/app/tfsec/rules/aws/iam/require_numbers_in_passwords_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,17 +51,13 @@ resource "aws_iam_account_password_policy" "good_example" { RequiredLabels: []string{"aws_iam_account_password_policy"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("require_numbers"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not require a number in the password.", resourceBlock.FullName())), - ) + if attr := resourceBlock.GetAttribute("require_numbers"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not require a number in the password.", resourceBlock.FullName()) } else if attr.Value().Type() == cty.Bool { if attr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' explicitly specifies not requiring at least one number in the password.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' explicitly specifies not requiring at least one number in the password.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/aws/iam/require_symbols_in_passwords_rule.go b/internal/app/tfsec/rules/aws/iam/require_symbols_in_passwords_rule.go index 1d3b239dd1..18ebc13431 100644 --- a/internal/app/tfsec/rules/aws/iam/require_symbols_in_passwords_rule.go +++ b/internal/app/tfsec/rules/aws/iam/require_symbols_in_passwords_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,17 +51,13 @@ resource "aws_iam_account_password_policy" "good_example" { RequiredLabels: []string{"aws_iam_account_password_policy"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("require_symbols"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not require a symbol in the password.", resourceBlock.FullName())), - ) + if attr := resourceBlock.GetAttribute("require_symbols"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not require a symbol in the password.", resourceBlock.FullName()) } else if attr.Value().Type() == cty.Bool { if attr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' explicitly specifies not requiring at least one symbol in the password.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' explicitly specifies not requiring at least one symbol in the password.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/aws/iam/require_uppercase_in_passwords_rule.go b/internal/app/tfsec/rules/aws/iam/require_uppercase_in_passwords_rule.go index 58293f7e2c..e2af0fa204 100644 --- a/internal/app/tfsec/rules/aws/iam/require_uppercase_in_passwords_rule.go +++ b/internal/app/tfsec/rules/aws/iam/require_uppercase_in_passwords_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -55,17 +53,13 @@ resource "aws_iam_account_password_policy" "good_example" { RequiredLabels: []string{"aws_iam_account_password_policy"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("require_uppercase_characters"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not require an uppercase character in the password.", resourceBlock.FullName())), - ) + if attr := resourceBlock.GetAttribute("require_uppercase_characters"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not require an uppercase character in the password.", resourceBlock.FullName()) } else if attr.Value().Type() == cty.Bool { if attr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' explicitly specifies not requiring at least one uppercase character in the password.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' explicitly specifies not requiring at least one uppercase character in the password.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/aws/iam/set_max_password_age_rule.go b/internal/app/tfsec/rules/aws/iam/set_max_password_age_rule.go index 590c78c1bf..27b504d4d8 100644 --- a/internal/app/tfsec/rules/aws/iam/set_max_password_age_rule.go +++ b/internal/app/tfsec/rules/aws/iam/set_max_password_age_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,19 +51,15 @@ resource "aws_iam_account_password_policy" "good_example" { RequiredLabels: []string{"aws_iam_account_password_policy"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("max_password_age"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have a max password age set.", resourceBlock.FullName())), - ) + if attr := resourceBlock.GetAttribute("max_password_age"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have a max password age set.", resourceBlock.FullName()) } else if attr.Value().Type() == cty.Number { value, _ := attr.Value().AsBigFloat().Float64() if value > 90 { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has high password age.", resourceBlock.FullName())). - WithAttribute(attr), - ) + set.AddResult(). + WithDescription("Resource '%s' has high password age.", resourceBlock.FullName()). + WithAttribute(attr) } } }, diff --git a/internal/app/tfsec/rules/aws/iam/set_minimum_password_length_rule.go b/internal/app/tfsec/rules/aws/iam/set_minimum_password_length_rule.go index ed450fb362..7de7a9c0be 100644 --- a/internal/app/tfsec/rules/aws/iam/set_minimum_password_length_rule.go +++ b/internal/app/tfsec/rules/aws/iam/set_minimum_password_length_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -55,18 +53,14 @@ resource "aws_iam_account_password_policy" "good_example" { RequiredLabels: []string{"aws_iam_account_password_policy"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("minimum_password_length"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have a minimum password length set.", resourceBlock.FullName())), - ) + if attr := resourceBlock.GetAttribute("minimum_password_length"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have a minimum password length set.", resourceBlock.FullName()) } else if attr.Value().Type() == cty.Number { value, _ := attr.Value().AsBigFloat().Float64() if value < 14 { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a minimum password length which is less than 14 characters.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has a minimum password length which is less than 14 characters.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/aws/kinesis/enable_in_transit_encryption_rule.go b/internal/app/tfsec/rules/aws/kinesis/enable_in_transit_encryption_rule.go index 377834fe36..9994a81abc 100644 --- a/internal/app/tfsec/rules/aws/kinesis/enable_in_transit_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/kinesis/enable_in_transit_encryption_rule.go @@ -1,7 +1,6 @@ package kinesis import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -55,24 +54,18 @@ resource "aws_kinesis_stream" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { encryptionTypeAttr := resourceBlock.GetAttribute("encryption_type") - if encryptionTypeAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted Kinesis Stream.", resourceBlock.FullName())), - ) + if encryptionTypeAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted Kinesis Stream.", resourceBlock.FullName()) } else if encryptionTypeAttr.Type() == cty.String && strings.ToUpper(encryptionTypeAttr.Value().AsString()) != "KMS" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted Kinesis Stream.", resourceBlock.FullName())). - WithAttribute(encryptionTypeAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted Kinesis Stream.", resourceBlock.FullName()). + WithAttribute(encryptionTypeAttr) } else { keyIDAttr := resourceBlock.GetAttribute("kms_key_id") - if keyIDAttr == nil || keyIDAttr.IsEmpty() || keyIDAttr.Equals("alias/aws/kinesis") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a Kinesis Stream encrypted with the default Kinesis key.", resourceBlock.FullName())), - ) + if keyIDAttr.IsNil() || keyIDAttr.IsEmpty() || keyIDAttr.Equals("alias/aws/kinesis") { + set.AddResult(). + WithDescription("Resource '%s' defines a Kinesis Stream encrypted with the default Kinesis key.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/aws/kms/auto_rotate_keys_rule.go b/internal/app/tfsec/rules/aws/kms/auto_rotate_keys_rule.go index 07ea9e54e7..18e79ea182 100644 --- a/internal/app/tfsec/rules/aws/kms/auto_rotate_keys_rule.go +++ b/internal/app/tfsec/rules/aws/kms/auto_rotate_keys_rule.go @@ -1,8 +1,6 @@ package kms import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,26 +51,22 @@ resource "aws_kms_key" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { keyUsageAttr := resourceBlock.GetAttribute("key_usage") - if keyUsageAttr != nil && keyUsageAttr.Equals("SIGN_VERIFY") { + if keyUsageAttr.IsNotNil() && keyUsageAttr.Equals("SIGN_VERIFY") { return } keyRotationAttr := resourceBlock.GetAttribute("enable_key_rotation") - if keyRotationAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have KMS Key auto-rotation enabled.", resourceBlock.FullName())), - ) + if keyRotationAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have KMS Key auto-rotation enabled.", resourceBlock.FullName()) return } if keyRotationAttr.Type() == cty.Bool && keyRotationAttr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have KMS Key auto-rotation enabled.", resourceBlock.FullName())). - WithAttribute(keyRotationAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have KMS Key auto-rotation enabled.", resourceBlock.FullName()). + WithAttribute(keyRotationAttr) } }, diff --git a/internal/app/tfsec/rules/aws/lambda/restrict_source_arn_rule.go b/internal/app/tfsec/rules/aws/lambda/restrict_source_arn_rule.go index 0fafc0b640..45e94a6a95 100644 --- a/internal/app/tfsec/rules/aws/lambda/restrict_source_arn_rule.go +++ b/internal/app/tfsec/rules/aws/lambda/restrict_source_arn_rule.go @@ -1,8 +1,6 @@ package lambda import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -62,10 +60,8 @@ resource "aws_lambda_permission" "good_example" { if resourceBlock.HasChild("principal") { if resourceBlock.GetAttribute("principal").EndsWith("amazonaws.com") { if resourceBlock.MissingChild("source_arn") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' missing source ARN but has *.amazonaws.com Principal.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' missing source ARN but has *.amazonaws.com Principal.", resourceBlock.FullName()) } } } diff --git a/internal/app/tfsec/rules/aws/misc/no_exposing_plaintext_credentials_rule.go b/internal/app/tfsec/rules/aws/misc/no_exposing_plaintext_credentials_rule.go index 84bf692ef3..5aa59d12fd 100644 --- a/internal/app/tfsec/rules/aws/misc/no_exposing_plaintext_credentials_rule.go +++ b/internal/app/tfsec/rules/aws/misc/no_exposing_plaintext_credentials_rule.go @@ -1,8 +1,6 @@ package misc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -52,18 +50,14 @@ provider "aws" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if accessKeyAttribute := resourceBlock.GetAttribute("access_key"); accessKeyAttribute != nil && accessKeyAttribute.Type() == cty.String { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Provider '%s' has an access key specified.", resourceBlock.FullName())). - WithAttribute(accessKeyAttribute), - ) - } else if secretKeyAttribute := resourceBlock.GetAttribute("secret_key"); secretKeyAttribute != nil && secretKeyAttribute.Type() == cty.String { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Provider '%s' has a secret key specified.", resourceBlock.FullName())). - WithAttribute(secretKeyAttribute), - ) + if accessKeyAttribute := resourceBlock.GetAttribute("access_key"); accessKeyAttribute.IsNotNil() && accessKeyAttribute.Type() == cty.String { + set.AddResult(). + WithDescription("Provider '%s' has an access key specified.", resourceBlock.FullName()). + WithAttribute(accessKeyAttribute) + } else if secretKeyAttribute := resourceBlock.GetAttribute("secret_key"); secretKeyAttribute.IsNotNil() && secretKeyAttribute.Type() == cty.String { + set.AddResult(). + WithDescription("Provider '%s' has a secret key specified.", resourceBlock.FullName()). + WithAttribute(secretKeyAttribute) } }, diff --git a/internal/app/tfsec/rules/aws/msk/enable_in_transit_encryption_rule.go b/internal/app/tfsec/rules/aws/msk/enable_in_transit_encryption_rule.go index de3d57dcbe..8db0c2dc10 100644 --- a/internal/app/tfsec/rules/aws/msk/enable_in_transit_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/msk/enable_in_transit_encryption_rule.go @@ -1,8 +1,6 @@ package msk import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -61,41 +59,31 @@ resource "aws_msk_cluster" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { defaultBehaviorBlock := resourceBlock.GetBlock("encryption_info") - if defaultBehaviorBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit (missing encryption_info block).", resourceBlock.FullName())), - ) + if defaultBehaviorBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit (missing encryption_info block).", resourceBlock.FullName()) return } encryptionInTransit := defaultBehaviorBlock.GetBlock("encryption_in_transit") - if encryptionInTransit == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit (missing encryption_in_transit block).", resourceBlock.FullName())), - ) + if encryptionInTransit.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit (missing encryption_in_transit block).", resourceBlock.FullName()).WithBlock(defaultBehaviorBlock) return } clientBrokerAttr := encryptionInTransit.GetAttribute("client_broker") - if clientBrokerAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit (missing client_broker block).", resourceBlock.FullName())), - ) + if clientBrokerAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit (missing client_broker block).", resourceBlock.FullName()).WithBlock(encryptionInTransit) } else if clientBrokerAttr.Value().AsString() == "PLAINTEXT" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a MSK cluster that only allows plaintext data in transit.", resourceBlock.FullName())). - WithAttribute(clientBrokerAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a MSK cluster that only allows plaintext data in transit.", resourceBlock.FullName()). + WithAttribute(clientBrokerAttr) } else if clientBrokerAttr.Value().AsString() == "TLS_PLAINTEXT" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit.", resourceBlock.FullName())). - WithAttribute(clientBrokerAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a MSK cluster that allows plaintext as well as TLS encrypted data in transit.", resourceBlock.FullName()). + WithAttribute(clientBrokerAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/rds/backup_retention_specified_rule.go b/internal/app/tfsec/rules/aws/rds/backup_retention_specified_rule.go index 1d4771ee11..0186ee0276 100644 --- a/internal/app/tfsec/rules/aws/rds/backup_retention_specified_rule.go +++ b/internal/app/tfsec/rules/aws/rds/backup_retention_specified_rule.go @@ -1,8 +1,6 @@ package rds import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -95,20 +93,16 @@ resource "aws_rds_cluster" "good_example" { } if resourceBlock.MissingChild("backup_retention_period") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have backup retention explicitly set", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have backup retention explicitly set", resourceBlock.FullName()) return } retentionAttr := resourceBlock.GetAttribute("backup_retention_period") if retentionAttr.LessThanOrEqualTo(1) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has backup retention period set to a low value", resourceBlock.FullName())). - WithAttribute(retentionAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has backup retention period set to a low value", resourceBlock.FullName()). + WithAttribute(retentionAttr) } }, diff --git a/internal/app/tfsec/rules/aws/rds/enable_performance_insights_rule.go b/internal/app/tfsec/rules/aws/rds/enable_performance_insights_rule.go index 0dfc3ded14..416c6211d3 100644 --- a/internal/app/tfsec/rules/aws/rds/enable_performance_insights_rule.go +++ b/internal/app/tfsec/rules/aws/rds/enable_performance_insights_rule.go @@ -1,8 +1,6 @@ package rds import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -59,19 +57,15 @@ resource "aws_rds_cluster_instance" "good_example" { if resourceBlock.HasChild("performance_insights_enabled") && resourceBlock.GetAttribute("performance_insights_enabled").IsTrue() { if resourceBlock.MissingChild("performance_insights_kms_key_id") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines Performance Insights without encryption key specified.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines Performance Insights without encryption key specified.", resourceBlock.FullName()) return } if keyAttr := resourceBlock.GetAttribute("performance_insights_kms_key_id"); keyAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines Performance Insights without encryption key specified.", resourceBlock.FullName())). - WithAttribute(keyAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines Performance Insights without encryption key specified.", resourceBlock.FullName()). + WithAttribute(keyAttr) } } diff --git a/internal/app/tfsec/rules/aws/rds/encrypt_cluster_storage_data_rule.go b/internal/app/tfsec/rules/aws/rds/encrypt_cluster_storage_data_rule.go index a12475610f..f1a55e993a 100644 --- a/internal/app/tfsec/rules/aws/rds/encrypt_cluster_storage_data_rule.go +++ b/internal/app/tfsec/rules/aws/rds/encrypt_cluster_storage_data_rule.go @@ -1,8 +1,6 @@ package rds import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -56,24 +54,15 @@ resource "aws_rds_cluster" "good_example" { kmsKeyIdAttr := resourceBlock.GetAttribute("kms_key_id") storageEncryptedattr := resourceBlock.GetAttribute("storage_encrypted") - if (kmsKeyIdAttr == nil || kmsKeyIdAttr.IsEmpty()) && - (storageEncryptedattr == nil || storageEncryptedattr.IsFalse()) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a disabled RDS Cluster encryption.", resourceBlock.FullName())), - ) - } else if kmsKeyIdAttr != nil && kmsKeyIdAttr.Equals("") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a disabled RDS Cluster encryption.", resourceBlock.FullName())). - WithAttribute(kmsKeyIdAttr), - ) - } else if storageEncryptedattr == nil || storageEncryptedattr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a enabled RDS Cluster encryption but not the required encrypted_storage.", resourceBlock.FullName())). - WithAttribute(kmsKeyIdAttr), - ) + if kmsKeyIdAttr.IsEmpty() && storageEncryptedattr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines a disabled RDS Cluster encryption.", resourceBlock.FullName()) + } else if kmsKeyIdAttr.IsNotNil() && kmsKeyIdAttr.Equals("") { + set.AddResult(). + WithDescription("Resource '%s' defines a disabled RDS Cluster encryption.", resourceBlock.FullName()) + } else if storageEncryptedattr.IsNil() || storageEncryptedattr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines a enabled RDS Cluster encryption but not the required encrypted_storage.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/aws/rds/encrypt_instance_storage_data_rule.go b/internal/app/tfsec/rules/aws/rds/encrypt_instance_storage_data_rule.go index f38d93b762..a3fff54e91 100644 --- a/internal/app/tfsec/rules/aws/rds/encrypt_instance_storage_data_rule.go +++ b/internal/app/tfsec/rules/aws/rds/encrypt_instance_storage_data_rule.go @@ -1,8 +1,6 @@ package rds import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,20 +51,16 @@ resource "aws_db_instance" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("storage_encrypted") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has no storage encryption defined.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has no storage encryption defined.", resourceBlock.FullName()) return } storageEncryptedAttr := resourceBlock.GetAttribute("storage_encrypted") if storageEncryptedAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has storage encrypted set to false", resourceBlock.FullName())). - WithAttribute(storageEncryptedAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has storage encrypted set to false", resourceBlock.FullName()). + WithAttribute(storageEncryptedAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/rds/no_classic_resources_rule.go b/internal/app/tfsec/rules/aws/rds/no_classic_resources_rule.go index 21a95e83f6..d89ae55cea 100644 --- a/internal/app/tfsec/rules/aws/rds/no_classic_resources_rule.go +++ b/internal/app/tfsec/rules/aws/rds/no_classic_resources_rule.go @@ -1,8 +1,6 @@ package rds import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -50,10 +48,8 @@ resource "aws_security_group" "good_example" { RequiredLabels: []string{"aws_db_security_group", "aws_redshift_security_group", "aws_elasticache_security_group"}, DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' uses EC2 Classic. Use a VPC instead.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' uses EC2 Classic. Use a VPC instead.", resourceBlock.FullName()) }, }) } diff --git a/internal/app/tfsec/rules/aws/rds/no_public_db_access_rule.go b/internal/app/tfsec/rules/aws/rds/no_public_db_access_rule.go index 1126535f59..de0f187d02 100644 --- a/internal/app/tfsec/rules/aws/rds/no_public_db_access_rule.go +++ b/internal/app/tfsec/rules/aws/rds/no_public_db_access_rule.go @@ -1,8 +1,6 @@ package rds import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -50,17 +46,12 @@ resource "aws_db_instance" "good_example" { RequiredLabels: []string{"aws_db_instance", "aws_dms_replication_instance", "aws_rds_cluster_instance", "aws_redshift_cluster"}, DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - - if publicAttr := resourceBlock.GetAttribute("publicly_accessible"); publicAttr != nil && publicAttr.Type() == cty.Bool { - if publicAttr.Value().True() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is exposed publicly.", resourceBlock.FullName())). - WithAttribute(publicAttr), - ) - } + publicAttr := resourceBlock.GetAttribute("publicly_accessible") + if publicAttr.IsTrue() { + set.AddResult(). + WithDescription("Resource '%s' is exposed publicly.", resourceBlock.FullName()). + WithAttribute(publicAttr) } - }, }) } diff --git a/internal/app/tfsec/rules/aws/redshift/encryption_customer_key_rule.go b/internal/app/tfsec/rules/aws/redshift/encryption_customer_key_rule.go index 9a7f2beaca..f0dccc3488 100644 --- a/internal/app/tfsec/rules/aws/redshift/encryption_customer_key_rule.go +++ b/internal/app/tfsec/rules/aws/redshift/encryption_customer_key_rule.go @@ -1,8 +1,6 @@ package redshift import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -67,28 +65,22 @@ resource "aws_redshift_cluster" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("encrypted") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have encryption enabled", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have encryption enabled", resourceBlock.FullName()) return } encryptedAttr := resourceBlock.GetAttribute("encrypted") if encryptedAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has encryption explicitly disabled", resourceBlock.FullName())). - WithAttribute(encryptedAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has encryption explicitly disabled", resourceBlock.FullName()). + WithAttribute(encryptedAttr) return } if resourceBlock.MissingChild("kms_key_id") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have a customer managed key specified", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have a customer managed key specified", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/aws/redshift/non_default_vpc_deployment_rule.go b/internal/app/tfsec/rules/aws/redshift/non_default_vpc_deployment_rule.go index 2800079d62..dca00a6850 100644 --- a/internal/app/tfsec/rules/aws/redshift/non_default_vpc_deployment_rule.go +++ b/internal/app/tfsec/rules/aws/redshift/non_default_vpc_deployment_rule.go @@ -1,8 +1,6 @@ package redshift import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -64,10 +62,8 @@ resource "aws_redshift_cluster" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("cluster_subnet_group_name") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is being deployed outside of a VPC", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is being deployed outside of a VPC", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/aws/s3/block_public_acls_rule.go b/internal/app/tfsec/rules/aws/s3/block_public_acls_rule.go index aa2c129547..4fbf15a41e 100644 --- a/internal/app/tfsec/rules/aws/s3/block_public_acls_rule.go +++ b/internal/app/tfsec/rules/aws/s3/block_public_acls_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,20 +56,16 @@ resource "aws_s3_bucket_public_access_block" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("block_public_acls") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not specify block_public_acls, defaults to false", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not specify block_public_acls, defaults to false", resourceBlock.FullName()) return } - attr := resourceBlock.GetAttribute("block_public_acls") - if attr != nil && attr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' sets block_public_acls explicitly to false", resourceBlock.FullName())). - WithAttribute(attr), - ) + publicAclAttr := resourceBlock.GetAttribute("block_public_acls") + if publicAclAttr.IsNotNil() && publicAclAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' sets block_public_acls explicitly to false", resourceBlock.FullName()). + WithAttribute(publicAclAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/s3/block_public_policy_rule.go b/internal/app/tfsec/rules/aws/s3/block_public_policy_rule.go index 2f49b8fd5e..8111f03108 100644 --- a/internal/app/tfsec/rules/aws/s3/block_public_policy_rule.go +++ b/internal/app/tfsec/rules/aws/s3/block_public_policy_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,20 +56,16 @@ resource "aws_s3_bucket_public_access_block" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("block_public_policy") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not specify block_public_policy, defaults to false", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not specify block_public_policy, defaults to false", resourceBlock.FullName()) return } attr := resourceBlock.GetAttribute("block_public_policy") if attr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' sets block_public_policy explicitly to false", resourceBlock.FullName())). - WithAttribute(attr), - ) + set.AddResult(). + WithDescription("Resource '%s' sets block_public_policy explicitly to false", resourceBlock.FullName()). + WithAttribute(attr) } }, }) diff --git a/internal/app/tfsec/rules/aws/s3/enable_bucket_encryption_rule.go b/internal/app/tfsec/rules/aws/s3/enable_bucket_encryption_rule.go index f8dbc191db..bbac13e1a4 100644 --- a/internal/app/tfsec/rules/aws/s3/enable_bucket_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/s3/enable_bucket_encryption_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -60,36 +58,28 @@ resource "aws_s3_bucket" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { if resourceBlock.MissingChild("server_side_encryption_configuration") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted S3 bucket (missing server_side_encryption_configuration block).", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted S3 bucket (missing server_side_encryption_configuration block).", resourceBlock.FullName()) return } encryptionBlock := resourceBlock.GetBlock("server_side_encryption_configuration") if encryptionBlock.MissingChild("rule") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted S3 bucket (missing rule block).", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted S3 bucket (missing rule block).", resourceBlock.FullName()) return } ruleBlock := encryptionBlock.GetBlock("rule") if ruleBlock.MissingChild("apply_server_side_encryption_by_default") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted S3 bucket (missing apply_server_side_encryption_by_default block).", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted S3 bucket (missing apply_server_side_encryption_by_default block).", resourceBlock.FullName()).WithBlock(ruleBlock) return } applyBlock := ruleBlock.GetBlock("apply_server_side_encryption_by_default") - if sseAttr := applyBlock.GetAttribute("sse_algorithm"); sseAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted S3 bucket (missing sse_algorithm attribute).", resourceBlock.FullName())), - ) + if sseAttr := applyBlock.GetAttribute("sse_algorithm"); sseAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted S3 bucket (missing sse_algorithm attribute).", resourceBlock.FullName()).WithBlock(applyBlock) } }, diff --git a/internal/app/tfsec/rules/aws/s3/enable_bucket_logging_rule.go b/internal/app/tfsec/rules/aws/s3/enable_bucket_logging_rule.go index 96543ec0c5..10488377e8 100644 --- a/internal/app/tfsec/rules/aws/s3/enable_bucket_logging_rule.go +++ b/internal/app/tfsec/rules/aws/s3/enable_bucket_logging_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -51,14 +49,13 @@ resource "aws_s3_bucket" "good_example" { RequiredLabels: []string{"aws_s3_bucket"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if loggingBlock := resourceBlock.GetBlock("logging"); loggingBlock == nil { - if resourceBlock.GetAttribute("acl") != nil && resourceBlock.GetAttribute("acl").Equals("log-delivery-write") { + + if resourceBlock.MissingChild("logging") { + if resourceBlock.GetAttribute("acl").IsNotNil() && resourceBlock.GetAttribute("acl").Equals("log-delivery-write") { return } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have logging enabled.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have logging enabled.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/aws/s3/enable_versioning_rule.go b/internal/app/tfsec/rules/aws/s3/enable_versioning_rule.go index af7d1d3fd6..739c475000 100644 --- a/internal/app/tfsec/rules/aws/s3/enable_versioning_rule.go +++ b/internal/app/tfsec/rules/aws/s3/enable_versioning_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -56,21 +54,16 @@ resource "aws_s3_bucket" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("versioning") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have versioning enabled", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have versioning enabled", resourceBlock.FullName()) return } versioningBlock := resourceBlock.GetBlock("versioning") if versioningBlock.HasChild("enabled") && versioningBlock.GetAttribute("enabled").IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has versioning block but is disabled", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has versioning block but is disabled", resourceBlock.FullName()).WithBlock(versioningBlock) } - }, }) } diff --git a/internal/app/tfsec/rules/aws/s3/ignore_public_acls_rule.go b/internal/app/tfsec/rules/aws/s3/ignore_public_acls_rule.go index 8badf22fef..a3703520bd 100644 --- a/internal/app/tfsec/rules/aws/s3/ignore_public_acls_rule.go +++ b/internal/app/tfsec/rules/aws/s3/ignore_public_acls_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -59,20 +57,16 @@ resource "aws_s3_bucket_public_access_block" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("ignore_public_acls") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not specify ignore_public_acls, defaults to false", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not specify ignore_public_acls, defaults to false", resourceBlock.FullName()) return } - attr := resourceBlock.GetAttribute("ignore_public_acls") - if attr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' sets ignore_public_acls explicitly to false", resourceBlock.FullName())). - WithAttribute(attr), - ) + ignorePublicAclsAttr := resourceBlock.GetAttribute("ignore_public_acls") + if ignorePublicAclsAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' sets ignore_public_acls explicitly to false", resourceBlock.FullName()). + WithAttribute(ignorePublicAclsAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule.go b/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule.go index 444b9bbd3a..047e504659 100644 --- a/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule.go +++ b/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,19 +51,18 @@ resource "aws_s3_bucket" "good_example" { RequiredLabels: []string{"aws_s3_bucket"}, DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("acl"); attr != nil { - if attr.IsAny("public-read", "public-read-write", "website") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has an ACL which allows public access.", resourceBlock.FullName())). - WithAttribute(attr), - ) - } else if attr.Equals("authenticated-read") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has an ACL which allows access to any authenticated AWS user, not just users within the target account.", resourceBlock.FullName())), - ) - } + if resourceBlock.MissingChild("acl") { + return + } + + aclAttr := resourceBlock.GetAttribute("acl") + if aclAttr.IsAny("public-read", "public-read-write", "website") { + set.AddResult(). + WithDescription("Resource '%s' has an ACL which allows public access.", resourceBlock.FullName()). + WithAttribute(aclAttr) + } else if aclAttr.Equals("authenticated-read") { + set.AddResult(). + WithDescription("Resource '%s' has an ACL which allows access to any authenticated AWS user, not just users within the target account.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule_test.go b/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule_test.go index 6b8dbf32a5..370201f2be 100644 --- a/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule_test.go +++ b/internal/app/tfsec/rules/aws/s3/no_public_access_with_acl_rule_test.go @@ -46,6 +46,14 @@ resource "aws_s3_bucket" "my-bucket" { source: ` resource "aws_s3_bucket" "my-bucket" { acl = "private" +}`, + mustExcludeResultCode: expectedCode, + }, + { + name: "check aws_s3_bucket with acl not set", + source: ` +resource "aws_s3_bucket" "my-bucket" { + }`, mustExcludeResultCode: expectedCode, }, diff --git a/internal/app/tfsec/rules/aws/s3/no_public_buckets_rule.go b/internal/app/tfsec/rules/aws/s3/no_public_buckets_rule.go index dad4864573..191792028b 100644 --- a/internal/app/tfsec/rules/aws/s3/no_public_buckets_rule.go +++ b/internal/app/tfsec/rules/aws/s3/no_public_buckets_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,20 +56,16 @@ resource "aws_s3_bucket_public_access_block" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("restrict_public_buckets") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not specify restrict_public_buckets, defaults to false", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not specify restrict_public_buckets, defaults to false", resourceBlock.FullName()) return } - attr := resourceBlock.GetAttribute("restrict_public_buckets") - if attr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' sets restrict_public_buckets explicitly to false", resourceBlock.FullName())). - WithAttribute(attr), - ) + restrictPublicAttr := resourceBlock.GetAttribute("restrict_public_buckets") + if restrictPublicAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' sets restrict_public_buckets explicitly to false", resourceBlock.FullName()). + WithAttribute(restrictPublicAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/s3/specify_public_access_block_rule.go b/internal/app/tfsec/rules/aws/s3/specify_public_access_block_rule.go index dcdab3ce0d..db2dc3b3f3 100644 --- a/internal/app/tfsec/rules/aws/s3/specify_public_access_block_rule.go +++ b/internal/app/tfsec/rules/aws/s3/specify_public_access_block_rule.go @@ -1,8 +1,6 @@ package s3 import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -52,12 +50,11 @@ resource "aws_s3_bucket_public_access_block" "example" { RequiredLabels: []string{"aws_s3_bucket"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) { + blocks, err := ctx.GetReferencingResources(resourceBlock, "aws_s3_bucket_public_access_block", "bucket") if err != nil || len(blocks) == 0 { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource %s has no associated aws_s3_bucket_public_access_block.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource %s has no associated aws_s3_bucket_public_access_block.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/aws/sns/enable_topic_encryption_rule.go b/internal/app/tfsec/rules/aws/sns/enable_topic_encryption_rule.go index 0f58296d34..e1dbff0ae6 100644 --- a/internal/app/tfsec/rules/aws/sns/enable_topic_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/sns/enable_topic_encryption_rule.go @@ -1,8 +1,6 @@ package sns import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,18 +51,14 @@ resource "aws_sns_topic" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) { kmsKeyIDAttr := resourceBlock.GetAttribute("kms_master_key_id") - if kmsKeyIDAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted SNS topic.", resourceBlock.FullName())), - ) + if kmsKeyIDAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted SNS topic.", resourceBlock.FullName()) return } else if kmsKeyIDAttr.Type() == cty.String && kmsKeyIDAttr.Value().AsString() == "" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted SNS topic.", resourceBlock.FullName())). - WithAttribute(kmsKeyIDAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted SNS topic.", resourceBlock.FullName()). + WithAttribute(kmsKeyIDAttr) return } @@ -76,12 +70,10 @@ resource "aws_sns_topic" "good_example" { } keyIdAttr := kmsData.GetAttribute("key_id") - if keyIdAttr != nil && keyIdAttr.Equals("alias/aws/sns") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' explicitly uses the default CMK", resourceBlock.FullName())). - WithAttribute(kmsKeyIDAttr), - ) + if keyIdAttr.IsNotNil() && keyIdAttr.Equals("alias/aws/sns") { + set.AddResult(). + WithDescription("Resource '%s' explicitly uses the default CMK", resourceBlock.FullName()). + WithAttribute(kmsKeyIDAttr) } } diff --git a/internal/app/tfsec/rules/aws/sqs/enable_queue_encryption_rule.go b/internal/app/tfsec/rules/aws/sqs/enable_queue_encryption_rule.go index 67d8a7a752..8c6f6119be 100644 --- a/internal/app/tfsec/rules/aws/sqs/enable_queue_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/sqs/enable_queue_encryption_rule.go @@ -1,8 +1,6 @@ package sqs import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -53,18 +49,14 @@ resource "aws_sqs_queue" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, context *hclcontext.Context) { kmsKeyIDAttr := resourceBlock.GetAttribute("kms_master_key_id") - if kmsKeyIDAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted SQS queue.", resourceBlock.FullName())), - ) + if kmsKeyIDAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted SQS queue.", resourceBlock.FullName()) - } else if kmsKeyIDAttr.Type() == cty.String && kmsKeyIDAttr.Value().AsString() == "" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines an unencrypted SQS queue.", resourceBlock.FullName())). - WithAttribute(kmsKeyIDAttr), - ) + } else if kmsKeyIDAttr.IsEmpty() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted SQS queue.", resourceBlock.FullName()). + WithAttribute(kmsKeyIDAttr) } }, diff --git a/internal/app/tfsec/rules/aws/sqs/no_wildcards_in_policy_documents_rule.go b/internal/app/tfsec/rules/aws/sqs/no_wildcards_in_policy_documents_rule.go index d74a310007..7ec4431b0b 100644 --- a/internal/app/tfsec/rules/aws/sqs/no_wildcards_in_policy_documents_rule.go +++ b/internal/app/tfsec/rules/aws/sqs/no_wildcards_in_policy_documents_rule.go @@ -2,7 +2,6 @@ package sqs import ( "encoding/json" - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -16,8 +15,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -80,15 +77,12 @@ POLICY DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.MissingChild("policy") { - return - } - - if resourceBlock.GetAttribute("policy").Value().Type() != cty.String { + if resourceBlock.MissingChild("policy") || !resourceBlock.GetAttribute("policy").IsString() { return } - rawJSON := []byte(resourceBlock.GetAttribute("policy").Value().AsString()) + policyAttr := resourceBlock.GetAttribute("policy") + rawJSON := []byte(policyAttr.Value().AsString()) var policy struct { Statement []struct { Effect string `json:"Effect"` @@ -99,10 +93,8 @@ POLICY if err := json.Unmarshal(rawJSON, &policy); err == nil { for _, statement := range policy.Statement { if strings.ToLower(statement.Effect) == "allow" && (statement.Action == "*" || statement.Action == "sqs:*") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("SQS policy '%s' has a wildcard action specified.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("SQS policy '%s' has a wildcard action specified.", resourceBlock.FullName()).WithAttribute(policyAttr) } } } diff --git a/internal/app/tfsec/rules/aws/ssm/secret_use_customer_key_rule.go b/internal/app/tfsec/rules/aws/ssm/secret_use_customer_key_rule.go index 243a2079e0..8ad1cc3495 100644 --- a/internal/app/tfsec/rules/aws/ssm/secret_use_customer_key_rule.go +++ b/internal/app/tfsec/rules/aws/ssm/secret_use_customer_key_rule.go @@ -1,8 +1,6 @@ package ssm import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -56,10 +54,8 @@ resource "aws_secretsmanager_secret" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) { if resourceBlock.MissingChild("kms_key_id") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not use CMK", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not use CMK", resourceBlock.FullName()) return } @@ -70,12 +66,10 @@ resource "aws_secretsmanager_secret" "good_example" { return } keyIdAttr := kmsData.GetAttribute("key_id") - if keyIdAttr != nil && keyIdAttr.Equals("alias/aws/secretsmanager") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' explicitly uses the default CMK", resourceBlock.FullName())). - WithAttribute(kmsKeyAttr), - ) + if keyIdAttr.IsNotNil() && keyIdAttr.Equals("alias/aws/secretsmanager") { + set.AddResult(). + WithDescription("Resource '%s' explicitly uses the default CMK", resourceBlock.FullName()). + WithAttribute(kmsKeyAttr) } } diff --git a/internal/app/tfsec/rules/aws/vpc/add_decription_to_security_group_rule.go b/internal/app/tfsec/rules/aws/vpc/add_decription_to_security_group_rule.go index 75c558b213..f5cb71f6a7 100644 --- a/internal/app/tfsec/rules/aws/vpc/add_decription_to_security_group_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/add_decription_to_security_group_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -70,20 +68,16 @@ resource "aws_security_group" "good_example" { DefaultSeverity: severity.Low, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("description") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should include a description for auditing purposes.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should include a description for auditing purposes.", resourceBlock.FullName()) return } descriptionAttr := resourceBlock.GetAttribute("description") if descriptionAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should include a non-empty description for auditing purposes.", resourceBlock.FullName())). - WithAttribute(descriptionAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' should include a non-empty description for auditing purposes.", resourceBlock.FullName()). + WithAttribute(descriptionAttr) } }, }) diff --git a/internal/app/tfsec/rules/aws/vpc/no_default_vpc_rule.go b/internal/app/tfsec/rules/aws/vpc/no_default_vpc_rule.go index dcec67078c..8013598074 100644 --- a/internal/app/tfsec/rules/aws/vpc/no_default_vpc_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/no_default_vpc_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -49,10 +47,8 @@ resource "aws_default_vpc" "default" { RequiredLabels: []string{"aws_default_vpc"}, DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should not exist", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should not exist", resourceBlock.FullName()) }, }) } diff --git a/internal/app/tfsec/rules/aws/vpc/no_excessive_port_access_rule.go b/internal/app/tfsec/rules/aws/vpc/no_excessive_port_access_rule.go index f62dc83510..e50f419386 100644 --- a/internal/app/tfsec/rules/aws/vpc/no_excessive_port_access_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/no_excessive_port_access_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,7 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - "github.com/zclconf/go-cty/cty" ) func init() { @@ -63,35 +60,27 @@ resource "aws_network_acl_rule" "good_example" { actionAttr := resourceBlock.GetAttribute("rule_action") protoAttr := resourceBlock.GetAttribute("protocol") - if egressAttr != nil && egressAttr.IsTrue() { - return - } - - if actionAttr == nil || actionAttr.Type() != cty.String { + if egressAttr.IsNotNil() && egressAttr.IsTrue() { return } - if actionAttr.Value().AsString() != "allow" { + if actionAttr.IsNil() || !actionAttr.IsString() || actionAttr.NotEqual("allow") { return } - if cidrBlockAttr := resourceBlock.GetAttribute("cidr_block"); cidrBlockAttr != nil { + if cidrBlockAttr := resourceBlock.GetAttribute("cidr_block"); cidrBlockAttr.IsNotNil() { if protoAttr.Value().AsString() == "all" || protoAttr.Value().AsString() == "-1" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open ingress Network ACL rule with ALL ports open.", resourceBlock.FullName())). - WithAttribute(cidrBlockAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open ingress Network ACL rule with ALL ports open.", resourceBlock.FullName()). + WithAttribute(cidrBlockAttr) } } - if ipv6CidrBlockAttr := resourceBlock.GetAttribute("ipv6_cidr_block"); ipv6CidrBlockAttr != nil { + if ipv6CidrBlockAttr := resourceBlock.GetAttribute("ipv6_cidr_block"); ipv6CidrBlockAttr.IsNotNil() { if protoAttr.Value().AsString() == "all" || protoAttr.Value().AsString() == "-1" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open ingress Network ACL rule with ALL ports open.", resourceBlock.FullName())). - WithAttribute(ipv6CidrBlockAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open ingress Network ACL rule with ALL ports open.", resourceBlock.FullName()). + WithAttribute(ipv6CidrBlockAttr) } } diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go index 39d8d70103..df2fe32650 100644 --- a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sg_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -55,25 +53,21 @@ resource "aws_security_group" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { for _, directionBlock := range resourceBlock.GetBlocks("egress") { - if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil { + if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() { if cidr.IsOpen(cidrBlocksAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open egress security group.", resourceBlock.FullName())). - WithAttribute(cidrBlocksAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open egress security group.", resourceBlock.FullName()). + WithAttribute(cidrBlocksAttr) } } - if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr != nil { + if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr.IsNotNil() { if cidr.IsOpen(cidrBlocksAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open egress security group.", resourceBlock.FullName())). - WithAttribute(cidrBlocksAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open egress security group.", resourceBlock.FullName()). + WithAttribute(cidrBlocksAttr) } } } diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go index 08a5448c9c..16ed550734 100644 --- a/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/no_public_egress_sgr_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -55,33 +51,25 @@ resource "aws_security_group_rule" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { typeAttr := resourceBlock.GetAttribute("type") - if typeAttr == nil || typeAttr.Type() != cty.String { - return - } - - if typeAttr.Value().AsString() != "egress" { + if typeAttr.IsNil() || !typeAttr.IsString() || typeAttr.NotEqual("egress") { return } - if cidrBlocksAttr := resourceBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil { + if cidrBlocksAttr := resourceBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() { if cidr.IsOpen(cidrBlocksAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open egress security group rule.", resourceBlock.FullName())). - WithAttribute(cidrBlocksAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open egress security group rule.", resourceBlock.FullName()). + WithAttribute(cidrBlocksAttr) } } - if ipv6CidrBlocksAttr := resourceBlock.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr != nil { + if ipv6CidrBlocksAttr := resourceBlock.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr.IsNotNil() { if cidr.IsOpen(ipv6CidrBlocksAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open egress security group rule.", resourceBlock.FullName())). - WithAttribute(ipv6CidrBlocksAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open egress security group rule.", resourceBlock.FullName()). + WithAttribute(ipv6CidrBlocksAttr) } } }, diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go index 31f67012be..b5ccbba09c 100644 --- a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -66,40 +64,36 @@ resource "aws_network_acl_rule" "good_example" { actionAttr := resourceBlock.GetAttribute("rule_action") protoAttr := resourceBlock.GetAttribute("protocol") - if egressAttr != nil && egressAttr.IsTrue() { + if egressAttr.IsNotNil() && egressAttr.IsTrue() { return } - if actionAttr != nil && !actionAttr.Equals("allow") { + if actionAttr.IsNotNil() && actionAttr.NotEqual("allow") { return } - if cidrBlockAttr := resourceBlock.GetAttribute("cidr_block"); cidrBlockAttr != nil { + if cidrBlockAttr := resourceBlock.GetAttribute("cidr_block"); cidrBlockAttr.IsNotNil() { if cidr.IsOpen(cidrBlockAttr) { if protoAttr.Value().AsString() == "all" || protoAttr.Value().AsString() == "-1" { return } else { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a Network ACL rule that allows specific ingress ports from anywhere.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a Network ACL rule that allows specific ingress ports from anywhere.", resourceBlock.FullName()) } } } - if ipv6CidrBlockAttr := resourceBlock.GetAttribute("ipv6_cidr_block"); ipv6CidrBlockAttr != nil { + if ipv6CidrBlockAttr := resourceBlock.GetAttribute("ipv6_cidr_block"); ipv6CidrBlockAttr.IsNotNil() { if cidr.IsOpen(ipv6CidrBlockAttr) { if protoAttr.Value().AsString() == "all" || protoAttr.Value().AsString() == "-1" { return } else { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a Network ACL rule that allows specific ingress ports from anywhere.", resourceBlock.FullName())). - WithAttribute(ipv6CidrBlockAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a Network ACL rule that allows specific ingress ports from anywhere.", resourceBlock.FullName()). + WithAttribute(ipv6CidrBlockAttr) } } diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go index af62e91fc3..15e6039a11 100644 --- a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sg_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -52,27 +50,23 @@ resource "aws_security_group" "good_example" { RequiredTypes: []string{"resource"}, RequiredLabels: []string{"aws_security_group"}, DefaultSeverity: severity.Critical, - CheckFunc: func(resultSet result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { for _, directionBlock := range resourceBlock.GetBlocks("ingress") { - if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil { + if cidrBlocksAttr := directionBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() { if cidr.IsOpen(cidrBlocksAttr) { - resultSet.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open ingress security group.", resourceBlock.FullName())). - WithAttribute(cidrBlocksAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open ingress security group.", resourceBlock.FullName()). + WithAttribute(cidrBlocksAttr) } } - if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr != nil { + if cidrBlocksAttr := directionBlock.GetAttribute("ipv6_cidr_blocks"); cidrBlocksAttr.IsNotNil() { if cidr.IsOpen(cidrBlocksAttr) { - resultSet.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open ingress security group.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open ingress security group.", resourceBlock.FullName()) } } } diff --git a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go index 37a47d5c1c..17a40f7808 100644 --- a/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/no_public_ingress_sgr_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -16,8 +14,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -56,31 +52,23 @@ resource "aws_security_group_rule" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { typeAttr := resourceBlock.GetAttribute("type") - if typeAttr == nil || typeAttr.Type() != cty.String { - return - } - - if typeAttr.Value().AsString() != "ingress" { + if typeAttr.IsNil() || !typeAttr.IsString() || typeAttr.NotEqual("ingress") { return } - if cidrBlocksAttr := resourceBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr != nil { + if cidrBlocksAttr := resourceBlock.GetAttribute("cidr_blocks"); cidrBlocksAttr.IsNotNil() { if cidr.IsOpen(cidrBlocksAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open ingress security group rule.", resourceBlock.FullName())). - WithAttribute(cidrBlocksAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open ingress security group rule.", resourceBlock.FullName()). + WithAttribute(cidrBlocksAttr) } } - if ipv6CidrBlocksAttr := resourceBlock.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr != nil { + if ipv6CidrBlocksAttr := resourceBlock.GetAttribute("ipv6_cidr_blocks"); ipv6CidrBlocksAttr.IsNotNil() { if cidr.IsOpen(ipv6CidrBlocksAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open ingress security group rule.", resourceBlock.FullName())). - WithAttribute(ipv6CidrBlocksAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open ingress security group rule.", resourceBlock.FullName()). + WithAttribute(ipv6CidrBlocksAttr) } } diff --git a/internal/app/tfsec/rules/aws/vpc/use_secure_tls_policy_rule.go b/internal/app/tfsec/rules/aws/vpc/use_secure_tls_policy_rule.go index bf9e70f850..96401076e0 100644 --- a/internal/app/tfsec/rules/aws/vpc/use_secure_tls_policy_rule.go +++ b/internal/app/tfsec/rules/aws/vpc/use_secure_tls_policy_rule.go @@ -1,8 +1,6 @@ package vpc import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) var outdatedSSLPolicies = []string{ @@ -60,14 +56,12 @@ resource "aws_alb_listener" "good_example" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if sslPolicyAttr := resourceBlock.GetAttribute("ssl_policy"); sslPolicyAttr != nil && sslPolicyAttr.Type() == cty.String { + if sslPolicyAttr := resourceBlock.GetAttribute("ssl_policy"); sslPolicyAttr.IsString() { for _, policy := range outdatedSSLPolicies { - if policy == sslPolicyAttr.Value().AsString() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is using an outdated SSL policy.", resourceBlock.FullName())). - WithAttribute(sslPolicyAttr), - ) + if sslPolicyAttr.Equals(policy) { + set.AddResult(). + WithDescription("Resource '%s' is using an outdated SSL policy.", resourceBlock.FullName()). + WithAttribute(sslPolicyAttr) } } } diff --git a/internal/app/tfsec/rules/aws/workspace/enable_disk_encryption_rule.go b/internal/app/tfsec/rules/aws/workspace/enable_disk_encryption_rule.go index 2e1d4202ba..c123840b0b 100644 --- a/internal/app/tfsec/rules/aws/workspace/enable_disk_encryption_rule.go +++ b/internal/app/tfsec/rules/aws/workspace/enable_disk_encryption_rule.go @@ -1,8 +1,6 @@ package workspace import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -73,34 +71,28 @@ resource "aws_workspaces_workspace" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("root_volume_encryption_enabled") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have root volume encryption enables", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have root volume encryption enabled", resourceBlock.FullName()) } else { - attr := resourceBlock.GetAttribute("root_volume_encryption_enabled") - if attr != nil && attr.IsFalse() { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has the root volume encryption set to false", resourceBlock.FullName())). - WithAttribute(attr), - ) + rootVolEncAttr := resourceBlock.GetAttribute("root_volume_encryption_enabled") + if rootVolEncAttr.IsNotNil() && rootVolEncAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' has the root volume encryption set to false", resourceBlock.FullName()). + WithAttribute(rootVolEncAttr) } } if resourceBlock.MissingChild("user_volume_encryption_enabled") { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have user volume encryption enables", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have user volume encryption enabled", resourceBlock.FullName()) return } - attr := resourceBlock.GetAttribute("user_volume_encryption_enabled") - if attr != nil && attr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has the user volume encryption set to false", resourceBlock.FullName())). - WithAttribute(attr), - ) + userVolEncAttr := resourceBlock.GetAttribute("user_volume_encryption_enabled") + if userVolEncAttr.IsNotNil() && userVolEncAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' has the user volume encryption set to false", resourceBlock.FullName()). + WithAttribute(userVolEncAttr) } }, diff --git a/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go b/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go index 5a2a264cf7..1cff5a1890 100644 --- a/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go +++ b/internal/app/tfsec/rules/azure/appservice/enforce_https_rule.go @@ -1,8 +1,6 @@ package appservice import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -65,19 +63,15 @@ resource "azurerm_function_app" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("https_only") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have https_only set to true, the default is false.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have https_only set to true, the default is false.", resourceBlock.FullName()) return } httpsOnlyAttr := resourceBlock.GetAttribute("https_only") if httpsOnlyAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have https_only set to true, the default is false.", resourceBlock.FullName())). - WithAttribute(httpsOnlyAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' should have https_only set to true, the default is false.", resourceBlock.FullName()). + WithAttribute(httpsOnlyAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go b/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go index 1d96fcda67..d5b0df1396 100644 --- a/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go +++ b/internal/app/tfsec/rules/azure/compute/disable_password_authentication_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -113,14 +111,8 @@ resource "azurerm_virtual_machine" "good_example" { passwordAuthAttr := workingBlock.GetAttribute("disable_password_authentication") if passwordAuthAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' has password authentication enabled.", - resourceBlock.FullName(), - )). - WithAttribute(passwordAuthAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has password authentication enabled.", resourceBlock.FullName()).WithAttribute(passwordAuthAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go b/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go index 61afc5ac2b..2b91a3801f 100644 --- a/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go +++ b/internal/app/tfsec/rules/azure/compute/enable_disk_encryption_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -52,20 +50,19 @@ resource "azurerm_managed_disk" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { encryptionSettingsBlock := resourceBlock.GetBlock("encryption_settings") - if encryptionSettingsBlock == nil { + if encryptionSettingsBlock.IsNil() { return // encryption is by default now, so this is fine } + if encryptionSettingsBlock.MissingChild("enabled") { + return + } + enabledAttr := encryptionSettingsBlock.GetAttribute("enabled") - if enabledAttr != nil && enabledAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' defines an unencrypted managed disk.", - resourceBlock.FullName(), - )). - WithAttribute(enabledAttr), - ) + if enabledAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted managed disk.", resourceBlock.FullName()). + WithAttribute(enabledAttr) } }, diff --git a/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go b/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go index d5c39b94f9..404e55b1e8 100644 --- a/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go +++ b/internal/app/tfsec/rules/azure/compute/no_secrets_in_custom_data_rule.go @@ -2,7 +2,6 @@ package compute import ( "encoding/base64" - "fmt" "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -63,10 +62,10 @@ EOF if resourceBlock.TypeLabel() == "azurerm_virtual_machine" { for _, str := range customDataAttr.ValueAsStrings() { - if checkResult := checkStringForSensitive(str, resourceBlock); checkResult != nil { - checkResult. + if checkStringForSensitive(str) { + set.AddResult(). + WithDescription("Resource '%s' has custom_data with sensitive data.", resourceBlock.FullName()). WithAttribute(customDataAttr) - set.Add(checkResult) } } } else if customDataAttr.IsResolvable() && customDataAttr.IsString() { @@ -75,10 +74,10 @@ EOF debug.Log("could not decode the base64 string in the terraform, trying with the string verbatim") encoded = []byte(customDataAttr.Value().AsString()) } - if checkResult := checkStringForSensitive(string(encoded), resourceBlock); checkResult != nil { - checkResult. + if checkStringForSensitive(string(encoded)) { + set.AddResult(). + WithDescription("Resource '%s' has custom_data with sensitive data.", resourceBlock.FullName()). WithAttribute(customDataAttr) - set.Add(checkResult) } } @@ -86,10 +85,7 @@ EOF }) } -func checkStringForSensitive(stringToCheck string, resourceBlock block.Block) *result.Result { - if scanResult := squealer.NewStringScanner().Scan(stringToCheck); scanResult.TransgressionFound { - return result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has custom_data with sensitive data.", resourceBlock.FullName())) - } - return nil +func checkStringForSensitive(stringToCheck string) bool { + scanResult := squealer.NewStringScanner().Scan(stringToCheck) + return scanResult.TransgressionFound } diff --git a/internal/app/tfsec/rules/azure/compute/ssh_authentication_rule.go b/internal/app/tfsec/rules/azure/compute/ssh_authentication_rule.go index 721a2ae38c..df68ea0cc6 100644 --- a/internal/app/tfsec/rules/azure/compute/ssh_authentication_rule.go +++ b/internal/app/tfsec/rules/azure/compute/ssh_authentication_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -54,17 +50,16 @@ resource "azurerm_virtual_machine" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if linuxConfigBlock := resourceBlock.GetBlock("os_profile_linux_config"); linuxConfigBlock != nil { + if linuxConfigBlock := resourceBlock.GetBlock("os_profile_linux_config"); linuxConfigBlock.IsNotNil() { + if linuxConfigBlock.MissingChild("disable_password_authentication") { + set.AddResult().WithDescription("Resource '%s' missing required attribute in os_profile_linux_config", resourceBlock.FullName()).WithBlock(linuxConfigBlock) + } + passwordAuthDisabledAttr := linuxConfigBlock.GetAttribute("disable_password_authentication") - if passwordAuthDisabledAttr != nil && passwordAuthDisabledAttr.Type() == cty.Bool && passwordAuthDisabledAttr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' has password authentication enabled. Use SSH keys instead.", - resourceBlock.FullName(), - )). - WithAttribute(passwordAuthDisabledAttr), - ) + if passwordAuthDisabledAttr.IsNotNil() && passwordAuthDisabledAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' has password authentication enabled. Use SSH keys instead.", resourceBlock.FullName()). + WithAttribute(passwordAuthDisabledAttr) } } diff --git a/internal/app/tfsec/rules/azure/container/configured_network_policy_rule.go b/internal/app/tfsec/rules/azure/container/configured_network_policy_rule.go index 25483b54b4..036cc0c41d 100644 --- a/internal/app/tfsec/rules/azure/container/configured_network_policy_rule.go +++ b/internal/app/tfsec/rules/azure/container/configured_network_policy_rule.go @@ -1,8 +1,6 @@ package container import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,12 +51,10 @@ resource "azurerm_kubernetes_cluster" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if networkProfileBlock := resourceBlock.GetBlock("network_profile"); networkProfileBlock != nil { - if networkProfileBlock.GetAttribute("network_policy") == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' do not have network_policy define. network_policy should be defined to have opportunity allow or block traffic to pods", resourceBlock.FullName())), - ) + if networkProfileBlock := resourceBlock.GetBlock("network_profile"); networkProfileBlock.IsNotNil() { + if networkProfileBlock.MissingChild("network_policy") { + set.AddResult(). + WithDescription("Resource '%s' do not have network_policy define. network_policy should be defined to have opportunity allow or block traffic to pods", resourceBlock.FullName()) } } diff --git a/internal/app/tfsec/rules/azure/container/limit_authorized_ips_rule.go b/internal/app/tfsec/rules/azure/container/limit_authorized_ips_rule.go index 9d6b636520..1f43d0f4e5 100644 --- a/internal/app/tfsec/rules/azure/container/limit_authorized_ips_rule.go +++ b/internal/app/tfsec/rules/azure/container/limit_authorized_ips_rule.go @@ -1,8 +1,6 @@ package container import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,14 +51,12 @@ resource "azurerm_kubernetes_cluster" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if (resourceBlock.MissingChild("api_server_authorized_ip_ranges") || - resourceBlock.GetAttribute("api_server_authorized_ip_ranges").Value().LengthInt() < 1) && + resourceBlock.GetAttribute("api_server_authorized_ip_ranges").IsEmpty()) && (resourceBlock.MissingChild("private_cluster_enabled") || resourceBlock.GetAttribute("private_cluster_enabled").IsFalse()) { { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defined without limited set of IP address ranges to the API server.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defined without limited set of IP address ranges to the API server.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/azure/container/logging_rule.go b/internal/app/tfsec/rules/azure/container/logging_rule.go index 7fa9caf066..80573771a0 100644 --- a/internal/app/tfsec/rules/azure/container/logging_rule.go +++ b/internal/app/tfsec/rules/azure/container/logging_rule.go @@ -1,8 +1,6 @@ package container import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,7 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - "github.com/zclconf/go-cty/cty" ) func init() { @@ -55,40 +52,18 @@ resource "azurerm_kubernetes_cluster" "good_example" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - addonProfileBlock := resourceBlock.GetBlock("addon_profile") - if addonProfileBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' AKS logging to Azure Monitoring is not configured (missing addon_profile).", resourceBlock.FullName())), - ) - return - } - - omsAgentBlock := addonProfileBlock.GetBlock("oms_agent") - if omsAgentBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' AKS logging to Azure Monitoring is not configured (missing oms_agent).", resourceBlock.FullName())), - ) + if resourceBlock.MissingNestedChild("addon_profile.oms_agent") { + set.AddResult(). + WithDescription("Resource '%s' AKS logging to Azure Monitoring is not configured.", resourceBlock.FullName()) return } - enabledAttr := omsAgentBlock.GetAttribute("enabled") - if enabledAttr == nil || (enabledAttr.Type() == cty.Bool && enabledAttr.Value().False()) { - - res := result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' AKS logging to Azure Monitoring is not configured (oms_agent disabled).", - resourceBlock.FullName(), - )) - - if enabledAttr != nil { - res.WithAttribute(enabledAttr) - } - - set.Add(res) + enabledAttr := resourceBlock.GetNestedAttribute("addon_profile.oms_agent.enabled") + if enabledAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' AKS logging to Azure Monitoring is not configured (oms_agent disabled).", resourceBlock.FullName()). + WithAttribute(enabledAttr) } - }, }) } diff --git a/internal/app/tfsec/rules/azure/container/use_rbac_permissions_rule.go b/internal/app/tfsec/rules/azure/container/use_rbac_permissions_rule.go index 9760ce282d..b761fca596 100644 --- a/internal/app/tfsec/rules/azure/container/use_rbac_permissions_rule.go +++ b/internal/app/tfsec/rules/azure/container/use_rbac_permissions_rule.go @@ -1,8 +1,6 @@ package container import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,7 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - "github.com/zclconf/go-cty/cty" ) func init() { @@ -55,25 +52,17 @@ resource "azurerm_kubernetes_cluster" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - rbacBlock := resourceBlock.GetBlock("role_based_access_control") - if rbacBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines without RBAC", resourceBlock.FullName())), - ) + if resourceBlock.MissingChild("role_based_access_control") { + set.AddResult(). + WithDescription("Resource '%s' defines without RBAC", resourceBlock.FullName()) return } - enabledAttr := rbacBlock.GetAttribute("enabled") - if enabledAttr != nil && enabledAttr.Type() == cty.Bool && enabledAttr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' RBAC disabled.", - resourceBlock.FullName(), - )). - WithAttribute(enabledAttr), - ) + enabledAttr := resourceBlock.GetNestedAttribute("role_based_access_control.enabled") + if enabledAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' RBAC disabled.", resourceBlock.FullName()). + WithAttribute(enabledAttr) } }, diff --git a/internal/app/tfsec/rules/azure/database/enable_audit_rule.go b/internal/app/tfsec/rules/azure/database/enable_audit_rule.go index d0afb95565..8f58c83d3d 100644 --- a/internal/app/tfsec/rules/azure/database/enable_audit_rule.go +++ b/internal/app/tfsec/rules/azure/database/enable_audit_rule.go @@ -1,8 +1,6 @@ package database import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -68,7 +66,7 @@ resource "azurerm_sql_server" "good_example" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) { - if !resourceBlock.MissingChild("extended_auditing_policy") { + if resourceBlock.HasChild("extended_auditing_policy") { return } @@ -82,10 +80,8 @@ resource "azurerm_sql_server" "good_example" { return } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have an extended audit policy configured.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have an extended audit policy configured.", resourceBlock.FullName()) }, }) diff --git a/internal/app/tfsec/rules/azure/database/enable_ssl_enforcement_rule.go b/internal/app/tfsec/rules/azure/database/enable_ssl_enforcement_rule.go index 38c92ab48d..f321199f3a 100644 --- a/internal/app/tfsec/rules/azure/database/enable_ssl_enforcement_rule.go +++ b/internal/app/tfsec/rules/azure/database/enable_ssl_enforcement_rule.go @@ -1,8 +1,6 @@ package database import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,20 +55,16 @@ resource "azurerm_postgresql_server" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("ssl_enforcement_enabled") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing the required ssl_enforcement_enabled attribute", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is missing the required ssl_enforcement_enabled attribute", resourceBlock.FullName()) return } sslEnforceAttr := resourceBlock.GetAttribute("ssl_enforcement_enabled") if sslEnforceAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has ssl_enforcement_enabled disabled", resourceBlock.FullName())). - WithAttribute(sslEnforceAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has ssl_enforcement_enabled disabled", resourceBlock.FullName()). + WithAttribute(sslEnforceAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/database/no_public_access_rule.go b/internal/app/tfsec/rules/azure/database/no_public_access_rule.go index 06001d6c2f..333e7a4218 100644 --- a/internal/app/tfsec/rules/azure/database/no_public_access_rule.go +++ b/internal/app/tfsec/rules/azure/database/no_public_access_rule.go @@ -1,8 +1,6 @@ package database import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,20 +55,16 @@ resource "azurerm_postgresql_server" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("public_network_access_enabled") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has default public network access of enabled", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has default public network access of enabled", resourceBlock.FullName()) return } publicAccessAttr := resourceBlock.GetAttribute("public_network_access_enabled") if publicAccessAttr.IsTrue() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has public access explicitly enabled", resourceBlock.FullName())). - WithAttribute(publicAccessAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has public access explicitly enabled", resourceBlock.FullName()). + WithAttribute(publicAccessAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule.go b/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule.go index 41f7705713..d70fa5a3f7 100644 --- a/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule.go +++ b/internal/app/tfsec/rules/azure/database/no_public_firewall_access_rule.go @@ -1,8 +1,6 @@ package database import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -73,15 +71,12 @@ resource "azurerm_sql_firewall_rule" "good_example" { } sourceIpAttr := resourceBlock.GetAttribute("start_ip_address") - if sourceIpAttr.Equals("0.0.0.0") { - endIpAttr := resourceBlock.GetAttribute("end_ip_address") - if !endIpAttr.Equals("0.0.0.0") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has an open IP range set.", resourceBlock.FullName())). - WithAttribute(endIpAttr), - ) - } + endIpAttr := resourceBlock.GetAttribute("end_ip_address") + if sourceIpAttr.Equals("0.0.0.0") && endIpAttr.NotEqual("0.0.0.0") { + set.AddResult(). + WithDescription("Resource '%s' has an open IP range set.", resourceBlock.FullName()). + WithAttribute(endIpAttr) + } }, diff --git a/internal/app/tfsec/rules/azure/database/retention_period_set_rule.go b/internal/app/tfsec/rules/azure/database/retention_period_set_rule.go index 01652a8c08..33603b076c 100644 --- a/internal/app/tfsec/rules/azure/database/retention_period_set_rule.go +++ b/internal/app/tfsec/rules/azure/database/retention_period_set_rule.go @@ -1,8 +1,6 @@ package database import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -80,10 +78,8 @@ resource "azurerm_mssql_database_extended_auditing_policy" "good_example" { return } if resourceBlock.GetAttribute("retention_in_days").LessThan(90) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' specifies a retention period of less than 90 days.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' specifies a retention period of less than 90 days.", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/azure/database/secure_tls_policy_rule.go b/internal/app/tfsec/rules/azure/database/secure_tls_policy_rule.go index a4f7ede2d4..996778edc8 100644 --- a/internal/app/tfsec/rules/azure/database/secure_tls_policy_rule.go +++ b/internal/app/tfsec/rules/azure/database/secure_tls_policy_rule.go @@ -1,8 +1,6 @@ package database import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -93,20 +91,16 @@ resource "azurerm_postgresql_server" "good_example" { return } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have %s set", resourceBlock.FullName(), attribute)), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have %s set", resourceBlock.FullName(), attribute) return } tlsMinimumAttr := resourceBlock.GetAttribute(attribute) - if !tlsMinimumAttr.Equals(requiredValue) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a value %s that is not %s", resourceBlock.FullName(), attribute, requiredValue)). - WithAttribute(tlsMinimumAttr), - ) + if tlsMinimumAttr.NotEqual(requiredValue) { + set.AddResult(). + WithDescription("Resource '%s' has a value %s that is not %s", resourceBlock.FullName(), attribute, requiredValue). + WithAttribute(tlsMinimumAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/datafactory/no_public_access_rule.go b/internal/app/tfsec/rules/azure/datafactory/no_public_access_rule.go index 710dc3dd82..aa91e6d399 100644 --- a/internal/app/tfsec/rules/azure/datafactory/no_public_access_rule.go +++ b/internal/app/tfsec/rules/azure/datafactory/no_public_access_rule.go @@ -1,8 +1,6 @@ package datafactory import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,17 +56,14 @@ resource "azurerm_data_factory" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("public_network_enabled") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have public_network_enabled set to false, the default is true.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have public_network_enabled set to false, the default is true.", resourceBlock.FullName()) return } - if resourceBlock.GetAttribute("public_network_enabled").IsTrue() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should not have public network set to true.", resourceBlock.FullName())), - ) + publicAccessAttr := resourceBlock.GetAttribute("public_network_enabled") + if publicAccessAttr.IsTrue() { + set.AddResult(). + WithDescription("Resource '%s' should not have public network set to true.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/azure/datalake/enable_at_rest_encryption_rule.go b/internal/app/tfsec/rules/azure/datalake/enable_at_rest_encryption_rule.go index de25a3aebf..b06b5b9db9 100644 --- a/internal/app/tfsec/rules/azure/datalake/enable_at_rest_encryption_rule.go +++ b/internal/app/tfsec/rules/azure/datalake/enable_at_rest_encryption_rule.go @@ -1,8 +1,6 @@ package datalake import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -50,16 +46,14 @@ resource "azurerm_data_lake_store" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + if resourceBlock.MissingChild("encryption_state") { + return + } + encryptionStateAttr := resourceBlock.GetAttribute("encryption_state") - if encryptionStateAttr != nil && encryptionStateAttr.Type() == cty.String && encryptionStateAttr.Value().AsString() == "Disabled" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' defines an unencrypted data lake store.", - resourceBlock.FullName(), - )). - WithAttribute(encryptionStateAttr), - ) + if encryptionStateAttr.Equals("Disabled") { + set.AddResult(). + WithDescription("Resource '%s' defines an unencrypted data lake store.", resourceBlock.FullName()).WithAttribute(encryptionStateAttr) } }, diff --git a/internal/app/tfsec/rules/azure/keyvault/content_type_for_secret_rule.go b/internal/app/tfsec/rules/azure/keyvault/content_type_for_secret_rule.go index ceafbbb53a..2ec132f9c4 100644 --- a/internal/app/tfsec/rules/azure/keyvault/content_type_for_secret_rule.go +++ b/internal/app/tfsec/rules/azure/keyvault/content_type_for_secret_rule.go @@ -1,8 +1,6 @@ package keyvault import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,10 +56,8 @@ resource "azurerm_key_vault_secret" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("content_type") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have a content type set.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have a content type set.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/azure/keyvault/ensure_key_expiry_rule.go b/internal/app/tfsec/rules/azure/keyvault/ensure_key_expiry_rule.go index f90c82d1bd..fa7437b361 100644 --- a/internal/app/tfsec/rules/azure/keyvault/ensure_key_expiry_rule.go +++ b/internal/app/tfsec/rules/azure/keyvault/ensure_key_expiry_rule.go @@ -1,8 +1,6 @@ package keyvault import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -78,10 +76,8 @@ resource "azurerm_key_vault_key" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("expiration_date") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have an expiration date set.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have an expiration date set.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/azure/keyvault/ensure_secret_expiry_rule.go b/internal/app/tfsec/rules/azure/keyvault/ensure_secret_expiry_rule.go index e0ae70f4b0..17750c47cf 100644 --- a/internal/app/tfsec/rules/azure/keyvault/ensure_secret_expiry_rule.go +++ b/internal/app/tfsec/rules/azure/keyvault/ensure_secret_expiry_rule.go @@ -1,8 +1,6 @@ package keyvault import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,10 +56,8 @@ resource "azurerm_key_vault_secret" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("expiration_date") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have an expiration date set.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have an expiration date set.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/azure/keyvault/no_purge_rule.go b/internal/app/tfsec/rules/azure/keyvault/no_purge_rule.go index 911d3b53aa..abf5250fe4 100644 --- a/internal/app/tfsec/rules/azure/keyvault/no_purge_rule.go +++ b/internal/app/tfsec/rules/azure/keyvault/no_purge_rule.go @@ -1,8 +1,6 @@ package keyvault import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -59,18 +57,21 @@ resource "azurerm_key_vault" "good_example" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.MissingChild("purge_protection_enabled") || resourceBlock.GetAttribute("purge_protection_enabled").IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have purge protection enabled.", resourceBlock.FullName())), - ) + if resourceBlock.MissingChild("purge_protection_enabled") { + set.AddResult(). + WithDescription("Resource '%s' should have purge protection enabled.", resourceBlock.FullName()) + return + } + purgeProtectionAttr := resourceBlock.GetAttribute("purge_protection_enabled") + if purgeProtectionAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' should have purge protection enabled.", resourceBlock.FullName()).WithAttribute(purgeProtectionAttr) return } + if resourceBlock.MissingChild("soft_delete_retention_days") || resourceBlock.GetAttribute("soft_delete_retention_days").LessThan(1) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have soft_delete_retention_days set in order to enabled purge protection.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have soft_delete_retention_days set in order to enabled purge protection.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule.go b/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule.go index a9bba5f122..6ce52ba961 100644 --- a/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule.go +++ b/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule.go @@ -1,8 +1,6 @@ package keyvault import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -65,38 +63,17 @@ resource "azurerm_key_vault" "good_example" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.MissingChild("network_acls") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' specifies does not specify a network acl block.", resourceBlock.FullName())), - ) - return - } - - networkAcls := resourceBlock.GetBlock("network_acls") - if networkAcls == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' specifies does not specify a network acl block.", resourceBlock.FullName())), - ) - return - } - - if networkAcls.MissingChild("default_action") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' specifies does not specify a default action in the network acl.", resourceBlock.FullName())), - ) + defaultActionAttr := resourceBlock.GetNestedAttribute("network_acls.default_action") + if defaultActionAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' specifies does not specify a network acl block with default action.", resourceBlock.FullName()) return } - defaultActionAttr := networkAcls.GetAttribute("default_action") if !defaultActionAttr.Equals("Deny") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' specifies does not specify a network acl block.", resourceBlock.FullName())). - WithAttribute(defaultActionAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' specifies does not specify a network acl block.", resourceBlock.FullName()). + WithAttribute(defaultActionAttr) } }, diff --git a/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule_test.go b/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule_test.go index 4d7437fcb3..3e97a47225 100644 --- a/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule_test.go +++ b/internal/app/tfsec/rules/azure/keyvault/specify_network_acl_rule_test.go @@ -18,31 +18,31 @@ func Test_AZUKeyVaultNetworkAcl(t *testing.T) { { name: "check fails when no network acl block is provided", source: ` -resource "azurerm_key_vault" "bad_example" { - name = "examplekeyvault" - location = azurerm_resource_group.bad_example.location - enabled_for_disk_encryption = true - soft_delete_retention_days = 7 - purge_protection_enabled = false -} -`, + resource "azurerm_key_vault" "bad_example" { + name = "examplekeyvault" + location = azurerm_resource_group.bad_example.location + enabled_for_disk_encryption = true + soft_delete_retention_days = 7 + purge_protection_enabled = false + } + `, mustIncludeResultCode: expectedCode, }, { name: "check fails when network acl block is provided with default action as allow", source: ` -resource "azurerm_key_vault" "bad_example" { - name = "examplekeyvault" - location = azurerm_resource_group.bad_example.location - enabled_for_disk_encryption = true - soft_delete_retention_days = 7 - purge_protection_enabled = false + resource "azurerm_key_vault" "bad_example" { + name = "examplekeyvault" + location = azurerm_resource_group.bad_example.location + enabled_for_disk_encryption = true + soft_delete_retention_days = 7 + purge_protection_enabled = false - network_acls { - bypass = "AzureServices" - default_action = "Allow" - } -} -`, + network_acls { + bypass = "AzureServices" + default_action = "Allow" + } + } + `, mustIncludeResultCode: expectedCode, }, { diff --git a/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go b/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go index bd356e091a..f236466eff 100644 --- a/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go +++ b/internal/app/tfsec/rules/azure/monitor/activity_log_retention_set_rule.go @@ -1,8 +1,6 @@ package monitor import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -64,28 +62,22 @@ resource "azurerm_monitor_log_profile" "good_example" { retentionPolicyBlock := resourceBlock.GetBlock("retention_policy") if retentionPolicyBlock.MissingChild("enabled") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not enable retention policy", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not enable retention policy", resourceBlock.FullName()).WithBlock(retentionPolicyBlock) return } if retentionPolicyBlock.MissingChild("days") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not retention policy days set", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not retention policy days set", resourceBlock.FullName()).WithBlock(retentionPolicyBlock) return } daysAttr := retentionPolicyBlock.GetAttribute("days") if daysAttr.LessThan(356) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has retention period of less than 365 days", resourceBlock.FullName())). - WithAttribute(daysAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has retention period of less than 365 days", resourceBlock.FullName()). + WithAttribute(daysAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go b/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go index 938f6fae44..d13667d676 100644 --- a/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go +++ b/internal/app/tfsec/rules/azure/monitor/capture_all_activities_rule.go @@ -1,8 +1,6 @@ package monitor import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -67,21 +65,17 @@ resource "azurerm_monitor_log_profile" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { categoriesAttr := resourceBlock.GetAttribute("categories") - if categoriesAttr == nil || categoriesAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have required categories", resourceBlock.FullName())), - ) + if categoriesAttr.IsNil() || categoriesAttr.IsEmpty() { + set.AddResult(). + WithDescription("Resource '%s' does not have required categories", resourceBlock.FullName()) return } for _, category := range []string{"Action", "Write", "Delete"} { if !categoriesAttr.Contains(category) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing '%s' category", resourceBlock.FullName(), category)). - WithAttribute(categoriesAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' is missing '%s' category", resourceBlock.FullName(), category). + WithAttribute(categoriesAttr) } } diff --git a/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go b/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go index 6885074ebb..ac6a7efa93 100644 --- a/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go +++ b/internal/app/tfsec/rules/azure/monitor/capture_all_regions_rule.go @@ -1,8 +1,6 @@ package monitor import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -140,22 +138,24 @@ resource "azurerm_monitor_log_profile" "bad_example" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + if resourceBlock.MissingChild("locations") { + set.AddResult(). + WithDescription("Resource '%s' does not have the locations block set", resourceBlock.FullName()) + return + } + locationsAttr := resourceBlock.GetAttribute("locations") - if locationsAttr == nil || locationsAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have all locations specified", resourceBlock.FullName())), - ) + if locationsAttr.IsEmpty() { + set.AddResult(). + WithDescription("Resource '%s' does not have all locations specified", resourceBlock.FullName()) return } for _, location := range locations { if !locationsAttr.Contains(location) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have the location '%s'", resourceBlock.LocalName(), location)). - WithAttribute(locationsAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have the location '%s'", resourceBlock.LocalName(), location). + WithAttribute(locationsAttr) } } diff --git a/internal/app/tfsec/rules/azure/network/disable_rdp_from_internet_rule.go b/internal/app/tfsec/rules/azure/network/disable_rdp_from_internet_rule.go index 792047c534..d81e3bca52 100644 --- a/internal/app/tfsec/rules/azure/network/disable_rdp_from_internet_rule.go +++ b/internal/app/tfsec/rules/azure/network/disable_rdp_from_internet_rule.go @@ -1,8 +1,6 @@ package network import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -107,11 +105,10 @@ resource "azurerm_network_security_group" "example" { } if securityRule.HasChild("destination_port_range") && securityRule.GetAttribute("destination_port_range").Contains("3389") { if securityRule.HasChild("source_address_prefix") { - if securityRule.GetAttribute("source_address_prefix").IsAny("*", "0.0.0.0", "/0", "internet", "any") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a source address prefix of *, 0.0.0.0, /0, internet or an any. Consider using the Azure Bastion Service.", resourceBlock.FullName())), - ) + sourceAddrAttr := securityRule.GetAttribute("source_address_prefix") + if sourceAddrAttr.IsAny("*", "0.0.0.0", "/0", "internet", "any") { + set.AddResult(). + WithDescription("Resource '%s' has a source address prefix of *, 0.0.0.0, /0, internet or an any. Consider using the Azure Bastion Service.", resourceBlock.FullName()).WithAttribute(sourceAddrAttr) } } } diff --git a/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go b/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go index 044feec150..8fada65ecc 100644 --- a/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go +++ b/internal/app/tfsec/rules/azure/network/no_public_egress_rule.go @@ -1,7 +1,6 @@ package network import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -59,34 +58,26 @@ resource "azurerm_network_security_rule" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { directionAttr := resourceBlock.GetAttribute("direction") - if directionAttr == nil || directionAttr.Type() != cty.String || strings.ToUpper(directionAttr.Value().AsString()) != "OUTBOUND" { + if directionAttr.IsNil() || directionAttr.Type() != cty.String || strings.ToUpper(directionAttr.Value().AsString()) != "OUTBOUND" { return } - if prefixAttr := resourceBlock.GetAttribute("destination_address_prefix"); prefixAttr != nil && prefixAttr.Type() == cty.String { + if prefixAttr := resourceBlock.GetAttribute("destination_address_prefix"); prefixAttr.IsString() { if cidr.IsOpen(prefixAttr) { - if accessAttr := resourceBlock.GetAttribute("access"); accessAttr != nil && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' defines a fully open %s network security group rule.", - resourceBlock.FullName(), - strings.ToLower(directionAttr.Value().AsString()), - )). - WithAttribute(prefixAttr), - ) + if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.IsNotNil() && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" { + set.AddResult(). + WithDescription("Resource '%s' defines a fully open %s network security group rule.", resourceBlock.FullName(), strings.ToLower(directionAttr.Value().AsString())). + WithAttribute(prefixAttr) } } } - if prefixesAttr := resourceBlock.GetAttribute("destination_address_prefixes"); prefixesAttr != nil && prefixesAttr.Value().LengthInt() > 0 { + if prefixesAttr := resourceBlock.GetAttribute("destination_address_prefixes"); !prefixesAttr.IsEmpty() { if cidr.IsOpen(prefixesAttr) { - if accessAttr := resourceBlock.GetAttribute("access"); accessAttr != nil && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open security group rule.", resourceBlock.FullName())). - WithAttribute(prefixesAttr), - ) + if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.IsNotNil() && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" { + set.AddResult(). + WithDescription("Resource '%s' defines a fully open security group rule.", resourceBlock.FullName()). + WithAttribute(prefixesAttr) } } } diff --git a/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go b/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go index 8f2b194d76..560718d6f8 100644 --- a/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go +++ b/internal/app/tfsec/rules/azure/network/no_public_ingress_rule.go @@ -1,7 +1,6 @@ package network import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -17,8 +16,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -59,34 +56,26 @@ resource "azurerm_network_security_rule" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { directionAttr := resourceBlock.GetAttribute("direction") - if directionAttr == nil || directionAttr.Type() != cty.String || strings.ToUpper(directionAttr.Value().AsString()) != "INBOUND" { + if directionAttr.NotEqual("INBOUND", block.IgnoreCase) { return } - if prefixAttr := resourceBlock.GetAttribute("source_address_prefix"); prefixAttr != nil && prefixAttr.Type() == cty.String { + if prefixAttr := resourceBlock.GetAttribute("source_address_prefix"); prefixAttr.IsString() { if cidr.IsOpen(prefixAttr) { - if accessAttr := resourceBlock.GetAttribute("access"); accessAttr != nil && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' defines a fully open %s network security group rule.", - resourceBlock.FullName(), - strings.ToLower(directionAttr.Value().AsString()), - )). - WithAttribute(prefixAttr), - ) + if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.Equals("ALLOW", block.IgnoreCase) { + set.AddResult(). + WithDescription("Resource '%s' defines a fully open %s network security group rule.", resourceBlock.FullName(), strings.ToLower(directionAttr.Value().AsString())). + WithAttribute(prefixAttr) } } } - if prefixesAttr := resourceBlock.GetAttribute("source_address_prefixes"); prefixesAttr != nil && prefixesAttr.Value().LengthInt() > 0 { + if prefixesAttr := resourceBlock.GetAttribute("source_address_prefixes"); !prefixesAttr.IsEmpty() { if cidr.IsOpen(prefixesAttr) { - if accessAttr := resourceBlock.GetAttribute("access"); accessAttr != nil && strings.ToUpper(accessAttr.Value().AsString()) == "ALLOW" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open security group rule.", resourceBlock.FullName())). - WithAttribute(prefixesAttr), - ) + if accessAttr := resourceBlock.GetAttribute("access"); accessAttr.Equals("ALLOW", block.IgnoreCase) { + set.AddResult(). + WithDescription("Resource '%s' defines a fully open security group rule.", resourceBlock.FullName()). + WithAttribute(prefixesAttr) } } } diff --git a/internal/app/tfsec/rules/azure/network/retention_policy_set_rule.go b/internal/app/tfsec/rules/azure/network/retention_policy_set_rule.go index d9eef971c1..6cd36e7cec 100644 --- a/internal/app/tfsec/rules/azure/network/retention_policy_set_rule.go +++ b/internal/app/tfsec/rules/azure/network/retention_policy_set_rule.go @@ -1,8 +1,6 @@ package network import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -71,17 +69,15 @@ resource "azurerm_network_watcher_flow_log" "good_watcher" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("retention_policy") { - set.Add( - result.New(resourceBlock).WithDescription(fmt.Sprintf("Resource '%s' is missing the required retention policy block", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is missing the required retention policy block", resourceBlock.FullName()) return } retentionPolicyBlock := resourceBlock.GetBlock("retention_policy") if retentionPolicyBlock.MissingChild("enabled") || retentionPolicyBlock.MissingChild("days") { - set.Add( - result.New(resourceBlock).WithDescription(fmt.Sprintf("Resource '%s' is missing the required attributes retention policy block", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is missing the required attributes retention policy block", resourceBlock.FullName()) return } @@ -89,17 +85,15 @@ resource "azurerm_network_watcher_flow_log" "good_watcher" { daysAttr := retentionPolicyBlock.GetAttribute("days") if enabledAttr.IsFalse() { - set.Add( - result.New(resourceBlock).WithDescription(fmt.Sprintf("Resource '%s' has retention policy turned off", resourceBlock.FullName())). - WithAttribute(enabledAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has retention policy turned off", resourceBlock.FullName()). + WithAttribute(enabledAttr) } if daysAttr.LessThan(90) { - set.Add( - result.New(resourceBlock).WithDescription(fmt.Sprintf("Resource '%s' has retention policy period of less than 90 days", resourceBlock.FullName())). - WithAttribute(daysAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has retention policy period of less than 90 days", resourceBlock.FullName()). + WithAttribute(daysAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/network/ssh_blocked_from_internet_rule.go b/internal/app/tfsec/rules/azure/network/ssh_blocked_from_internet_rule.go index 854f5c55fe..bdf907691c 100644 --- a/internal/app/tfsec/rules/azure/network/ssh_blocked_from_internet_rule.go +++ b/internal/app/tfsec/rules/azure/network/ssh_blocked_from_internet_rule.go @@ -1,8 +1,6 @@ package network import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -107,10 +105,8 @@ resource "azurerm_network_security_group" "example" { if securityRule.HasChild("destination_port_range") && securityRule.GetAttribute("destination_port_range").Contains("22") { if securityRule.HasChild("source_address_prefix") { if securityRule.GetAttribute("source_address_prefix").IsAny("*", "0.0.0.0", "/0", "internet", "any") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a .", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has a .", resourceBlock.FullName()).WithBlock(securityRule) } } } diff --git a/internal/app/tfsec/rules/azure/securitycenter/alert_on_severe_notifications_rule.go b/internal/app/tfsec/rules/azure/securitycenter/alert_on_severe_notifications_rule.go index 34aab7cb41..ee10b93e42 100644 --- a/internal/app/tfsec/rules/azure/securitycenter/alert_on_severe_notifications_rule.go +++ b/internal/app/tfsec/rules/azure/securitycenter/alert_on_severe_notifications_rule.go @@ -1,8 +1,6 @@ package securitycenter import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,19 +55,17 @@ resource "azurerm_security_center_contact" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("alert_notifications") { - set.Add( - result.New(resourceBlock).WithDescription(fmt.Sprintf("Resource '%s' is missing the required setting for alert_notifications", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is missing the required setting for alert_notifications", resourceBlock.FullName()) return } alertNotificationsAttr := resourceBlock.GetAttribute("alert_notifications") if alertNotificationsAttr.IsFalse() { - set.Add( - result.New(resourceBlock).WithDescription(fmt.Sprintf("Resource '%s' has alert_notifications turned off", resourceBlock.FullName())). - WithAttribute(alertNotificationsAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has alert_notifications turned off", resourceBlock.FullName()). + WithAttribute(alertNotificationsAttr) } }, diff --git a/internal/app/tfsec/rules/azure/securitycenter/enable_standard_subscription_rule.go b/internal/app/tfsec/rules/azure/securitycenter/enable_standard_subscription_rule.go index c6aa37f8e9..03de01ca99 100644 --- a/internal/app/tfsec/rules/azure/securitycenter/enable_standard_subscription_rule.go +++ b/internal/app/tfsec/rules/azure/securitycenter/enable_standard_subscription_rule.go @@ -1,8 +1,6 @@ package securitycenter import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -51,13 +49,16 @@ resource "azurerm_security_center_subscription_pricing" "good_example" { RequiredLabels: []string{"azurerm_security_center_subscription_pricing"}, DefaultSeverity: severity.Low, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + + if resourceBlock.MissingChild("tier") { + return + } + tierAttr := resourceBlock.GetAttribute("tier") - if tierAttr != nil && tierAttr.Equals("Free", block.IgnoreCase) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' sets security center subscription type to free.", resourceBlock.FullName())). - WithAttribute(tierAttr), - ) + if tierAttr.Equals("Free", block.IgnoreCase) { + set.AddResult(). + WithDescription("Resource '%s' sets security center subscription type to free.", resourceBlock.FullName()). + WithAttribute(tierAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/securitycenter/set_required_contact_details_rule.go b/internal/app/tfsec/rules/azure/securitycenter/set_required_contact_details_rule.go index d3d10c563f..d3142bb99d 100644 --- a/internal/app/tfsec/rules/azure/securitycenter/set_required_contact_details_rule.go +++ b/internal/app/tfsec/rules/azure/securitycenter/set_required_contact_details_rule.go @@ -1,8 +1,6 @@ package securitycenter import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -57,19 +55,17 @@ resource "azurerm_security_center_contact" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("phone") { - set.Add( - result.New(resourceBlock).WithDescription(fmt.Sprintf("Resource '%s' does not have a phone number set for the security contact", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have a phone number set for the security contact", resourceBlock.FullName()) + return } phoneAttr := resourceBlock.GetAttribute("phone") if phoneAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have a phone number set for the security contact", resourceBlock.FullName())). - WithAttribute(phoneAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' does not have a phone number set for the security contact", resourceBlock.FullName()). + WithAttribute(phoneAttr) } }, }) diff --git a/internal/app/tfsec/rules/azure/storage/allow_microsoft_service_bypass_rule.go b/internal/app/tfsec/rules/azure/storage/allow_microsoft_service_bypass_rule.go index 30756d24b7..caa036fc3d 100644 --- a/internal/app/tfsec/rules/azure/storage/allow_microsoft_service_bypass_rule.go +++ b/internal/app/tfsec/rules/azure/storage/allow_microsoft_service_bypass_rule.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -105,20 +103,21 @@ resource "azurerm_storage_account_network_rules" "test" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + blockName := resourceBlock.FullName() + if resourceBlock.IsResourceType("azurerm_storage_account") { if resourceBlock.MissingChild("network_rules") { return } resourceBlock = resourceBlock.GetBlock("network_rules") + } if resourceBlock.HasChild("bypass") { bypass := resourceBlock.GetAttribute("bypass") - if bypass != nil && !bypass.Contains("AzureServices") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a network rule that doesn't allow bypass of Microsoft Services.", resourceBlock.FullName())), - ) + if bypass.IsNotNil() && !bypass.Contains("AzureServices") { + set.AddResult(). + WithDescription("Resource '%s' defines a network rule that doesn't allow bypass of Microsoft Services.", blockName) } } diff --git a/internal/app/tfsec/rules/azure/storage/default_action_deny_rule.go b/internal/app/tfsec/rules/azure/storage/default_action_deny_rule.go index 892a2e18c3..6c537d30c5 100644 --- a/internal/app/tfsec/rules/azure/storage/default_action_deny_rule.go +++ b/internal/app/tfsec/rules/azure/storage/default_action_deny_rule.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -60,6 +58,8 @@ resource "azurerm_storage_account_network_rules" "good_example" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { + blockName := resourceBlock.FullName() + if resourceBlock.IsResourceType("azurerm_storage_account") { if resourceBlock.MissingChild("network_rules") { return @@ -68,11 +68,9 @@ resource "azurerm_storage_account_network_rules" "good_example" { } defaultAction := resourceBlock.GetAttribute("default_action") - if defaultAction != nil && defaultAction.Equals("Allow", block.IgnoreCase) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a default_action of Allow. It should be Deny.", resourceBlock.FullName())), - ) + if defaultAction.IsNotNil() && defaultAction.Equals("Allow", block.IgnoreCase) { + set.AddResult(). + WithDescription("Resource '%s' defines a default_action of Allow. It should be Deny.", blockName) } }, diff --git a/internal/app/tfsec/rules/azure/storage/enforce_https_rule.go b/internal/app/tfsec/rules/azure/storage/enforce_https_rule.go index 2251ade22d..3660f8c135 100644 --- a/internal/app/tfsec/rules/azure/storage/enforce_https_rule.go +++ b/internal/app/tfsec/rules/azure/storage/enforce_https_rule.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -64,11 +62,14 @@ resource "azurerm_storage_account" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.HasChild("enable_https_traffic_only") && resourceBlock.GetAttribute("enable_https_traffic_only").IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' explicitly turns off secure transfer to storage account.", resourceBlock.FullName())), - ) + if resourceBlock.HasChild("enable_https_traffic_only") { + + httpsOnlyAttr := resourceBlock.GetAttribute("enable_https_traffic_only") + + if httpsOnlyAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' explicitly turns off secure transfer to storage account.", resourceBlock.FullName()) + } } }, diff --git a/internal/app/tfsec/rules/azure/storage/ensure_https_rule.go b/internal/app/tfsec/rules/azure/storage/ensure_https_rule.go deleted file mode 100644 index 7bc83e9301..0000000000 --- a/internal/app/tfsec/rules/azure/storage/ensure_https_rule.go +++ /dev/null @@ -1,68 +0,0 @@ -package storage - -import ( - "fmt" - - "github.com/aquasecurity/tfsec/pkg/result" - "github.com/aquasecurity/tfsec/pkg/severity" - - "github.com/aquasecurity/tfsec/pkg/provider" - - "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" - - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" - - "github.com/aquasecurity/tfsec/pkg/rule" - - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - "github.com/zclconf/go-cty/cty" -) - -func init() { - scanner.RegisterCheckRule(rule.Rule{ - LegacyID: "AZU010", - Service: "storage", - ShortCode: "ensure-https", - Documentation: rule.RuleDocumentation{ - Summary: "Ensure HTTPS is enabled on Azure Storage Account", - Impact: "HTTP access to storage account could be read if intercepted", - Resolution: "Only use HTTPS for storage account", - Explanation: ` -Requiring HTTPS in Storage Account helps to minimize the risk of eavesdropping. -`, - BadExample: []string{` -resource "azurerm_storage_account" "bad_example" { - enable_https_traffic_only = false -} -`}, - GoodExample: []string{` -resource "azurerm_storage_account" "good_example" { - enable_https_traffic_only = true -} -`}, - Links: []string{ - "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account", - "https://docs.microsoft.com/en-us/azure/storage/blobs/security-recommendations", - }, - }, - Provider: provider.AzureProvider, - RequiredTypes: []string{"resource"}, - RequiredLabels: []string{"azurerm_storage_account", "enable_https_traffic_only"}, - DefaultSeverity: severity.Critical, - CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - - enabledAttr := resourceBlock.GetAttribute("enable_https_traffic_only") - if enabledAttr != nil && enabledAttr.Type() == cty.Bool && enabledAttr.Value().False() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf( - "Resource '%s' enable_https_traffic_only disabled.", - resourceBlock.FullName(), - )). - WithAttribute(enabledAttr), - ) - } - - }, - }) -} diff --git a/internal/app/tfsec/rules/azure/storage/ensure_https_rule_test.go b/internal/app/tfsec/rules/azure/storage/ensure_https_rule_test.go deleted file mode 100644 index 8debbb31d0..0000000000 --- a/internal/app/tfsec/rules/azure/storage/ensure_https_rule_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package storage - -import ( - "testing" - - "github.com/aquasecurity/tfsec/internal/app/tfsec/testutil" -) - -func Test_AZUStorageAccountHTTPSenabled(t *testing.T) { - expectedCode := "azure-storage-ensure-https" - - var tests = []struct { - name string - source string - mustIncludeResultCode string - mustExcludeResultCode string - }{ - { - name: "check azurerm_storage_account with no enable_https_traffic_only define", - source: ` -resource "azurerm_storage_account" "my-storage-account" { - -}`, - mustExcludeResultCode: expectedCode, - }, - { - name: "check azurerm_storage_account with enable_https_traffic_only disabled", - source: ` -resource "azurerm_storage_account" "my-storage-account" { - enable_https_traffic_only = false -}`, - mustIncludeResultCode: expectedCode, - }, - { - name: "check azurerm_storage_account with enable_https_traffic_only enabled", - source: ` -resource "azurerm_storage_account" "my-storage-account" { - enable_https_traffic_only = true -}`, - mustExcludeResultCode: expectedCode, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - - results := testutil.ScanHCL(test.source, t) - testutil.AssertCheckCode(t, test.mustIncludeResultCode, test.mustExcludeResultCode, results) - }) - } - -} diff --git a/internal/app/tfsec/rules/azure/storage/no_public_access_rule.go b/internal/app/tfsec/rules/azure/storage/no_public_access_rule.go index 4b793e3307..8a950b35a8 100644 --- a/internal/app/tfsec/rules/azure/storage/no_public_access_rule.go +++ b/internal/app/tfsec/rules/azure/storage/no_public_access_rule.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -64,20 +62,17 @@ resource "azure_storage_container" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - // function contents here - if resourceBlock.HasChild("properties") { - properties := resourceBlock.GetAttribute("properties") - if properties != nil && properties.Contains("publicAccess") { - value := properties.MapValue("publicAccess") - if value == cty.StringVal("blob") || value == cty.StringVal("container") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines publicAccess as '%s', should be 'off .", resourceBlock.FullName(), value)), - ) - } + if resourceBlock.MissingChild("properties") { + return + } + properties := resourceBlock.GetAttribute("properties") + if properties.Contains("publicAccess") { + value := properties.MapValue("publicAccess") + if value == cty.StringVal("blob") || value == cty.StringVal("container") { + set.AddResult(). + WithDescription("Resource '%s' defines publicAccess as '%s', should be 'off .", resourceBlock.FullName(), value).WithAttribute(properties) } } - }, }) } diff --git a/internal/app/tfsec/rules/azure/storage/queue_services_logging_enabled_rule.go b/internal/app/tfsec/rules/azure/storage/queue_services_logging_enabled_rule.go index a8d6bf267d..c4adb7173d 100644 --- a/internal/app/tfsec/rules/azure/storage/queue_services_logging_enabled_rule.go +++ b/internal/app/tfsec/rules/azure/storage/queue_services_logging_enabled_rule.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -73,14 +71,13 @@ resource "azurerm_storage_account" "good_example" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.HasChild("queue_properties") { - queueProps := resourceBlock.GetBlock("queue_properties") - if queueProps.MissingChild("logging") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a Queue Services storage account without Storage Analytics logging.", resourceBlock.FullName())), - ) - } + if resourceBlock.MissingChild("queue_properties") { + return + } + queueProps := resourceBlock.GetBlock("queue_properties") + if queueProps.MissingChild("logging") { + set.AddResult(). + WithDescription("Resource '%s' defines a Queue Services storage account without Storage Analytics logging.", resourceBlock.FullName()).WithBlock(queueProps) } }, diff --git a/internal/app/tfsec/rules/azure/storage/use_secure_tls_policy_rule.go b/internal/app/tfsec/rules/azure/storage/use_secure_tls_policy_rule.go index 144c7774b1..563fd3fba6 100644 --- a/internal/app/tfsec/rules/azure/storage/use_secure_tls_policy_rule.go +++ b/internal/app/tfsec/rules/azure/storage/use_secure_tls_policy_rule.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -59,11 +57,16 @@ resource "azurerm_storage_account" "good_example" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.MissingChild("min_tls_version") || resourceBlock.GetAttribute("min_tls_version").IsNone("TLS1_2") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have the min tls version set to TLS1_2 .", resourceBlock.FullName())), - ) + if resourceBlock.MissingChild("min_tls_version") { + set.AddResult(). + WithDescription("Resource '%s' should have the min tls version set to TLS1_2 .", resourceBlock.FullName()) + return + } + + minTlsAttr := resourceBlock.GetAttribute("min_tls_version") + if minTlsAttr.IsNone("TLS1_2") { + set.AddResult(). + WithDescription("Resource '%s' should have the min tls version set to TLS1_2 .", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go b/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go index 7f805f4800..c95ad5ac34 100644 --- a/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go +++ b/internal/app/tfsec/rules/azure/synapse/virtual_network_enabled_rule.go @@ -1,8 +1,6 @@ package synapse import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -85,19 +83,15 @@ resource "azurerm_synapse_workspace" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("managed_virtual_network_enabled") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have managed_virtual_network_enabled set to true, the default is false.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' should have managed_virtual_network_enabled set to true, the default is false.", resourceBlock.FullName()) return } managedNetworkAttr := resourceBlock.GetAttribute("managed_virtual_network_enabled") if managedNetworkAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' should have managed_virtual_network_enabled set to true, the default is false.", resourceBlock.FullName())). - WithAttribute(managedNetworkAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' should have managed_virtual_network_enabled set to true, the default is false.", resourceBlock.FullName()). + WithAttribute(managedNetworkAttr) } }, }) diff --git a/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go b/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go index 0184ebd726..8e3c1addb4 100644 --- a/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go +++ b/internal/app/tfsec/rules/digitalocean/compute/no_public_egress_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/cidr" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" @@ -69,11 +67,9 @@ resource "digitalocean_firewall" "good_example" { } destinationAddressesAttr := inboundRuleBlock.GetAttribute("destination_addresses") if cidr.IsOpen(destinationAddressesAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open outbound_rule.", resourceBlock.FullName())). - WithAttribute(destinationAddressesAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open outbound_rule.", resourceBlock.FullName()). + WithAttribute(destinationAddressesAttr) } } }, diff --git a/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go b/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go index fbb05d640b..e6b0dbd221 100644 --- a/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go +++ b/internal/app/tfsec/rules/digitalocean/compute/no_public_ingress_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/cidr" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" @@ -70,11 +68,9 @@ resource "digitalocean_firewall" "good_example" { } sourceAddressesAttr := inboundRuleBlock.GetAttribute("source_addresses") if cidr.IsOpen(sourceAddressesAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open inbound_rule.", resourceBlock.FullName())). - WithAttribute(sourceAddressesAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open inbound_rule.", resourceBlock.FullName()). + WithAttribute(sourceAddressesAttr) } } }, diff --git a/internal/app/tfsec/rules/digitalocean/droplet/use_ssh_keys_rule.go b/internal/app/tfsec/rules/digitalocean/droplet/use_ssh_keys_rule.go index 10bdccd426..81ed29d969 100644 --- a/internal/app/tfsec/rules/digitalocean/droplet/use_ssh_keys_rule.go +++ b/internal/app/tfsec/rules/digitalocean/droplet/use_ssh_keys_rule.go @@ -1,8 +1,6 @@ package droplet import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -57,19 +55,15 @@ resource "digitalocean_droplet" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("ssh_keys") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not define ssh_keys", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not define ssh_keys", resourceBlock.FullName()) return } sshKeysAttr := resourceBlock.GetAttribute("ssh_keys") if sshKeysAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has ssh_key specified but is empty.", resourceBlock.FullName())). - WithAttribute(sshKeysAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' has ssh_key specified but is empty.", resourceBlock.FullName()). + WithAttribute(sshKeysAttr) } }, }) diff --git a/internal/app/tfsec/rules/digitalocean/loadbalancing/enforce_https_rule.go b/internal/app/tfsec/rules/digitalocean/loadbalancing/enforce_https_rule.go index 4142627c1c..86a71ef3b7 100644 --- a/internal/app/tfsec/rules/digitalocean/loadbalancing/enforce_https_rule.go +++ b/internal/app/tfsec/rules/digitalocean/loadbalancing/enforce_https_rule.go @@ -1,8 +1,6 @@ package loadbalancing import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -80,10 +78,8 @@ resource "digitalocean_loadbalancer" "bad_example" { } entryPointAttr := rule.GetAttribute("entry_protocol") if entryPointAttr.Equals("http", block.IgnoreCase) { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' uses plain HTTP instead of HTTPS.", resourceBlock.FullName())). - WithAttribute(entryPointAttr), - ) + set.AddResult().WithDescription("Resource '%s' uses plain HTTP instead of HTTPS.", resourceBlock.FullName()). + WithAttribute(entryPointAttr) } } }, diff --git a/internal/app/tfsec/rules/digitalocean/spaces/acl_no_public_read_rule.go b/internal/app/tfsec/rules/digitalocean/spaces/acl_no_public_read_rule.go index 8408b4f28a..d1f9cc5772 100644 --- a/internal/app/tfsec/rules/digitalocean/spaces/acl_no_public_read_rule.go +++ b/internal/app/tfsec/rules/digitalocean/spaces/acl_no_public_read_rule.go @@ -1,8 +1,6 @@ package spaces import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -70,10 +68,8 @@ resource "digitalocean_spaces_bucket_object" "index" { if resourceBlock.HasChild("acl") { aclAttr := resourceBlock.GetAttribute("acl") if aclAttr.Equals("public-read", block.IgnoreCase) { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a publicly readable acl.", resourceBlock.FullName())). - WithAttribute(aclAttr), - ) + set.AddResult().WithDescription("Resource '%s' has a publicly readable acl.", resourceBlock.FullName()). + WithAttribute(aclAttr) } } }, diff --git a/internal/app/tfsec/rules/digitalocean/spaces/disable_force_destroy_rule.go b/internal/app/tfsec/rules/digitalocean/spaces/disable_force_destroy_rule.go index bd4154df16..2d0d70e1e4 100644 --- a/internal/app/tfsec/rules/digitalocean/spaces/disable_force_destroy_rule.go +++ b/internal/app/tfsec/rules/digitalocean/spaces/disable_force_destroy_rule.go @@ -1,8 +1,6 @@ package spaces import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -49,10 +47,8 @@ resource "digitalocean_spaces_bucket" "good_example" { if resourceBlock.HasChild("force_destroy") { forceDestroyAttr := resourceBlock.GetAttribute("force_destroy") if forceDestroyAttr.IsTrue() { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has versioning specified, but it isn't enabled", resourceBlock.FullName())). - WithAttribute(forceDestroyAttr), - ) + set.AddResult().WithDescription("Resource '%s' has versioning specified, but it isn't enabled", resourceBlock.FullName()). + WithAttribute(forceDestroyAttr) } } }, diff --git a/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule.go b/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule.go index 67d957cf44..c647fa2a05 100644 --- a/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule.go +++ b/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule.go @@ -1,8 +1,6 @@ package spaces import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -61,22 +59,16 @@ resource "digitalocean_spaces_bucket" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("versioning") { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have versioning enabled.", resourceBlock.FullName())), - ) - + set.AddResult().WithDescription("Resource '%s' does not have versioning block specified", resourceBlock.FullName()) return } versioningBlock := resourceBlock.GetBlock("versioning") enabledAttr := versioningBlock.GetAttribute("enabled") - if enabledAttr == nil || enabledAttr.IsFalse() { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has versioning specified, but it isn't enabled", resourceBlock.FullName())). - WithAttribute(enabledAttr), - ) - + if enabledAttr.IsNil() || enabledAttr.IsFalse() { + set.AddResult().WithDescription("Resource '%s' has versioning specified, but it isn't enabled", resourceBlock.FullName()). + WithAttribute(enabledAttr) } }, diff --git a/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule_test.go b/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule_test.go index 571a61a5e2..aaa49b38e7 100644 --- a/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule_test.go +++ b/internal/app/tfsec/rules/digitalocean/spaces/versioning_enabled_rule_test.go @@ -18,15 +18,15 @@ func Test_DIGSpacesBucketVersioningEnabled(t *testing.T) { { name: "Spaces bucket with versioning actively disabled fails check", source: ` -resource "digitalocean_spaces_bucket" "bad_example" { - name = "foobar" - region = "nyc3" + resource "digitalocean_spaces_bucket" "bad_example" { + name = "foobar" + region = "nyc3" - versioning { - enabled = false - } -} -`, + versioning { + enabled = false + } + } + `, mustIncludeResultCode: expectedCode, }, { diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule.go b/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule.go index 1a3f93cf24..82eb8ba3b3 100644 --- a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule.go +++ b/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule.go @@ -1,8 +1,6 @@ package secrets import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" "github.com/zclconf/go-cty/cty" @@ -95,10 +93,8 @@ resource "evil_corp" "good_example" { } if security.IsSensitiveAttribute(attribute.Name()) { if attribute.IsResolvable() && attribute.Type() == cty.String && !attribute.Equals("") { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Block '%s' includes a potentially sensitive attribute which is defined within the project.", resourceBlock.FullName())). - WithAttribute(attribute), - ) + set.AddResult().WithDescription("Block '%s' includes a potentially sensitive attribute which is defined within the project.", resourceBlock.FullName()). + WithAttribute(attribute) } } diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule.go b/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule.go index 4a47e863f8..c3d8347033 100644 --- a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule.go +++ b/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule.go @@ -1,8 +1,6 @@ package secrets import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -65,11 +63,9 @@ EOF for _, attribute := range attributes { if attribute.IsString() { if scanResult := security.StringScanner.Scan(attribute.Value().AsString()); scanResult.TransgressionFound { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Block '%s' includes potentially sensitive data. %s", resourceBlock.FullName(), scanResult.Description)). - WithAttribute(attribute), - ) + set.AddResult(). + WithDescription("Block '%s' includes potentially sensitive data. %s", resourceBlock.FullName(), scanResult.Description). + WithAttribute(attribute) } } } diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule.go b/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule.go index acd4f073c8..4fdc7b7623 100644 --- a/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule.go +++ b/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule.go @@ -1,8 +1,6 @@ package secrets import ( - "fmt" - "github.com/zclconf/go-cty/cty" "github.com/aquasecurity/tfsec/internal/app/tfsec/block" @@ -60,10 +58,8 @@ resource "evil_corp" "good_example" { for _, attribute := range resourceBlock.GetAttributes() { if security.IsSensitiveAttribute(attribute.Name()) { if attribute.Type() == cty.String && attribute.IsResolvable() { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Local '%s' includes a potentially sensitive value which is defined within the project.", resourceBlock.FullName())). - WithAttribute(attribute), - ) + set.AddResult().WithDescription("Local '%s' includes a potentially sensitive value which is defined within the project.", resourceBlock.FullName()). + WithAttribute(attribute) } } } diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule.go b/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule.go index 57fd93ddab..d02ee14d1c 100644 --- a/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule.go +++ b/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule.go @@ -1,8 +1,6 @@ package secrets import ( - "fmt" - "github.com/zclconf/go-cty/cty" "github.com/aquasecurity/tfsec/pkg/result" @@ -72,10 +70,8 @@ resource "evil_corp" "virtual_machine" { for _, attribute := range resourceBlock.GetAttributes() { if attribute.Name() == "default" { if attribute.Type() == cty.String && attribute.IsResolvable() { - set.Add(result.New(resourceBlock). - WithDescription(fmt.Sprintf("Variable '%s' includes a potentially sensitive default value.", resourceBlock.FullName())). - WithAttribute(attribute), - ) + set.AddResult().WithDescription("Variable '%s' includes a potentially sensitive default value.", resourceBlock.FullName()). + WithAttribute(attribute) } } } diff --git a/internal/app/tfsec/rules/github/repositories/private_rule.go b/internal/app/tfsec/rules/github/repositories/private_rule.go index 34af2398a1..0b21430951 100644 --- a/internal/app/tfsec/rules/github/repositories/private_rule.go +++ b/internal/app/tfsec/rules/github/repositories/private_rule.go @@ -1,8 +1,6 @@ package repositories import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -71,22 +69,18 @@ resource "github_repository" "good_example" { privateAttribute := resourceBlock.GetAttribute("private") visibilityAttribute := resourceBlock.GetAttribute("visibility") - if visibilityAttribute == nil && privateAttribute == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is missing both of `private` or `visibility` attributes - one of these is required to make repository private", resourceBlock.FullName())), - ) + if visibilityAttribute.IsNil() && privateAttribute.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is missing both of `private` or `visibility` attributes - one of these is required to make repository private", resourceBlock.FullName()) return } // this should be evaluated first as visibility overrides private - if visibilityAttribute != nil { + if visibilityAttribute.IsNotNil() { if visibilityAttribute.Equals("public") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has visibility set to public - visibility should be set to `private` or `internal` to make repository private", resourceBlock.FullName())). - WithAttribute(visibilityAttribute), - ) + set.AddResult(). + WithDescription("Resource '%s' has visibility set to public - visibility should be set to `private` or `internal` to make repository private", resourceBlock.FullName()). + WithAttribute(visibilityAttribute) } // stop here as visibility parameter trumps the private one // see https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository @@ -94,12 +88,10 @@ resource "github_repository" "good_example" { } // this should be evaluated first as visibility overrides private - if privateAttribute != nil { + if privateAttribute.IsNotNil() { if privateAttribute.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has private set to false - it should be set to `true` to make repository private", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has private set to false - it should be set to `true` to make repository private", resourceBlock.FullName()) } } diff --git a/internal/app/tfsec/rules/google/compute/disk_encryption_customer_keys_rule.go b/internal/app/tfsec/rules/google/compute/disk_encryption_customer_keys_rule.go index 62089550e1..2e58521af7 100644 --- a/internal/app/tfsec/rules/google/compute/disk_encryption_customer_keys_rule.go +++ b/internal/app/tfsec/rules/google/compute/disk_encryption_customer_keys_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -54,12 +52,9 @@ resource "google_compute_disk" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - keyBlock := resourceBlock.GetBlock("disk_encryption_key") - if keyBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a disk encrypted with an auto-generated key.", resourceBlock.FullName())), - ) + if resourceBlock.MissingChild("disk_encryption_key") { + set.AddResult(). + WithDescription("Resource '%s' defines a disk encrypted with an auto-generated key.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/google/compute/disk_encryption_required_rule.go b/internal/app/tfsec/rules/google/compute/disk_encryption_required_rule.go index 8674a047d6..5209231cdd 100644 --- a/internal/app/tfsec/rules/google/compute/disk_encryption_required_rule.go +++ b/internal/app/tfsec/rules/google/compute/disk_encryption_required_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/internal/app/tfsec/block" "github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" @@ -49,22 +47,20 @@ resource "google_compute_disk" "good_example" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - keyBlock := resourceBlock.GetBlock("disk_encryption_key") - if keyBlock == nil { + if resourceBlock.MissingChild("disk_encryption_key") { return } - rawKeyAttr := keyBlock.GetAttribute("raw_key") - if rawKeyAttr == nil { + if resourceBlock.MissingNestedChild("disk_encryption_key.raw_key") { return } + rawKeyAttr := resourceBlock.GetNestedAttribute("disk_encryption_key.raw_key") + if rawKeyAttr.IsString() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' specifies an encryption key in raw format.", resourceBlock.FullName())). - WithAttribute(rawKeyAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' specifies an encryption key in raw format.", resourceBlock.FullName()). + WithAttribute(rawKeyAttr) } }, diff --git a/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go b/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go index 28f8ab8c65..09922526bf 100644 --- a/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go +++ b/internal/app/tfsec/rules/google/compute/no_public_egress_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -51,14 +49,12 @@ resource "google_compute_firewall" "good_example" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if destinationRanges := resourceBlock.GetAttribute("destination_ranges"); destinationRanges != nil { + if destinationRanges := resourceBlock.GetAttribute("destination_ranges"); destinationRanges.IsNotNil() { if cidr.IsOpen(destinationRanges) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open outbound firewall rule.", resourceBlock.FullName())). - WithAttribute(destinationRanges), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open outbound firewall rule.", resourceBlock.FullName()). + WithAttribute(destinationRanges) } } diff --git a/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go b/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go index 74a9addf53..bd2745f9e0 100644 --- a/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go +++ b/internal/app/tfsec/rules/google/compute/no_public_ingress_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -52,13 +50,11 @@ resource "google_compute_firewall" "good_example" { DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if sourceRanges := resourceBlock.GetAttribute("source_ranges"); sourceRanges != nil { + if sourceRanges := resourceBlock.GetAttribute("source_ranges"); sourceRanges.IsNotNil() { if cidr.IsOpen(sourceRanges) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a fully open inbound firewall rule.", resourceBlock.FullName())). - WithAttribute(sourceRanges), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a fully open inbound firewall rule.", resourceBlock.FullName()). + WithAttribute(sourceRanges) } } diff --git a/internal/app/tfsec/rules/google/gke/enforce_pod_security_policy_rule.go b/internal/app/tfsec/rules/google/gke/enforce_pod_security_policy_rule.go index 256c562295..7e6f9c49a9 100644 --- a/internal/app/tfsec/rules/google/gke/enforce_pod_security_policy_rule.go +++ b/internal/app/tfsec/rules/google/gke/enforce_pod_security_policy_rule.go @@ -1,8 +1,6 @@ package gke import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,21 +56,16 @@ resource "google_container_cluster" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - pspBlock := resourceBlock.GetBlock("pod_security_policy_config") - if pspBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster with no Pod Security Policy config defined. It is recommended to define a PSP for your pods and enable PSP enforcement.", resourceBlock.FullName())), - ) + if resourceBlock.MissingChild("pod_security_policy_config") { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster with no Pod Security Policy config defined. It is recommended to define a PSP for your pods and enable PSP enforcement.", resourceBlock.FullName()) return } - enforcePSP := pspBlock.GetAttribute("enabled") - if enforcePSP != nil && enforcePSP.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster with Pod Security Policy enforcement disabled. It is recommended to define a PSP for your pods and enable PSP enforcement.", resourceBlock.FullName())), - ) + enforcePSP := resourceBlock.GetNestedAttribute("pod_security_policy_config.enabled") + if enforcePSP.IsNotNil() && enforcePSP.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster with Pod Security Policy enforcement disabled. It is recommended to define a PSP for your pods and enable PSP enforcement.", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/gke/metadata_endpoints_disabled_rule.go b/internal/app/tfsec/rules/google/gke/metadata_endpoints_disabled_rule.go index 92b57917f8..a6197c64cf 100644 --- a/internal/app/tfsec/rules/google/gke/metadata_endpoints_disabled_rule.go +++ b/internal/app/tfsec/rules/google/gke/metadata_endpoints_disabled_rule.go @@ -1,8 +1,6 @@ package gke import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -62,12 +60,10 @@ resource "google_container_cluster" "good_example" { return } - legacyMetadataAPI := resourceBlock.GetBlock("metadata").GetAttribute("disable-legacy-endpoints") - if legacyMetadataAPI != nil && legacyMetadataAPI.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster with legacy metadata endpoints enabled.", resourceBlock.FullName())), - ) + legacyMetadataAPI := resourceBlock.GetNestedAttribute("metadata.disable-legacy-endpoints") + if legacyMetadataAPI.IsNotNil() && legacyMetadataAPI.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster with legacy metadata endpoints enabled.", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/gke/no_legacy_authentication_rule.go b/internal/app/tfsec/rules/google/gke/no_legacy_authentication_rule.go index ab7e99f6fb..1a9250c41e 100644 --- a/internal/app/tfsec/rules/google/gke/no_legacy_authentication_rule.go +++ b/internal/app/tfsec/rules/google/gke/no_legacy_authentication_rule.go @@ -1,8 +1,6 @@ package gke import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -64,33 +62,29 @@ resource "google_container_cluster" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - masterAuthBlock := resourceBlock.GetBlock("master_auth") - if masterAuthBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not disable basic auth with static passwords for client authentication. Disable this with a master_auth block container empty strings for user and password.", resourceBlock.FullName())), - ) + if resourceBlock.MissingChild("master_auth") { + set.AddResult(). + WithDescription("Resource '%s' does not disable basic auth with static passwords for client authentication. Disable this with a master_auth block container empty strings for user and password.", resourceBlock.FullName()) return } - staticAuthPass := masterAuthBlock.GetAttribute("password") - if staticAuthPass != nil && !staticAuthPass.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster using basic auth with static passwords for client authentication. It is recommended to use OAuth or service accounts instead.", resourceBlock.FullName())), - ) + staticAuthPass := resourceBlock.GetNestedAttribute("master_auth.password") + if staticAuthPass.IsNotNil() && !staticAuthPass.IsEmpty() { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster using basic auth with static passwords for client authentication. It is recommended to use OAuth or service accounts instead.", resourceBlock.FullName()) } - if masterAuthBlock.MissingChild("client_certificate_config") { + if resourceBlock.MissingNestedChild("master_auth.client_certificate_config") { return } - issueClientCert := masterAuthBlock.GetBlock("client_certificate_config").GetAttribute("issue_client_certificate") - if issueClientCert != nil && issueClientCert.IsTrue() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster using basic auth with client certificates for authentication. This cert has no permissions if RBAC is enabled and ABAC is disabled. It is recommended to use OAuth or service accounts instead.", resourceBlock.FullName())), - ) + issueClientCert := resourceBlock.GetNestedAttribute("master_auth.client_certificate_config.issue_client_certificate") + if issueClientCert.IsNil() { + return + } + if issueClientCert.IsTrue() { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster using basic auth with client certificates for authentication. This cert has no permissions if RBAC is enabled and ABAC is disabled. It is recommended to use OAuth or service accounts instead.", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/gke/node_metadata_security_rule.go b/internal/app/tfsec/rules/google/gke/node_metadata_security_rule.go index d08f56cfb1..ef31c85546 100644 --- a/internal/app/tfsec/rules/google/gke/node_metadata_security_rule.go +++ b/internal/app/tfsec/rules/google/gke/node_metadata_security_rule.go @@ -1,8 +1,6 @@ package gke import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -15,8 +13,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" - - "github.com/zclconf/go-cty/cty" ) func init() { @@ -61,27 +57,14 @@ resource "google_container_node_pool" "good_example" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if resourceBlock.MissingChild("node_config") { - return - } - nodeConfigBlock := resourceBlock.GetBlock("node_config") - - if nodeConfigBlock.MissingChild("workload_metadata_config") { - return - } - workloadMetadataConfigBlock := nodeConfigBlock.GetBlock("workload_metadata_config") - - if workloadMetadataConfigBlock.MissingChild("node_metadata") { + if resourceBlock.MissingNestedChild("node_config.workload_metadata_config.node_metadata") { return } - nodeMetadata := workloadMetadataConfigBlock.GetAttribute("node_metadata") - if nodeMetadata != nil && nodeMetadata.Type() == cty.String && - (nodeMetadata.Value().AsString() == "EXPOSE" || nodeMetadata.Value().AsString() == "UNSPECIFIED") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster with node metadata exposed. node_metadata set to EXPOSE or UNSPECIFIED disables metadata concealment. ", resourceBlock.FullName())), - ) + nodeMetadata := resourceBlock.GetNestedAttribute("node_config.workload_metadata_config.node_metadata") + if nodeMetadata.IsAny("EXPOSE", "UNSPECIFIED") { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster with node metadata exposed. node_metadata set to EXPOSE or UNSPECIFIED disables metadata concealment. ", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/gke/node_shielding_enabled_rule.go b/internal/app/tfsec/rules/google/gke/node_shielding_enabled_rule.go index bce35a0cd1..13a2f2dfbe 100644 --- a/internal/app/tfsec/rules/google/gke/node_shielding_enabled_rule.go +++ b/internal/app/tfsec/rules/google/gke/node_shielding_enabled_rule.go @@ -1,8 +1,6 @@ package gke import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -51,19 +49,15 @@ resource "google_container_cluster" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.MissingChild("enable_shielded_nodes") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster with shielded nodes disabled. Shielded GKE Nodes provide strong, verifiable node identity and integrity to increase the security of GKE nodes and should be enabled on all GKE clusters.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a cluster with shielded nodes disabled. Shielded GKE Nodes provide strong, verifiable node identity and integrity to increase the security of GKE nodes and should be enabled on all GKE clusters.", resourceBlock.FullName()) return } enableShieldedNodesAttr := resourceBlock.GetAttribute("enable_shielded_nodes") - if enableShieldedNodesAttr != nil && enableShieldedNodesAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster with shielded nodes disabled. Shielded GKE Nodes provide strong, verifiable node identity and integrity to increase the security of GKE nodes and should be enabled on all GKE clusters.", resourceBlock.FullName())), - ) + if enableShieldedNodesAttr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster with shielded nodes disabled. Shielded GKE Nodes provide strong, verifiable node identity and integrity to increase the security of GKE nodes and should be enabled on all GKE clusters.", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/gke/use_rbac_permissions_rule.go b/internal/app/tfsec/rules/google/gke/use_rbac_permissions_rule.go index 6751475a6c..d30807910a 100644 --- a/internal/app/tfsec/rules/google/gke/use_rbac_permissions_rule.go +++ b/internal/app/tfsec/rules/google/gke/use_rbac_permissions_rule.go @@ -1,8 +1,6 @@ package gke import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -14,8 +12,6 @@ import ( "github.com/aquasecurity/tfsec/pkg/rule" - "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" ) @@ -57,11 +53,9 @@ resource "google_container_cluster" "good_example" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { enableLegacyABAC := resourceBlock.GetAttribute("enable_legacy_abac") - if enableLegacyABAC != nil && enableLegacyABAC.Value().Type() == cty.String && enableLegacyABAC.Value().AsString() == "true" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a cluster with ABAC enabled. Disable and rely on RBAC instead. ", resourceBlock.FullName())), - ) + if enableLegacyABAC.IsNotNil() && enableLegacyABAC.IsTrue() { + set.AddResult(). + WithDescription("Resource '%s' defines a cluster with ABAC enabled. Disable and rely on RBAC instead. ", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/gke/use_service_account_rule.go b/internal/app/tfsec/rules/google/gke/use_service_account_rule.go index 97510648c1..c2f2663e0b 100644 --- a/internal/app/tfsec/rules/google/gke/use_service_account_rule.go +++ b/internal/app/tfsec/rules/google/gke/use_service_account_rule.go @@ -1,7 +1,6 @@ package gke import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -56,27 +55,23 @@ resource "google_container_cluster" "good_example" { if strings.HasPrefix(resourceBlock.Label(), "google_container_cluster") { attr := resourceBlock.GetAttribute("remove_default_node_pool") - if attr != nil && attr.IsTrue() { + if attr.IsNotNil() && attr.IsTrue() { return } } if resourceBlock.MissingChild("node_config") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not define the node config and does not override the default service account. It is recommended to use a minimally privileged service account to run your GKE cluster.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' does not define the node config and does not override the default service account. It is recommended to use a minimally privileged service account to run your GKE cluster.", resourceBlock.FullName()) return } nodeConfigBlock := resourceBlock.GetBlock("node_config") serviceAccount := nodeConfigBlock.GetAttribute("service_account") - if serviceAccount == nil || serviceAccount.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not override the default service account. It is recommended to use a minimally privileged service account to run your GKE cluster.", resourceBlock.FullName())), - ) + if serviceAccount.IsNil() || serviceAccount.IsEmpty() { + set.AddResult(). + WithDescription("Resource '%s' does not override the default service account. It is recommended to use a minimally privileged service account to run your GKE cluster.", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/iam/no_default_service_account_assignment_rule.go b/internal/app/tfsec/rules/google/iam/no_default_service_account_assignment_rule.go index 4fb11cf01c..a6687f90fe 100644 --- a/internal/app/tfsec/rules/google/iam/no_default_service_account_assignment_rule.go +++ b/internal/app/tfsec/rules/google/iam/no_default_service_account_assignment_rule.go @@ -1,7 +1,6 @@ package iam import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -75,49 +74,41 @@ resource "google_project_iam_member" "project-123" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, ctx *hclcontext.Context) { - if memberAttr := resourceBlock.GetAttribute("member"); memberAttr != nil { - if memberAttr.IsString() && memberAttr.Value().IsKnown() { + if memberAttr := resourceBlock.GetAttribute("member"); memberAttr.IsNotNil() { + if memberAttr.IsString() { if isMemberDefaultServiceAccount(memberAttr.Value().AsString()) { - set.Add( - result.New(resourceBlock). - WithAttribute(memberAttr). - WithDescription(fmt.Sprintf("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName())), - ) + set.AddResult(). + WithAttribute(memberAttr). + WithDescription("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName()) } } else { computeServiceAccounts := ctx.GetDatasByType("google_compute_default_service_account") serviceAccounts := append(computeServiceAccounts, ctx.GetResourcesByType("google_app_engine_default_service_account")...) for _, serviceAccount := range serviceAccounts { if memberAttr.ReferencesBlock(serviceAccount) { - set.Add( - result.New(resourceBlock). - WithAttribute(memberAttr). - WithDescription(fmt.Sprintf("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName())), - ) + set.AddResult(). + WithAttribute(memberAttr). + WithDescription("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName()) } } } } - if membersAttr := resourceBlock.GetAttribute("members"); membersAttr != nil { + if membersAttr := resourceBlock.GetAttribute("members"); membersAttr.IsNotNil() { for _, member := range membersAttr.ValueAsStrings() { if isMemberDefaultServiceAccount(member) { - set.Add( - result.New(resourceBlock). - WithAttribute(membersAttr). - WithDescription(fmt.Sprintf("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName())), - ) + set.AddResult(). + WithAttribute(membersAttr). + WithDescription("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName()) } } computeServiceAccounts := ctx.GetDatasByType("google_compute_default_service_account") serviceAccounts := append(computeServiceAccounts, ctx.GetResourcesByType("google_app_engine_default_service_account")...) for _, serviceAccount := range serviceAccounts { if membersAttr.ReferencesBlock(serviceAccount) { - set.Add( - result.New(resourceBlock). - WithAttribute(membersAttr). - WithDescription(fmt.Sprintf("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName())), - ) + set.AddResult(). + WithAttribute(membersAttr). + WithDescription("Resource '%s' assigns a role to a default service account.", resourceBlock.FullName()) } } } diff --git a/internal/app/tfsec/rules/google/iam/no_privileged_service_accounts_rule.go b/internal/app/tfsec/rules/google/iam/no_privileged_service_accounts_rule.go index 15d9a98bc2..1beac84f06 100644 --- a/internal/app/tfsec/rules/google/iam/no_privileged_service_accounts_rule.go +++ b/internal/app/tfsec/rules/google/iam/no_privileged_service_accounts_rule.go @@ -1,7 +1,6 @@ package iam import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -64,7 +63,7 @@ resource "google_project_iam_member" "project" { // is this a sensitive role? roleAttr := resourceBlock.GetAttribute("role") - if roleAttr == nil || !roleAttr.IsString() || !roleAttr.Value().IsKnown() { + if !roleAttr.IsString() { return } if !isRolePrivileged(roleAttr.Value().AsString()) { @@ -73,28 +72,24 @@ resource "google_project_iam_member" "project" { // is it linked to a service account? memberAttr := resourceBlock.GetAttribute("member") - if memberAttr == nil { + if memberAttr.IsNil() { return } - if memberAttr.IsString() && memberAttr.Value().IsKnown() { + if memberAttr.IsString() { if memberAttr.StartsWith("serviceAccount:") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' provides privileged access to a service account", resourceBlock)). - WithAttribute(roleAttr), - ) + set.AddResult(). + WithDescription("Resource '%s' provides privileged access to a service account", resourceBlock). + WithAttribute(roleAttr) } } // the service account may be populated via a templated reference that we don't have, so we need to check references if serviceAccountBlock, err := ctx.GetReferencedBlock(memberAttr); err != nil { return - } else if serviceAccountBlock != nil && serviceAccountBlock.TypeLabel() == "google_service_account" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' provides privileged access to service account at %s", resourceBlock, serviceAccountBlock.FullName())). - WithAttribute(roleAttr), - ) + } else if serviceAccountBlock.IsNotNil() && serviceAccountBlock.TypeLabel() == "google_service_account" { + set.AddResult(). + WithDescription("Resource '%s' provides privileged access to service account at %s", resourceBlock, serviceAccountBlock.FullName()). + WithAttribute(roleAttr) } }, }) diff --git a/internal/app/tfsec/rules/google/iam/no_project_level_service_account_impersonation_rule.go b/internal/app/tfsec/rules/google/iam/no_project_level_service_account_impersonation_rule.go index 234fd2e911..935f2bafea 100644 --- a/internal/app/tfsec/rules/google/iam/no_project_level_service_account_impersonation_rule.go +++ b/internal/app/tfsec/rules/google/iam/no_project_level_service_account_impersonation_rule.go @@ -1,8 +1,6 @@ package iam import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -58,15 +56,13 @@ resource "google_project_iam_binding" "project-123" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { roleAttr := resourceBlock.GetAttribute("role") - if roleAttr == nil || !roleAttr.IsString() || !roleAttr.Value().IsKnown() { + if !roleAttr.IsString() { return } - if roleAttr.Value().AsString() == "roles/iam.serviceAccountUser" || roleAttr.Value().AsString() == "roles/iam.serviceAccountTokenCreator" { - set.Add( - result.New(resourceBlock). - WithAttribute(roleAttr). - WithDescription(fmt.Sprintf("Resource '%s' grants service account access to a user at project level.", resourceBlock.FullName())), - ) + if roleAttr.IsAny("roles/iam.serviceAccountUser", "roles/iam.serviceAccountTokenCreator") { + set.AddResult(). + WithAttribute(roleAttr). + WithDescription("Resource '%s' grants service account access to a user at project level.", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/iam/no_user_granted_permissions_rule.go b/internal/app/tfsec/rules/google/iam/no_user_granted_permissions_rule.go index 5099e3e50d..d5bb77c5e1 100644 --- a/internal/app/tfsec/rules/google/iam/no_user_granted_permissions_rule.go +++ b/internal/app/tfsec/rules/google/iam/no_user_granted_permissions_rule.go @@ -1,7 +1,6 @@ package iam import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -98,21 +97,19 @@ resource "google_storage_bucket_iam_member" "good_example" { var members []cty.Value var attribute block.Attribute - if attribute = resourceBlock.GetAttribute("member"); attribute != nil { + if attribute = resourceBlock.GetAttribute("member"); attribute.IsNotNil() { members = append(members, attribute.Value()) - } else if attribute = resourceBlock.GetAttribute("members"); attribute != nil { + } else if attribute = resourceBlock.GetAttribute("members"); attribute.IsNotNil() { members = attribute.Value().AsValueSlice() } else if resourceBlock.HasChild("binding") { - if attribute = resourceBlock.GetBlock("binding").GetAttribute("members"); attribute != nil { + if attribute = resourceBlock.GetBlock("binding").GetAttribute("members"); attribute.IsNotNil() { members = attribute.Value().AsValueSlice() } } for _, identities := range members { if identities.IsKnown() && identities.Type() == cty.String && strings.HasPrefix(identities.AsString(), "user:") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("'%s' grants IAM to a user object. It is recommended to manage user permissions with groups.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("'%s' grants IAM to a user object. It is recommended to manage user permissions with groups.", resourceBlock.FullName()) } } }, diff --git a/internal/app/tfsec/rules/google/sql/enable_backup_rule.go b/internal/app/tfsec/rules/google/sql/enable_backup_rule.go index 52859af68f..9b366c9a39 100644 --- a/internal/app/tfsec/rules/google/sql/enable_backup_rule.go +++ b/internal/app/tfsec/rules/google/sql/enable_backup_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -62,29 +60,21 @@ resource "google_sql_database_instance" "db" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have backups enabled.", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have backups enabled.", resourceBlock.FullName()) return } - if backupBlock := settingsBlock.GetBlock("backup_configuration"); backupBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have backups enabled.", resourceBlock.FullName())), - ) - } else if enabledAttr := backupBlock.GetAttribute("enabled"); enabledAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have backups enabled.", resourceBlock.FullName())), - ) + if backupBlock := settingsBlock.GetBlock("backup_configuration"); backupBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have backups enabled.", resourceBlock.FullName()) + } else if enabledAttr := backupBlock.GetAttribute("enabled"); enabledAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have backups enabled.", resourceBlock.FullName()) } else if enabledAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has backups explicitly disabled.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has backups explicitly disabled.", resourceBlock.FullName()) } }, }) diff --git a/internal/app/tfsec/rules/google/sql/enable_pg_temp_file_logging_rule.go b/internal/app/tfsec/rules/google/sql/enable_pg_temp_file_logging_rule.go index b744b865a8..8ba9335e81 100644 --- a/internal/app/tfsec/rules/google/sql/enable_pg_temp_file_logging_rule.go +++ b/internal/app/tfsec/rules/google/sql/enable_pg_temp_file_logging_rule.go @@ -1,7 +1,6 @@ package sql import ( - "fmt" "strings" "github.com/aquasecurity/tfsec/pkg/result" @@ -56,32 +55,26 @@ resource "google_sql_database_instance" "db" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr != nil && dbVersionAttr.IsString() && !strings.HasPrefix(dbVersionAttr.Value().AsString(), "POSTGRES") { + if dbVersionAttr.IsNotNil() && dbVersionAttr.IsString() && !strings.HasPrefix(dbVersionAttr.Value().AsString(), "POSTGRES") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has temporary file logging disabled by default", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' has temporary file logging disabled by default", resourceBlock.FullName()) return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Value().AsString() == "log_temp_files" { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { + if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr.IsNotNil() && nameAttr.IsString() && nameAttr.Value().AsString() == "log_temp_files" { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.IsNotNil() && valueAttr.IsString() { if valueAttr.Value().AsString() == "-1" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has temporary file logging explicitly disabled", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has temporary file logging explicitly disabled", resourceBlock.FullName()) } else if valueAttr.Value().AsString() != "0" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has temporary file logging disabled for files of certain sizes", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has temporary file logging disabled for files of certain sizes", resourceBlock.FullName()) } // otherwise it's off, awesome return @@ -90,10 +83,8 @@ resource "google_sql_database_instance" "db" { } // we didn't find the flag so it must be on by default - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has temporary file logging disabled by default", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has temporary file logging disabled by default", resourceBlock.FullName()) }, }) diff --git a/internal/app/tfsec/rules/google/sql/encrypt_in_transit_data_rule.go b/internal/app/tfsec/rules/google/sql/encrypt_in_transit_data_rule.go index a41852bd0a..58ee715f76 100644 --- a/internal/app/tfsec/rules/google/sql/encrypt_in_transit_data_rule.go +++ b/internal/app/tfsec/rules/google/sql/encrypt_in_transit_data_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -73,30 +71,24 @@ resource "google_sql_database_instance" "postgres" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { + if settingsBlock.IsNil() { return } ipConfigBlock := settingsBlock.GetBlock("ip_configuration") - if ipConfigBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not require SSL for all connections", resourceBlock.FullName())), - ) + if ipConfigBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not require SSL for all connections", resourceBlock.FullName()) return } - if requireSSLAttr := ipConfigBlock.GetAttribute("require_ssl"); requireSSLAttr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not require SSL for all connections", resourceBlock.FullName())), - ) + if requireSSLAttr := ipConfigBlock.GetAttribute("require_ssl"); requireSSLAttr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not require SSL for all connections", resourceBlock.FullName()) } else if requireSSLAttr.IsFalse() { - set.Add( - result.New(resourceBlock). - WithAttribute(requireSSLAttr). - WithDescription(fmt.Sprintf("Resource '%s' explicitly does not require SSL for all connections", resourceBlock.FullName())), - ) + set.AddResult(). + WithAttribute(requireSSLAttr). + WithDescription("Resource '%s' explicitly does not require SSL for all connections", resourceBlock.FullName()) } }, diff --git a/internal/app/tfsec/rules/google/sql/mysql_no_local_infile_rule.go b/internal/app/tfsec/rules/google/sql/mysql_no_local_infile_rule.go index 9bc97c172c..b7eae5f0f2 100644 --- a/internal/app/tfsec/rules/google/sql/mysql_no_local_infile_rule.go +++ b/internal/app/tfsec/rules/google/sql/mysql_no_local_infile_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -61,30 +59,23 @@ resource "google_sql_database_instance" "db" { RequiredLabels: []string{"google_sql_database_instance"}, DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - // we only need to check this for SQLSERVER, not mysql/postgres - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr == nil || !dbVersionAttr.IsString() { - // default is postgres - return - } - if !dbVersionAttr.StartsWith("MYSQL") { + // we only need to check this for MYSQL + if !resourceBlock.GetAttribute("database_version").StartsWith("MYSQL") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { + if settingsBlock.IsNil() { return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("local_infile") { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { + if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr.IsNotNil() && nameAttr.IsString() && nameAttr.Equals("local_infile") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.IsNotNil() && valueAttr.IsString() { if valueAttr.Equals("on", block.IgnoreCase) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has local file read access enabled.", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has local file read access enabled.", resourceBlock.FullName()) } } } diff --git a/internal/app/tfsec/rules/google/sql/no_contained_db_auth_rule.go b/internal/app/tfsec/rules/google/sql/no_contained_db_auth_rule.go index 469018be8c..e49b0ebbde 100644 --- a/internal/app/tfsec/rules/google/sql/no_contained_db_auth_rule.go +++ b/internal/app/tfsec/rules/google/sql/no_contained_db_auth_rule.go @@ -1,9 +1,6 @@ package sql import ( - "fmt" - "strings" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -56,45 +53,33 @@ resource "google_sql_database_instance" "db" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { // we only need to check this for SQLSERVER, not mysql/postgres - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr == nil || !dbVersionAttr.IsString() { - // default is postgres - return - } - - if !strings.HasPrefix(dbVersionAttr.Value().AsString(), "SQLSERVER") { + if !resourceBlock.GetAttribute("database_version").StartsWith("SQLSERVER") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has contained database authentication enabled by default", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' has contained database authentication enabled by default", resourceBlock.FullName()) return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Value().AsString() == "contained database authentication" { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { - if valueAttr.Value().AsString() == "on" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has contained database authentication explicitly enabled", resourceBlock.FullName())), - ) - } - // otherwise it's off, awesome - return + if dbFlagBlock.GetAttribute("name").Equals("contained database authentication") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.Equals("on") { + set.AddResult(). + WithDescription("Resource '%s' has contained database authentication explicitly enabled", resourceBlock.FullName()). + WithAttribute(valueAttr) } + // otherwise it's off, awesome + return } } // we didn't find the flag so it must be on by default - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has contained database authentication enabled by default", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has contained database authentication enabled by default", resourceBlock.FullName()). + WithBlock(settingsBlock) }, }) } diff --git a/internal/app/tfsec/rules/google/sql/no_cross_db_ownership_chaining_rule.go b/internal/app/tfsec/rules/google/sql/no_cross_db_ownership_chaining_rule.go index 513f49c845..d255758840 100644 --- a/internal/app/tfsec/rules/google/sql/no_cross_db_ownership_chaining_rule.go +++ b/internal/app/tfsec/rules/google/sql/no_cross_db_ownership_chaining_rule.go @@ -1,9 +1,6 @@ package sql import ( - "fmt" - "strings" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -56,45 +53,33 @@ resource "google_sql_database_instance" "db" { CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { // we only need to check this for SQLSERVER, not mysql/postgres - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr == nil || !dbVersionAttr.IsString() { - // default is postgres - return - } - - if !strings.HasPrefix(dbVersionAttr.Value().AsString(), "SQLSERVER") { + if !resourceBlock.GetAttribute("database_version").StartsWith("SQLSERVER") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has cross-database ownership chaining enabled by default", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' has cross-database ownership chaining enabled by default", resourceBlock.FullName()) return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Value().AsString() == "cross db ownership chaining" { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { - if valueAttr.Value().AsString() == "on" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has cross-database ownership chaining explicitly enabled", resourceBlock.FullName())), - ) - } - // otherwise it's off, awesome - return + if dbFlagBlock.GetAttribute("name").Equals("cross db ownership chaining") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.Equals("on") { + set.AddResult(). + WithDescription("Resource '%s' has cross-database ownership chaining explicitly enabled", resourceBlock.FullName()). + WithAttribute(valueAttr) } + // otherwise it's off, awesome + return } } // we didn't find the flag so it must be on by default - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has cross-database ownership chaining enabled by default", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has cross-database ownership chaining enabled by default", resourceBlock.FullName()). + WithBlock(settingsBlock) }, }) diff --git a/internal/app/tfsec/rules/google/sql/no_public_access_rule.go b/internal/app/tfsec/rules/google/sql/no_public_access_rule.go index 078f509807..95e84245d4 100644 --- a/internal/app/tfsec/rules/google/sql/no_public_access_rule.go +++ b/internal/app/tfsec/rules/google/sql/no_public_access_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -76,42 +74,26 @@ resource "google_sql_database_instance" "postgres" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - // function contents here - settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - return - } - - ipConfigBlock := settingsBlock.GetBlock("ip_configuration") - if ipConfigBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a public ipv4 address assigned by default", resourceBlock.FullName())), - ) + ipConfigBlock := resourceBlock.GetBlock("settings").GetBlock("ip_configuration") + ipv4Attr := ipConfigBlock.GetAttribute("ipv4_enabled") + if ipv4Attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' has a public ipv4 address assigned by default", resourceBlock.FullName()) return } - if ipv4Attr := ipConfigBlock.GetAttribute("ipv4_enabled"); ipv4Attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a public ipv4 address assigned by default", resourceBlock.FullName())), - ) - } else if ipv4Attr.IsTrue() { - set.Add( - result.New(ipConfigBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a public ipv4 address explicitly assigned", resourceBlock.FullName())). - WithAttribute(ipv4Attr), - ) + if ipv4Attr.IsTrue() { + set.AddResult(). + WithDescription("Resource '%s' has a public ipv4 address explicitly assigned", resourceBlock.FullName()). + WithAttribute(ipv4Attr) return } for _, authorizedNetworkBlock := range ipConfigBlock.GetBlocks("authorized_networks") { - if cidrAttr := authorizedNetworkBlock.GetAttribute("value"); cidrAttr != nil && cidrAttr.IsString() && cidr.IsOpen(cidrAttr) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' authorizes access from the public internet", resourceBlock.FullName())). - WithAttribute(cidrAttr), - ) + if cidrAttr := authorizedNetworkBlock.GetAttribute("value"); cidr.IsOpen(cidrAttr) { + set.AddResult(). + WithDescription("Resource '%s' authorizes access from the public internet", resourceBlock.FullName()). + WithAttribute(cidrAttr) } } diff --git a/internal/app/tfsec/rules/google/sql/no_public_access_rule_test.go b/internal/app/tfsec/rules/google/sql/no_public_access_rule_test.go index 138df4077e..d0dadb8a6b 100644 --- a/internal/app/tfsec/rules/google/sql/no_public_access_rule_test.go +++ b/internal/app/tfsec/rules/google/sql/no_public_access_rule_test.go @@ -29,7 +29,7 @@ resource "google_sql_database_instance" "postgres" { ipv4_enabled = true } } - } +} `, mustIncludeResultCode: expectedCode, }, @@ -41,12 +41,37 @@ resource "google_sql_database_instance" "postgres" { database_version = "POSTGRES_11" settings { - tier = "db-f1-micro" + tier = "db-f1-micro" - ip_configuration { - } + ip_configuration { + } } +} +`, + mustIncludeResultCode: expectedCode, + }, + { + name: "check detects issue with public ipv4 address being assigned by default", + source: ` +resource "google_sql_database_instance" "postgres" { + name = "postgres-instance-a" + database_version = "POSTGRES_11" + + settings { + tier = "db-f1-micro" } +} +`, + mustIncludeResultCode: expectedCode, + }, + { + name: "check detects issue with public ipv4 address being assigned by default", + source: ` +resource "google_sql_database_instance" "postgres" { + name = "postgres-instance-a" + database_version = "POSTGRES_11" + +} `, mustIncludeResultCode: expectedCode, }, diff --git a/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule.go index d83962db59..6ef34619dd 100644 --- a/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule.go +++ b/internal/app/tfsec/rules/google/sql/pg_log_checkpoints_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -62,38 +60,31 @@ resource "google_sql_database_instance" "db" { RequiredLabels: []string{"google_sql_database_instance"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") { + if !resourceBlock.GetAttribute("database_version").StartsWith("POSTGRES") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log checkpoints", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is not configured to log checkpoints", resourceBlock.FullName()) return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_checkpoints") { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { - if valueAttr.Value().AsString() == "off" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is configured not to log checkpoints", resourceBlock.FullName())), - ) - } - return + if dbFlagBlock.GetAttribute("name").Equals("log_checkpoints") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.Equals("off") { + set.AddResult(). + WithDescription("Resource '%s' is configured not to log checkpoints", resourceBlock.FullName()). + WithAttribute(valueAttr) } + return } } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log checkpoints", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is not configured to log checkpoints", resourceBlock.FullName()). + WithBlock(settingsBlock) }, }) diff --git a/internal/app/tfsec/rules/google/sql/pg_log_connections_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_connections_rule.go index 4757d87b07..90599873f3 100644 --- a/internal/app/tfsec/rules/google/sql/pg_log_connections_rule.go +++ b/internal/app/tfsec/rules/google/sql/pg_log_connections_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -62,38 +60,31 @@ resource "google_sql_database_instance" "db" { RequiredLabels: []string{"google_sql_database_instance"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") { + if !resourceBlock.GetAttribute("database_version").StartsWith("POSTGRES") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log connections", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is not configured to log connections", resourceBlock.FullName()) return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_connections") { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { - if valueAttr.Value().AsString() == "off" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is configured not to log connections", resourceBlock.FullName())), - ) - } - return + if dbFlagBlock.GetAttribute("name").Equals("log_connections") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.Equals("off") { + set.AddResult(). + WithDescription("Resource '%s' is configured not to log connections", resourceBlock.FullName()). + WithAttribute(valueAttr) } + return } } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log connections", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is not configured to log connections", resourceBlock.FullName()). + WithBlock(settingsBlock) }, }) diff --git a/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule.go index d69c7c907f..1055e48555 100644 --- a/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule.go +++ b/internal/app/tfsec/rules/google/sql/pg_log_disconnections_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -62,38 +60,31 @@ resource "google_sql_database_instance" "db" { RequiredLabels: []string{"google_sql_database_instance"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") { + if !resourceBlock.GetAttribute("database_version").StartsWith("POSTGRES") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log disconnections", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is not configured to log disconnections", resourceBlock.FullName()) return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_disconnections") { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { - if valueAttr.Value().AsString() == "off" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is configured not to log disconnections", resourceBlock.FullName())), - ) - } - return + if dbFlagBlock.GetAttribute("name").Equals("log_disconnections") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.Equals("off") { + set.AddResult(). + WithDescription("Resource '%s' is configured not to log disconnections", resourceBlock.FullName()). + WithAttribute(valueAttr) } + return } } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log disconnections", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is not configured to log disconnections", resourceBlock.FullName()). + WithBlock(settingsBlock) }, }) diff --git a/internal/app/tfsec/rules/google/sql/pg_log_errors_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_errors_rule.go index e87c675827..8a130ffb4f 100644 --- a/internal/app/tfsec/rules/google/sql/pg_log_errors_rule.go +++ b/internal/app/tfsec/rules/google/sql/pg_log_errors_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -63,25 +61,18 @@ resource "google_sql_database_instance" "db" { RequiredLabels: []string{"google_sql_database_instance"}, DefaultSeverity: severity.Low, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") { - return - } - - settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { + if !resourceBlock.GetAttribute("database_version").StartsWith("POSTGRES") { return } - for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_min_messages") { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { + for _, dbFlagBlock := range resourceBlock.GetBlock("settings").GetBlocks("database_flags") { + if dbFlagBlock.GetAttribute("name").Equals("log_min_messages") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.IsString() { switch valueAttr.Value().AsString() { case "FATAL", "PANIC", "LOG": - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has a minimum log severity set which ignores errors", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' has a minimum log severity set which ignores errors", resourceBlock.FullName()). + WithAttribute(valueAttr) } } } diff --git a/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule.go b/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule.go index bd54b924a6..f8c9b7cfdb 100644 --- a/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule.go +++ b/internal/app/tfsec/rules/google/sql/pg_log_lock_waits_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -62,38 +60,31 @@ resource "google_sql_database_instance" "db" { RequiredLabels: []string{"google_sql_database_instance"}, DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") { + if !resourceBlock.GetAttribute("database_version").StartsWith("POSTGRES") { return } settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log lock waits", resourceBlock.FullName())), - ) + if settingsBlock.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' is not configured to log lock waits", resourceBlock.FullName()) return } for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_lock_waits") { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { - if valueAttr.Value().AsString() == "off" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is configured not to log lock waits", resourceBlock.FullName())), - ) - } - return + if dbFlagBlock.GetAttribute("name").Equals("log_lock_waits") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.Equals("off") { + set.AddResult(). + WithDescription("Resource '%s' is configured not to log lock waits", resourceBlock.FullName()). + WithAttribute(valueAttr) } + return } } - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is not configured to log lock waits", resourceBlock.FullName())), - ) + set.AddResult(). + WithDescription("Resource '%s' is not configured to log lock waits", resourceBlock.FullName()). + WithBlock(settingsBlock) }, }) diff --git a/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule.go b/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule.go index 715970655d..6963e0ecba 100644 --- a/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule.go +++ b/internal/app/tfsec/rules/google/sql/pg_no_min_statement_logging_rule.go @@ -1,8 +1,6 @@ package sql import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -63,24 +61,16 @@ resource "google_sql_database_instance" "db" { DefaultSeverity: severity.Low, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { dbVersionAttr := resourceBlock.GetAttribute("database_version") - if dbVersionAttr != nil && dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") { - return - } - - settingsBlock := resourceBlock.GetBlock("settings") - if settingsBlock == nil { + if dbVersionAttr.IsString() && !dbVersionAttr.StartsWith("POSTGRES") { return } - for _, dbFlagBlock := range settingsBlock.GetBlocks("database_flags") { - if nameAttr := dbFlagBlock.GetAttribute("name"); nameAttr != nil && nameAttr.IsString() && nameAttr.Equals("log_min_duration_statement") { - if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr != nil && valueAttr.IsString() { - if valueAttr.Value().AsString() != "-1" { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' causes database query statements to be logged", resourceBlock.FullName())), - ) - } + for _, dbFlagBlock := range resourceBlock.GetBlock("settings").GetBlocks("database_flags") { + if dbFlagBlock.GetAttribute("name").Equals("log_min_duration_statement") { + if valueAttr := dbFlagBlock.GetAttribute("value"); valueAttr.NotEqual("-1") { + set.AddResult(). + WithDescription("Resource '%s' causes database query statements to be logged", resourceBlock.FullName()). + WithAttribute(valueAttr) } } } diff --git a/internal/app/tfsec/rules/google/storage/enable_uniform_bucket_level_access.go b/internal/app/tfsec/rules/google/storage/enable_uniform_bucket_level_access.go index cdd3992211..f05ea2228b 100644 --- a/internal/app/tfsec/rules/google/storage/enable_uniform_bucket_level_access.go +++ b/internal/app/tfsec/rules/google/storage/enable_uniform_bucket_level_access.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -80,17 +78,13 @@ resource "google_storage_bucket" "static-site" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("uniform_bucket_level_access"); attr == nil { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' does not have uniform_bucket_level_access enabled.", resourceBlock.FullName())), - ) - } else if attr.Value().IsKnown() && !attr.IsTrue() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' has uniform_bucket_level_access explicitly disabled.", resourceBlock.FullName())). - WithAttribute(attr), - ) + if attr := resourceBlock.GetAttribute("uniform_bucket_level_access"); attr.IsNil() { + set.AddResult(). + WithDescription("Resource '%s' does not have uniform_bucket_level_access enabled.", resourceBlock.FullName()) + } else if attr.Value().IsKnown() && attr.IsFalse() { + set.AddResult(). + WithDescription("Resource '%s' has uniform_bucket_level_access explicitly disabled.", resourceBlock.FullName()). + WithAttribute(attr) } }, }) diff --git a/internal/app/tfsec/rules/google/storage/no_public_access_rule.go b/internal/app/tfsec/rules/google/storage/no_public_access_rule.go index 60c98c2aa5..3310d6eb61 100644 --- a/internal/app/tfsec/rules/google/storage/no_public_access_rule.go +++ b/internal/app/tfsec/rules/google/storage/no_public_access_rule.go @@ -53,22 +53,18 @@ resource "google_storage_bucket_iam_binding" "binding" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if memberAttr := resourceBlock.GetAttribute("member"); memberAttr != nil && memberAttr.IsString() { + if memberAttr := resourceBlock.GetAttribute("member"); memberAttr.IsString() { if googleIAMMemberIsExternal(memberAttr.Value().AsString()) { - set.Add(result.New(resourceBlock). - WithDescription("Resource '%s' allows public access via member attribute."). - WithAttribute(memberAttr), - ) + set.AddResult().WithDescription("Resource '%s' allows public access via member attribute.", resourceBlock.FullName()). + WithAttribute(memberAttr) } } - if membersAttr := resourceBlock.GetAttribute("members"); membersAttr != nil { + if membersAttr := resourceBlock.GetAttribute("members"); membersAttr.IsNotNil() { for _, member := range membersAttr.ValueAsStrings() { if googleIAMMemberIsExternal(member) { - set.Add(result.New(resourceBlock). - WithDescription("Resource '%s' allows public access via members attribute."). - WithAttribute(membersAttr), - ) + set.AddResult().WithDescription("Resource '%s' allows public access via members attribute.", resourceBlock.FullName()). + WithAttribute(membersAttr) } } } diff --git a/internal/app/tfsec/rules/openstack/compute/no_plaintext_password_rule.go b/internal/app/tfsec/rules/openstack/compute/no_plaintext_password_rule.go index 9a8397fc11..6c88109655 100644 --- a/internal/app/tfsec/rules/openstack/compute/no_plaintext_password_rule.go +++ b/internal/app/tfsec/rules/openstack/compute/no_plaintext_password_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -66,13 +64,10 @@ resource "openstack_compute_instance_v2" "good_example" { return } - adminPassAttr := resourceBlock.GetAttribute("admin_pass") - if adminPassAttr.IsString() && !adminPassAttr.IsEmpty() { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' specifies a plain text password", resourceBlock.FullName())). - WithAttribute(adminPassAttr), - ) + if adminPassAttr := resourceBlock.GetAttribute("admin_pass"); adminPassAttr.IsString() && !adminPassAttr.IsEmpty() { + set.AddResult(). + WithDescription("Resource '%s' specifies a plain text password", resourceBlock.FullName()). + WithAttribute(adminPassAttr) } }, }) diff --git a/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go b/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go index 392b15fb34..160e9b58ac 100644 --- a/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go +++ b/internal/app/tfsec/rules/openstack/fw/no_public_access_rule.go @@ -59,36 +59,34 @@ resource "openstack_fw_rule_v1" "rule_1" { DefaultSeverity: severity.Medium, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if enabledAttr := resourceBlock.GetAttribute("enabled"); enabledAttr != nil && enabledAttr.IsFalse() { + if resourceBlock.GetAttribute("enabled").IsFalse() { return } - if actionAttr := resourceBlock.GetAttribute("action"); actionAttr != nil && actionAttr.Equals("deny") { + if resourceBlock.GetAttribute("action").Equals("deny") { return } - if destinationIP := resourceBlock.GetAttribute("destination_ip_address"); destinationIP == nil || destinationIP.Equals("") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a firewall rule with no restriction on destination IP", resourceBlock)), - ) + if destinationIP := resourceBlock.GetAttribute("destination_ip_address"); destinationIP.IsNil() || destinationIP.Equals("") { + set.AddResult(). + WithDescription( + fmt.Sprintf("Resource '%s' defines a firewall rule with no restriction on destination IP", resourceBlock), + ). + WithAttribute(destinationIP) } else if cidr.IsOpen(destinationIP) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a firewall rule with a public destination CIDR", resourceBlock)), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a firewall rule with a public destination CIDR", resourceBlock). + WithAttribute(destinationIP) } - if sourceIP := resourceBlock.GetAttribute("source_ip_address"); sourceIP == nil || sourceIP.Equals("") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a firewall rule with no restriction on source IP", resourceBlock)), - ) + if sourceIP := resourceBlock.GetAttribute("source_ip_address"); sourceIP.IsNil() || sourceIP.Equals("") { + set.AddResult(). + WithDescription("Resource '%s' defines a firewall rule with no restriction on source IP", resourceBlock). + WithAttribute(sourceIP) } else if cidr.IsOpen(sourceIP) { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' defines a firewall rule with a public source CIDR", resourceBlock)), - ) + set.AddResult(). + WithDescription("Resource '%s' defines a firewall rule with a public source CIDR", resourceBlock). + WithAttribute(sourceIP) } }, }) diff --git a/internal/app/tfsec/rules/oracle/compute/no_public_ip_rule.go b/internal/app/tfsec/rules/oracle/compute/no_public_ip_rule.go index 2f94d0354e..3866f6cd46 100644 --- a/internal/app/tfsec/rules/oracle/compute/no_public_ip_rule.go +++ b/internal/app/tfsec/rules/oracle/compute/no_public_ip_rule.go @@ -1,8 +1,6 @@ package compute import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -53,14 +51,10 @@ resource "opc_compute_ip_address_reservation" "good_example" { RequiredLabels: []string{"opc_compute_ip_address_reservation"}, DefaultSeverity: severity.Critical, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - if attr := resourceBlock.GetAttribute("ip_address_pool"); attr != nil { - if attr.Equals("public-ippool") { - set.Add( - result.New(resourceBlock). - WithDescription(fmt.Sprintf("Resource '%s' is using an IP from a public IP pool", resourceBlock.FullName())). - WithAttribute(attr), - ) - } + if attr := resourceBlock.GetAttribute("ip_address_pool"); attr.Equals("public-ippool") { + set.AddResult(). + WithDescription("Resource '%s' is using an IP from a public IP pool", resourceBlock.FullName()). + WithAttribute(attr) } }, }) diff --git a/internal/app/tfsec/scanner/scanner.go b/internal/app/tfsec/scanner/scanner.go index 7e1011f4f5..ea27b1f1df 100644 --- a/internal/app/tfsec/scanner/scanner.go +++ b/internal/app/tfsec/scanner/scanner.go @@ -1,8 +1,6 @@ package scanner import ( - "fmt" - "github.com/aquasecurity/tfsec/pkg/result" "github.com/aquasecurity/tfsec/pkg/severity" @@ -67,7 +65,7 @@ func (scanner *Scanner) Scan(blocks []block.Block) []result.Result { res := result.New(checkBlock). WithLegacyRuleID(r.LegacyID). WithRuleID(r.ID()). - WithDescription(fmt.Sprintf("Resource '%s' passed check: %s", checkBlock.FullName(), r.Documentation.Summary)). + WithDescription("Resource '%s' passed check: %s", checkBlock.FullName(), r.Documentation.Summary). WithStatus(result.Passed). WithImpact(r.Documentation.Impact). WithResolution(r.Documentation.Resolution). @@ -83,7 +81,7 @@ func (scanner *Scanner) Scan(blocks []block.Block) []result.Result { metrics.Add(metrics.IgnoredChecks, 1) debug.Log("Ignoring '%s'", ruleResult.RuleID) } else { - results = append(results, ruleResult) + results = append(results, *ruleResult) } } diff --git a/internal/app/tfsec/test/ignore_test.go b/internal/app/tfsec/test/ignore_test.go index ebfc47e6af..3817d0ca68 100644 --- a/internal/app/tfsec/test/ignore_test.go +++ b/internal/app/tfsec/test/ignore_test.go @@ -93,9 +93,8 @@ func Test_IgnoreSpecific(t *testing.T) { RequiredLabels: []string{"bad"}, DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - set.Add( - result.New(resourceBlock).WithDescription("example problem"), - ) + set.AddResult(). + WithDescription("example problem") }, }) @@ -107,9 +106,8 @@ func Test_IgnoreSpecific(t *testing.T) { RequiredLabels: []string{"bad"}, DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { - set.Add( - result.New(resourceBlock).WithDescription("example problem"), - ) + set.AddResult(). + WithDescription("example problem") }, }) @@ -198,6 +196,17 @@ resource "aws_security_group_rule" "my-rule" { assert.Len(t, results, 0) } +func Test_IgnoreInline(t *testing.T) { + results := testutil.ScanHCL(` + resource "aws_instance" "sample" { + metadata_options { + http_tokens = "optional" # tfsec:ignore:aws-ec2-enforce-http-token-imds + } + } + `, t) + assert.Len(t, results, 0) +} + func Test_IgnoreIgnoreWithExpiryAndWorkspaceButWrongWorkspaceSupplied(t *testing.T) { results := testutil.ScanHCL(` # tfsec:ignore:AWS006:exp:2221-01-02 #tfsec:ignore:AWS018:ws:otherworkspace diff --git a/internal/app/tfsec/test/module_scan_test.go b/internal/app/tfsec/test/module_scan_test.go index e554df8bce..0f6cd4ac49 100644 --- a/internal/app/tfsec/test/module_scan_test.go +++ b/internal/app/tfsec/test/module_scan_test.go @@ -44,9 +44,8 @@ resource "problem" "x" { DefaultSeverity: severity.High, CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { if resourceBlock.GetAttribute("bad") != nil { - set.Add( - result.New(resourceBlock).WithDescription("example problem"), - ) + set.AddResult(). + WithDescription("example problem") } }, }) diff --git a/internal/app/tfsec/test/wildcard_test.go b/internal/app/tfsec/test/wildcard_test.go index 60036400c8..5366c42a7b 100644 --- a/internal/app/tfsec/test/wildcard_test.go +++ b/internal/app/tfsec/test/wildcard_test.go @@ -67,9 +67,8 @@ func Test_WildcardMatchingOnRequiredLabels(t *testing.T) { RequiredLabels: []string{test.pattern}, DefaultSeverity: severity.High, CheckFunc: func(set result.Set, rootBlock block.Block, ctx *hclcontext.Context) { - set.Add( - result.New(rootBlock).WithDescription(fmt.Sprintf("Custom check failed for resource %s.", rootBlock.FullName())), - ) + set.AddResult(). + WithDescription("Custom check failed for resource %s.", rootBlock.FullName()) }, }) diff --git a/internal/app/tfsec/testutil/util.go b/internal/app/tfsec/testutil/util.go index e2e6fd8859..53f576dba5 100644 --- a/internal/app/tfsec/testutil/util.go +++ b/internal/app/tfsec/testutil/util.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "testing" "github.com/aquasecurity/tfsec/pkg/result" @@ -53,7 +54,6 @@ func CreateTestFile(filename, contents string) string { } func AssertCheckCode(t *testing.T, includeCode string, excludeCode string, results []result.Result, messages ...string) { - var foundInclude bool var foundExclude bool @@ -73,6 +73,10 @@ func AssertCheckCode(t *testing.T, includeCode string, excludeCode string, resul if includeCode != "" { assert.True(t, foundInclude, fmt.Sprintf("res with code '%s' was not found but should have been", includeCode)) } + + if t.Failed() { + t.Log(strings.ReplaceAll(t.Name(), "_", " ")) + } } func CreateTestFileWithModule(contents string, moduleContents string) string { diff --git a/pkg/result/ignores.go b/pkg/result/ignores.go index cd43e1fe61..415fce7974 100644 --- a/pkg/result/ignores.go +++ b/pkg/result/ignores.go @@ -24,7 +24,6 @@ func (res *Result) IsIgnored(workspace string) bool { // ignore rule matches! return true } - // no ignore rule found for this result return false } diff --git a/pkg/result/result.go b/pkg/result/result.go index 0b94140e62..b27ab57089 100644 --- a/pkg/result/result.go +++ b/pkg/result/result.go @@ -63,7 +63,7 @@ func (r *Result) Range() block.Range { if r.attribute != nil { return r.attribute.Range() } - return r.blocks[0].Range() + return r.blocks[len(r.blocks)-1].Range() } func (r *Result) HashCode() string { @@ -122,8 +122,13 @@ func (r *Result) WithBlock(block block.Block) *Result { return r } -func (r *Result) WithDescription(description string) *Result { - r.Description = description +func (r *Result) WithDescription(description string, parts ...interface{}) *Result { + if len(parts) == 0 { + r.Description = description + } else { + r.Description = fmt.Sprintf(description, parts...) + } + return r } @@ -139,6 +144,10 @@ func (r *Result) WithStatus(status Status) *Result { func (r *Result) WithAttribute(attr block.Attribute) *Result { + if attr.IsNil() { + return r + } + r.attribute = attr var raw string diff --git a/pkg/result/set.go b/pkg/result/set.go index 8832245bbf..c24bf0fd9c 100644 --- a/pkg/result/set.go +++ b/pkg/result/set.go @@ -1,9 +1,12 @@ package result -import "github.com/aquasecurity/tfsec/pkg/provider" +import ( + "github.com/aquasecurity/tfsec/internal/app/tfsec/block" + "github.com/aquasecurity/tfsec/pkg/provider" +) type Set interface { - Add(result *Result) + AddResult() *Result WithRuleID(id string) Set WithLegacyRuleID(id string) Set WithRuleSummary(description string) Set @@ -11,26 +14,29 @@ type Set interface { WithImpact(impact string) Set WithResolution(resolution string) Set WithLinks(links []string) Set - All() []Result + All() []*Result } -func NewSet() *resultSet { - return &resultSet{} +func NewSet(resourceBlock block.Block) *resultSet { + return &resultSet{ + resourceBlock: resourceBlock, + } } type resultSet struct { - results []Result - ruleID string - legacyID string - ruleSummary string - ruleProvider provider.Provider - impact string - resolution string - links []string + resourceBlock block.Block + results []*Result + ruleID string + legacyID string + ruleSummary string + ruleProvider provider.Provider + impact string + resolution string + links []string } -func (s *resultSet) Add(result *Result) { - result. +func (s *resultSet) AddResult() *Result { + result := New(s.resourceBlock). WithRuleID(s.ruleID). WithLegacyRuleID(s.legacyID). WithRuleSummary(s.ruleSummary). @@ -38,10 +44,11 @@ func (s *resultSet) Add(result *Result) { WithResolution(s.resolution). WithRuleProvider(s.ruleProvider). WithLinks(s.links) - s.results = append(s.results, *result) + s.results = append(s.results, result) + return result } -func (s *resultSet) All() []Result { +func (s *resultSet) All() []*Result { return s.results } diff --git a/pkg/rule/check.go b/pkg/rule/check.go index 1953ac220d..f823a1a9d3 100644 --- a/pkg/rule/check.go +++ b/pkg/rule/check.go @@ -17,7 +17,7 @@ import ( ) // CheckRule the provided HCL block against the rule -func CheckRule(r *Rule, block block.Block, ctx *hclcontext.Context, ignoreErrors bool) result.Set { +func CheckRule(r *Rule, resourceBlock block.Block, ctx *hclcontext.Context, ignoreErrors bool) result.Set { if ignoreErrors { defer func() { if err := recover(); err != nil { @@ -35,7 +35,7 @@ func CheckRule(r *Rule, block block.Block, ctx *hclcontext.Context, ignoreErrors links = append(links, r.Documentation.Links...) - resultSet := result.NewSet(). + resultSet := result.NewSet(resourceBlock). WithRuleID(r.ID()). WithLegacyRuleID(r.LegacyID). WithRuleSummary(r.Documentation.Summary). @@ -44,7 +44,7 @@ func CheckRule(r *Rule, block block.Block, ctx *hclcontext.Context, ignoreErrors WithRuleProvider(r.Provider). WithLinks(links) - r.CheckFunc(resultSet, block, ctx) + r.CheckFunc(resultSet, resourceBlock, ctx) return resultSet }