Skip to content

Commit a817fae

Browse files
authoredAug 6, 2024··
feat(misconf): support for policy and bucket grants (#7284)
Signed-off-by: nikpivkin <[email protected]>
1 parent a4180bd commit a817fae

File tree

6 files changed

+229
-0
lines changed

6 files changed

+229
-0
lines changed
 

‎pkg/iac/adapters/cloudformation/aws/s3/bucket.go

+35
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import (
77
"strings"
88

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

12+
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
1113
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/s3"
1214
"github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser"
1315
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
@@ -37,6 +39,7 @@ func getBuckets(cfFile parser.FileContext) []s3.Bucket {
3739
Website: getWebsite(r),
3840
BucketLocation: iacTypes.String("", r.Metadata()),
3941
Objects: nil,
42+
BucketPolicies: getBucketPolicies(cfFile, r),
4043
}
4144

4245
buckets = append(buckets, s3b)
@@ -156,3 +159,35 @@ func getWebsite(r *parser.Resource) *s3.Website {
156159
}
157160
}
158161
}
162+
163+
func getBucketPolicies(fctx parser.FileContext, r *parser.Resource) []iam.Policy {
164+
165+
var policies []iam.Policy
166+
for _, bucketPolicy := range fctx.GetResourcesByType("AWS::S3::BucketPolicy") {
167+
bucket := bucketPolicy.GetStringProperty("Bucket")
168+
if bucket.NotEqualTo(r.GetStringProperty("BucketName").Value()) && bucket.NotEqualTo(r.ID()) {
169+
continue
170+
}
171+
172+
doc := bucketPolicy.GetProperty("PolicyDocument")
173+
if doc.IsNil() {
174+
continue
175+
}
176+
177+
parsed, err := iamgo.Parse(doc.GetJsonBytes())
178+
if err != nil {
179+
continue
180+
}
181+
policies = append(policies, iam.Policy{
182+
Metadata: doc.Metadata(),
183+
Name: iacTypes.StringDefault("", doc.Metadata()),
184+
Document: iam.Document{
185+
Metadata: doc.Metadata(),
186+
Parsed: *parsed,
187+
},
188+
Builtin: iacTypes.Bool(false, doc.Metadata()),
189+
})
190+
}
191+
192+
return policies
193+
}

‎pkg/iac/adapters/cloudformation/aws/s3/s3_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package s3
33
import (
44
"testing"
55

6+
"github.com/liamg/iamgo"
7+
68
"github.com/aquasecurity/trivy/pkg/iac/adapters/cloudformation/testutil"
9+
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
710
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/s3"
811
"github.com/aquasecurity/trivy/pkg/iac/types"
912
)
@@ -57,6 +60,19 @@ Resources:
5760
Status: Enabled
5861
WebsiteConfiguration:
5962
IndexDocument: index.html
63+
SampleBucketPolicy:
64+
Type: AWS::S3::BucketPolicy
65+
Properties:
66+
Bucket: !Ref Bucket
67+
PolicyDocument:
68+
Version: 2012-10-17
69+
Statement:
70+
- Action:
71+
- 's3:GetObject'
72+
Effect: Allow
73+
Resource: !Join
74+
- 'arn:aws:s3:::testbucket/*'
75+
Principal: '*'
6076
`,
6177
expected: s3.S3{
6278
Buckets: []s3.Bucket{
@@ -91,6 +107,23 @@ Resources:
91107
Enabled: types.BoolTest(true),
92108
},
93109
Website: &s3.Website{},
110+
BucketPolicies: []iam.Policy{
111+
{
112+
Document: iam.Document{
113+
Parsed: iamgo.NewPolicyBuilder().
114+
WithStatement(
115+
iamgo.NewStatementBuilder().
116+
WithActions([]string{"s3:GetObject"}).
117+
WithAllPrincipals(true).
118+
WithEffect("Allow").
119+
WithResources([]string{"arn:aws:s3:::testbucket/*"}).
120+
Build(),
121+
).
122+
WithVersion("2012-10-17T00:00:00Z").
123+
Build(),
124+
},
125+
},
126+
},
94127
},
95128
},
96129
},

‎pkg/iac/adapters/terraform/aws/s3/adapt_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,15 @@ func Test_Adapt(t *testing.T) {
149149
resource "aws_s3_bucket_acl" "example" {
150150
bucket = aws_s3_bucket.example.id
151151
acl = "private"
152+
access_control_policy {
153+
grant {
154+
grantee {
155+
type = "Group"
156+
uri = "http://acs.amazonaws.com/groups/s3/LogDelivery"
157+
}
158+
permission = "READ_ACP"
159+
}
160+
}
152161
}
153162
154163
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
@@ -250,6 +259,51 @@ func Test_Adapt(t *testing.T) {
250259
TargetBucket: iacTypes.String("aws_s3_bucket.example", iacTypes.NewTestMetadata()),
251260
},
252261
ACL: iacTypes.String("private", iacTypes.NewTestMetadata()),
262+
Grants: []s3.Grant{
263+
{
264+
Metadata: iacTypes.NewTestMetadata(),
265+
Grantee: s3.Grantee{
266+
Type: iacTypes.StringTest("Group"),
267+
URI: iacTypes.StringTest("http://acs.amazonaws.com/groups/s3/LogDelivery"),
268+
},
269+
Permissions: iacTypes.StringValueList{
270+
iacTypes.StringTest("READ_ACP"),
271+
},
272+
},
273+
},
274+
},
275+
},
276+
},
277+
},
278+
{
279+
name: "bucket with grants",
280+
terraform: `
281+
resource "aws_s3_bucket" "this" {
282+
bucket = "test"
283+
284+
grant {
285+
type = "Group"
286+
uri = "http://acs.amazonaws.com/groups/s3/LogDelivery"
287+
permissions = ["FULL_CONTROL"]
288+
}
289+
}
290+
`,
291+
expected: s3.S3{
292+
Buckets: []s3.Bucket{
293+
{
294+
Name: iacTypes.StringTest("test"),
295+
ACL: iacTypes.StringTest("private"),
296+
Grants: []s3.Grant{
297+
{
298+
Grantee: s3.Grantee{
299+
Type: iacTypes.StringTest("Group"),
300+
URI: iacTypes.StringTest("http://acs.amazonaws.com/groups/s3/LogDelivery"),
301+
},
302+
Permissions: iacTypes.StringValueList{
303+
iacTypes.StringTest("FULL_CONTROL"),
304+
},
305+
},
306+
},
253307
},
254308
},
255309
},

‎pkg/iac/adapters/terraform/aws/s3/bucket.go

+50
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func (a *adapter) adaptBuckets() []s3.Bucket {
2626
Versioning: getVersioning(block, a),
2727
Logging: getLogging(block, a),
2828
ACL: getBucketAcl(block, a),
29+
Grants: getGrants(block, a),
2930
AccelerateConfigurationStatus: getAccelerateStatus(block, a),
3031
BucketLocation: block.GetAttribute("region").AsStringValueOrDefault("", block),
3132
LifecycleConfiguration: getLifecycle(block, a),
@@ -193,6 +194,55 @@ func getBucketAcl(block *terraform.Block, a *adapter) iacTypes.StringValue {
193194
return iacTypes.StringDefault("private", block.GetMetadata())
194195
}
195196

197+
func getGrants(block *terraform.Block, a *adapter) []s3.Grant {
198+
if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_acl", func(resource *terraform.Block) []s3.Grant {
199+
var grants []s3.Grant
200+
201+
if acessControlPolicy := resource.GetBlock("access_control_policy"); acessControlPolicy.IsNotNil() {
202+
for _, grantBlock := range acessControlPolicy.GetBlocks("grant") {
203+
grant := s3.Grant{
204+
Metadata: grantBlock.GetMetadata(),
205+
Permissions: iacTypes.StringValueList{
206+
grantBlock.GetAttribute("permission").AsStringValueOrDefault("", grantBlock),
207+
},
208+
}
209+
210+
if granteeBlock := grantBlock.GetBlock("grantee"); granteeBlock.IsNotNil() {
211+
grant.Grantee = s3.Grantee{
212+
Metadata: granteeBlock.GetMetadata(),
213+
Type: granteeBlock.GetAttribute("type").AsStringValueOrDefault("", granteeBlock),
214+
URI: granteeBlock.GetAttribute("uri").AsStringValueOrDefault("", granteeBlock),
215+
}
216+
}
217+
218+
grants = append(grants, grant)
219+
}
220+
}
221+
222+
return grants
223+
224+
}); ok {
225+
return val
226+
}
227+
228+
var grants []s3.Grant
229+
for _, grantBlock := range block.GetBlocks("grant") {
230+
grant := s3.Grant{
231+
Metadata: grantBlock.GetMetadata(),
232+
Permissions: grantBlock.GetAttribute("permissions").AsStringValueSliceOrEmpty(),
233+
Grantee: s3.Grantee{
234+
Metadata: grantBlock.GetMetadata(),
235+
Type: grantBlock.GetAttribute("type").AsStringValueOrDefault("", grantBlock),
236+
URI: grantBlock.GetAttribute("uri").AsStringValueOrDefault("", grantBlock),
237+
},
238+
}
239+
240+
grants = append(grants, grant)
241+
}
242+
243+
return grants
244+
}
245+
196246
func isEncrypted(sseConfgihuration *terraform.Block) iacTypes.BoolValue {
197247
return terraform.MapNestedAttribute(
198248
sseConfgihuration,

‎pkg/iac/providers/aws/s3/bucket.go

+13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Bucket struct {
1414
Versioning Versioning
1515
Logging Logging
1616
ACL iacTypes.StringValue
17+
Grants []Grant
1718
BucketLocation iacTypes.StringValue
1819
AccelerateConfigurationStatus iacTypes.StringValue
1920
LifecycleConfiguration []Rules
@@ -65,3 +66,15 @@ type Contents struct {
6566
type Website struct {
6667
Metadata iacTypes.Metadata
6768
}
69+
70+
type Grant struct {
71+
Metadata iacTypes.Metadata
72+
Grantee Grantee
73+
Permissions iacTypes.StringValueList
74+
}
75+
76+
type Grantee struct {
77+
Metadata iacTypes.Metadata
78+
URI iacTypes.StringValue
79+
Type iacTypes.StringValue
80+
}

‎pkg/iac/rego/schemas/cloud.json

+44
Original file line numberDiff line numberDiff line change
@@ -3647,6 +3647,13 @@
36473647
"type": "object",
36483648
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Encryption"
36493649
},
3650+
"grants": {
3651+
"type": "array",
3652+
"items": {
3653+
"type": "object",
3654+
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant"
3655+
}
3656+
},
36503657
"lifecycleconfiguration": {
36513658
"type": "array",
36523659
"items": {
@@ -3713,6 +3720,43 @@
37133720
}
37143721
}
37153722
},
3723+
"github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant": {
3724+
"type": "object",
3725+
"properties": {
3726+
"__defsec_metadata": {
3727+
"type": "object",
3728+
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata"
3729+
},
3730+
"grantee": {
3731+
"type": "object",
3732+
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee"
3733+
},
3734+
"permissions": {
3735+
"type": "array",
3736+
"items": {
3737+
"type": "object",
3738+
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue"
3739+
}
3740+
}
3741+
}
3742+
},
3743+
"github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee": {
3744+
"type": "object",
3745+
"properties": {
3746+
"__defsec_metadata": {
3747+
"type": "object",
3748+
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata"
3749+
},
3750+
"type": {
3751+
"type": "object",
3752+
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue"
3753+
},
3754+
"uri": {
3755+
"type": "object",
3756+
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue"
3757+
}
3758+
}
3759+
},
37163760
"github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Logging": {
37173761
"type": "object",
37183762
"properties": {

0 commit comments

Comments
 (0)
Please sign in to comment.