diff --git a/pkg/providers/aws/iam/wildcards.go b/pkg/providers/aws/iam/wildcards.go index 716036b9f..cae7b410c 100755 --- a/pkg/providers/aws/iam/wildcards.go +++ b/pkg/providers/aws/iam/wildcards.go @@ -645,8 +645,10 @@ var allowedActionsForResourceWildcards = []string{ "applicationinsights:UpdateLogPattern", "logs:CancelExportTask", "logs:CreateLogDelivery [permission only]", + "logs:CreateLogGroup", "logs:DeleteDestination", "logs:DeleteLogDelivery [permission only]", + "logs:DeleteLogGroup", "logs:DeleteQueryDefinition", "logs:DeleteResourcePolicy", "logs:DescribeDestinations", diff --git a/rules/cloud/policies/aws/iam/no_policy_wildcards.go b/rules/cloud/policies/aws/iam/no_policy_wildcards.go index e51ff0f27..bdfda144c 100755 --- a/rules/cloud/policies/aws/iam/no_policy_wildcards.go +++ b/rules/cloud/policies/aws/iam/no_policy_wildcards.go @@ -2,6 +2,7 @@ package iam import ( "fmt" + "regexp" "strings" "github.com/aquasecurity/defsec/pkg/framework" @@ -20,6 +21,11 @@ import ( "github.com/liamg/iamgo" ) +var ( + //arn:aws:logs:us-west-2:123456789012:log-group:SampleLogGroupName:* + cloudwatchLogStreamResourceRegex = regexp.MustCompile(`^arn:aws:logs:.*:.+:log-group:.+:\*`) +) + var CheckNoPolicyWildcards = rules.Register( scan.Rule{ AVDID: "AVD-AWS-0057", @@ -123,6 +129,10 @@ func checkStatement(src iam.Document, statement iamgo.Statement, results scan.Re if strings.HasSuffix(resource, "/*") && strings.HasPrefix(resource, "arn:aws:s3") { continue } + if cloudwatchLogStreamResourceRegex.MatchString(resource) { + continue + } + results.Add( fmt.Sprintf("IAM policy document uses sensitive action '%s' on wildcarded resource '%s'", action, resources[0]), src.MetadataFromIamGo(statement.Range(), r), diff --git a/rules/cloud/policies/aws/iam/no_policy_wildcards_test.go b/rules/cloud/policies/aws/iam/no_policy_wildcards_test.go index 0af393ee1..61d9eaec5 100644 --- a/rules/cloud/policies/aws/iam/no_policy_wildcards_test.go +++ b/rules/cloud/policies/aws/iam/no_policy_wildcards_test.go @@ -182,6 +182,122 @@ func TestCheckNoPolicyWildcards(t *testing.T) { }, expected: false, }, + { + name: "IAM policy with wildcard resource for cloudwatch log stream", + input: iam.IAM{ + Policies: []iam.Policy{ + { + Metadata: defsecTypes.NewTestMetadata(), + Document: func() iam.Document { + + builder := iamgo.NewPolicyBuilder() + builder.WithVersion("2012-10-17") + + sb := iamgo.NewStatementBuilder() + sb.WithEffect(iamgo.EffectAllow) + sb.WithActions([]string{"logs:CreateLogStream"}) + sb.WithResources([]string{"arn:aws:logs:us-west-2:123456789012:log-group:SampleLogGroupName:*"}) + sb.WithAWSPrincipals([]string{"arn:aws:iam::1234567890:root"}) + + builder.WithStatement(sb.Build()) + + return iam.Document{ + Parsed: builder.Build(), + Metadata: defsecTypes.NewTestMetadata(), + } + }(), + Builtin: defsecTypes.Bool(false, defsecTypes.NewTestMetadata()), + }, + }, + Roles: []iam.Role{ + { + Metadata: defsecTypes.NewTestMetadata(), + Policies: []iam.Policy{ + { + Metadata: defsecTypes.NewTestMetadata(), + Document: func() iam.Document { + + builder := iamgo.NewPolicyBuilder() + builder.WithVersion("2012-10-17") + + sb := iamgo.NewStatementBuilder() + sb.WithEffect(iamgo.EffectAllow) + sb.WithActions([]string{"sts:AssumeRole"}) + sb.WithServicePrincipals([]string{"logs.amazonaws.com"}) + + builder.WithStatement(sb.Build()) + + return iam.Document{ + Parsed: builder.Build(), + Metadata: defsecTypes.NewTestMetadata(), + } + }(), + Builtin: defsecTypes.Bool(false, defsecTypes.NewTestMetadata()), + }, + }, + }, + }, + }, + expected: false, + }, + { + name: "IAM policy with wildcard resource for cloudwatch log stream", + input: iam.IAM{ + Policies: []iam.Policy{ + { + Metadata: defsecTypes.NewTestMetadata(), + Document: func() iam.Document { + + builder := iamgo.NewPolicyBuilder() + builder.WithVersion("2012-10-17") + + sb := iamgo.NewStatementBuilder() + sb.WithEffect(iamgo.EffectAllow) + sb.WithActions([]string{"logs:CreateLogStream"}) + sb.WithResources([]string{"*"}) + sb.WithAWSPrincipals([]string{"arn:aws:iam::1234567890:root"}) + + builder.WithStatement(sb.Build()) + + return iam.Document{ + Parsed: builder.Build(), + Metadata: defsecTypes.NewTestMetadata(), + } + }(), + Builtin: defsecTypes.Bool(false, defsecTypes.NewTestMetadata()), + }, + }, + Roles: []iam.Role{ + { + Metadata: defsecTypes.NewTestMetadata(), + Policies: []iam.Policy{ + { + Metadata: defsecTypes.NewTestMetadata(), + Document: func() iam.Document { + + builder := iamgo.NewPolicyBuilder() + builder.WithVersion("2012-10-17") + + sb := iamgo.NewStatementBuilder() + sb.WithEffect(iamgo.EffectAllow) + sb.WithActions([]string{"sts:AssumeRole"}) + sb.WithServicePrincipals([]string{"logs.amazonaws.com"}) + + builder.WithStatement(sb.Build()) + + return iam.Document{ + Parsed: builder.Build(), + Metadata: defsecTypes.NewTestMetadata(), + } + }(), + Builtin: defsecTypes.Bool(false, defsecTypes.NewTestMetadata()), + }, + }, + }, + }, + }, + expected: true, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) {