Skip to content

Commit

Permalink
feat(misconf): support for policy and bucket grants (#7284)
Browse files Browse the repository at this point in the history
Signed-off-by: nikpivkin <[email protected]>
  • Loading branch information
nikpivkin authored Aug 6, 2024
1 parent a4180bd commit a817fae
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 0 deletions.
35 changes: 35 additions & 0 deletions pkg/iac/adapters/cloudformation/aws/s3/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (
"strings"

s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/liamg/iamgo"

"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/s3"
"github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser"
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
Expand Down Expand Up @@ -37,6 +39,7 @@ func getBuckets(cfFile parser.FileContext) []s3.Bucket {
Website: getWebsite(r),
BucketLocation: iacTypes.String("", r.Metadata()),
Objects: nil,
BucketPolicies: getBucketPolicies(cfFile, r),
}

buckets = append(buckets, s3b)
Expand Down Expand Up @@ -156,3 +159,35 @@ func getWebsite(r *parser.Resource) *s3.Website {
}
}
}

func getBucketPolicies(fctx parser.FileContext, r *parser.Resource) []iam.Policy {

var policies []iam.Policy
for _, bucketPolicy := range fctx.GetResourcesByType("AWS::S3::BucketPolicy") {
bucket := bucketPolicy.GetStringProperty("Bucket")
if bucket.NotEqualTo(r.GetStringProperty("BucketName").Value()) && bucket.NotEqualTo(r.ID()) {
continue
}

doc := bucketPolicy.GetProperty("PolicyDocument")
if doc.IsNil() {
continue
}

parsed, err := iamgo.Parse(doc.GetJsonBytes())
if err != nil {
continue
}
policies = append(policies, iam.Policy{
Metadata: doc.Metadata(),
Name: iacTypes.StringDefault("", doc.Metadata()),
Document: iam.Document{
Metadata: doc.Metadata(),
Parsed: *parsed,
},
Builtin: iacTypes.Bool(false, doc.Metadata()),
})
}

return policies
}
33 changes: 33 additions & 0 deletions pkg/iac/adapters/cloudformation/aws/s3/s3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package s3
import (
"testing"

"github.com/liamg/iamgo"

"github.com/aquasecurity/trivy/pkg/iac/adapters/cloudformation/testutil"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/s3"
"github.com/aquasecurity/trivy/pkg/iac/types"
)
Expand Down Expand Up @@ -57,6 +60,19 @@ Resources:
Status: Enabled
WebsiteConfiguration:
IndexDocument: index.html
SampleBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Bucket
PolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- 's3:GetObject'
Effect: Allow
Resource: !Join
- 'arn:aws:s3:::testbucket/*'
Principal: '*'
`,
expected: s3.S3{
Buckets: []s3.Bucket{
Expand Down Expand Up @@ -91,6 +107,23 @@ Resources:
Enabled: types.BoolTest(true),
},
Website: &s3.Website{},
BucketPolicies: []iam.Policy{
{
Document: iam.Document{
Parsed: iamgo.NewPolicyBuilder().
WithStatement(
iamgo.NewStatementBuilder().
WithActions([]string{"s3:GetObject"}).
WithAllPrincipals(true).
WithEffect("Allow").
WithResources([]string{"arn:aws:s3:::testbucket/*"}).
Build(),
).
WithVersion("2012-10-17T00:00:00Z").
Build(),
},
},
},
},
},
},
Expand Down
54 changes: 54 additions & 0 deletions pkg/iac/adapters/terraform/aws/s3/adapt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ func Test_Adapt(t *testing.T) {
resource "aws_s3_bucket_acl" "example" {
bucket = aws_s3_bucket.example.id
acl = "private"
access_control_policy {
grant {
grantee {
type = "Group"
uri = "http://acs.amazonaws.com/groups/s3/LogDelivery"
}
permission = "READ_ACP"
}
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
Expand Down Expand Up @@ -250,6 +259,51 @@ func Test_Adapt(t *testing.T) {
TargetBucket: iacTypes.String("aws_s3_bucket.example", iacTypes.NewTestMetadata()),
},
ACL: iacTypes.String("private", iacTypes.NewTestMetadata()),
Grants: []s3.Grant{
{
Metadata: iacTypes.NewTestMetadata(),
Grantee: s3.Grantee{
Type: iacTypes.StringTest("Group"),
URI: iacTypes.StringTest("http://acs.amazonaws.com/groups/s3/LogDelivery"),
},
Permissions: iacTypes.StringValueList{
iacTypes.StringTest("READ_ACP"),
},
},
},
},
},
},
},
{
name: "bucket with grants",
terraform: `
resource "aws_s3_bucket" "this" {
bucket = "test"
grant {
type = "Group"
uri = "http://acs.amazonaws.com/groups/s3/LogDelivery"
permissions = ["FULL_CONTROL"]
}
}
`,
expected: s3.S3{
Buckets: []s3.Bucket{
{
Name: iacTypes.StringTest("test"),
ACL: iacTypes.StringTest("private"),
Grants: []s3.Grant{
{
Grantee: s3.Grantee{
Type: iacTypes.StringTest("Group"),
URI: iacTypes.StringTest("http://acs.amazonaws.com/groups/s3/LogDelivery"),
},
Permissions: iacTypes.StringValueList{
iacTypes.StringTest("FULL_CONTROL"),
},
},
},
},
},
},
Expand Down
50 changes: 50 additions & 0 deletions pkg/iac/adapters/terraform/aws/s3/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func (a *adapter) adaptBuckets() []s3.Bucket {
Versioning: getVersioning(block, a),
Logging: getLogging(block, a),
ACL: getBucketAcl(block, a),
Grants: getGrants(block, a),
AccelerateConfigurationStatus: getAccelerateStatus(block, a),
BucketLocation: block.GetAttribute("region").AsStringValueOrDefault("", block),
LifecycleConfiguration: getLifecycle(block, a),
Expand Down Expand Up @@ -193,6 +194,55 @@ func getBucketAcl(block *terraform.Block, a *adapter) iacTypes.StringValue {
return iacTypes.StringDefault("private", block.GetMetadata())
}

func getGrants(block *terraform.Block, a *adapter) []s3.Grant {
if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_acl", func(resource *terraform.Block) []s3.Grant {
var grants []s3.Grant

if acessControlPolicy := resource.GetBlock("access_control_policy"); acessControlPolicy.IsNotNil() {
for _, grantBlock := range acessControlPolicy.GetBlocks("grant") {
grant := s3.Grant{
Metadata: grantBlock.GetMetadata(),
Permissions: iacTypes.StringValueList{
grantBlock.GetAttribute("permission").AsStringValueOrDefault("", grantBlock),
},
}

if granteeBlock := grantBlock.GetBlock("grantee"); granteeBlock.IsNotNil() {
grant.Grantee = s3.Grantee{
Metadata: granteeBlock.GetMetadata(),
Type: granteeBlock.GetAttribute("type").AsStringValueOrDefault("", granteeBlock),
URI: granteeBlock.GetAttribute("uri").AsStringValueOrDefault("", granteeBlock),
}
}

grants = append(grants, grant)
}
}

return grants

}); ok {
return val
}

var grants []s3.Grant
for _, grantBlock := range block.GetBlocks("grant") {
grant := s3.Grant{
Metadata: grantBlock.GetMetadata(),
Permissions: grantBlock.GetAttribute("permissions").AsStringValueSliceOrEmpty(),
Grantee: s3.Grantee{
Metadata: grantBlock.GetMetadata(),
Type: grantBlock.GetAttribute("type").AsStringValueOrDefault("", grantBlock),
URI: grantBlock.GetAttribute("uri").AsStringValueOrDefault("", grantBlock),
},
}

grants = append(grants, grant)
}

return grants
}

func isEncrypted(sseConfgihuration *terraform.Block) iacTypes.BoolValue {
return terraform.MapNestedAttribute(
sseConfgihuration,
Expand Down
13 changes: 13 additions & 0 deletions pkg/iac/providers/aws/s3/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Bucket struct {
Versioning Versioning
Logging Logging
ACL iacTypes.StringValue
Grants []Grant
BucketLocation iacTypes.StringValue
AccelerateConfigurationStatus iacTypes.StringValue
LifecycleConfiguration []Rules
Expand Down Expand Up @@ -65,3 +66,15 @@ type Contents struct {
type Website struct {
Metadata iacTypes.Metadata
}

type Grant struct {
Metadata iacTypes.Metadata
Grantee Grantee
Permissions iacTypes.StringValueList
}

type Grantee struct {
Metadata iacTypes.Metadata
URI iacTypes.StringValue
Type iacTypes.StringValue
}
44 changes: 44 additions & 0 deletions pkg/iac/rego/schemas/cloud.json
Original file line number Diff line number Diff line change
Expand Up @@ -3647,6 +3647,13 @@
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Encryption"
},
"grants": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant"
}
},
"lifecycleconfiguration": {
"type": "array",
"items": {
Expand Down Expand Up @@ -3713,6 +3720,43 @@
}
}
},
"github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant": {
"type": "object",
"properties": {
"__defsec_metadata": {
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.Metadata"
},
"grantee": {
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee"
},
"permissions": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue"
}
}
}
},
"github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee": {
"type": "object",
"properties": {
"__defsec_metadata": {
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.Metadata"
},
"type": {
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue"
},
"uri": {
"type": "object",
"$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue"
}
}
},
"github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Logging": {
"type": "object",
"properties": {
Expand Down

0 comments on commit a817fae

Please sign in to comment.