Skip to content

Commit 7abf5f0

Browse files
authored
feat(misconf): convert AWS managed policy to document (#8757)
Signed-off-by: nikpivkin <[email protected]>
1 parent 9fbfb04 commit 7abf5f0

File tree

3 files changed

+170
-29
lines changed

3 files changed

+170
-29
lines changed

pkg/iac/adapters/terraform/aws/iam/convert.go

+27-21
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,36 @@ type wrappedDocument struct {
1515
}
1616

1717
func ParsePolicyFromAttr(attr *terraform.Attribute, owner *terraform.Block, modules terraform.Modules) (*iam.Document, error) {
18-
if attr.IsString() {
19-
dataBlock, err := modules.GetBlockById(attr.Value().AsString())
18+
if !attr.IsString() {
19+
return &iam.Document{
20+
Metadata: owner.GetMetadata(),
21+
}, nil
22+
}
23+
24+
attrValue := attr.Value().AsString()
25+
26+
dataBlock, err := modules.GetBlockById(attrValue)
27+
if err != nil {
28+
parsed, err := iamgo.Parse([]byte(unescapeVars(attrValue)))
2029
if err != nil {
21-
parsed, err := iamgo.Parse([]byte(unescapeVars(attr.Value().AsString())))
22-
if err != nil {
23-
return nil, err
24-
}
25-
return &iam.Document{
26-
Parsed: *parsed,
27-
Metadata: attr.GetMetadata(),
28-
IsOffset: false,
29-
HasRefs: len(attr.AllReferences()) > 0,
30-
}, nil
30+
return nil, err
3131
}
32+
return &iam.Document{
33+
Parsed: *parsed,
34+
Metadata: attr.GetMetadata(),
35+
IsOffset: false,
36+
HasRefs: len(attr.AllReferences()) > 0,
37+
}, nil
38+
}
3239

33-
if dataBlock.Type() == "data" && dataBlock.TypeLabel() == "aws_iam_policy_document" {
34-
if doc, err := ConvertTerraformDocument(modules, dataBlock); err == nil {
35-
return &iam.Document{
36-
Metadata: dataBlock.GetMetadata(),
37-
Parsed: doc.Document,
38-
IsOffset: true,
39-
HasRefs: false,
40-
}, nil
41-
}
40+
if dataBlock.Type() == "data" && dataBlock.TypeLabel() == "aws_iam_policy_document" {
41+
if doc, err := ConvertTerraformDocument(modules, dataBlock); err == nil {
42+
return &iam.Document{
43+
Metadata: dataBlock.GetMetadata(),
44+
Parsed: doc.Document,
45+
IsOffset: true,
46+
HasRefs: false,
47+
}, nil
4248
}
4349
}
4450

pkg/iac/adapters/terraform/aws/iam/policies.go

+65-8
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import (
88
)
99

1010
func parsePolicy(policyBlock *terraform.Block, modules terraform.Modules) (iam.Policy, error) {
11+
nameAttr := policyBlock.GetAttribute("name")
1112
policy := iam.Policy{
1213
Metadata: policyBlock.GetMetadata(),
13-
Name: policyBlock.GetAttribute("name").AsStringValueOrDefault("", policyBlock),
14+
Name: nameAttr.AsStringValueOrDefault("", policyBlock),
1415
Document: iam.Document{
1516
Metadata: iacTypes.NewUnmanagedMetadata(),
1617
Parsed: iamgo.Document{},
@@ -19,7 +20,19 @@ func parsePolicy(policyBlock *terraform.Block, modules terraform.Modules) (iam.P
1920
},
2021
Builtin: iacTypes.Bool(false, policyBlock.GetMetadata()),
2122
}
22-
var err error
23+
24+
if policyBlock.Type() == "data" && policyBlock.TypeLabel() == "aws_iam_policy" &&
25+
nameAttr.IsString() {
26+
doc, exists := awsManagedPolicies[nameAttr.Value().AsString()]
27+
if exists {
28+
policy.Document = iam.Document{
29+
Metadata: nameAttr.GetMetadata(),
30+
Parsed: doc,
31+
}
32+
return policy, nil
33+
}
34+
}
35+
2336
doc, err := ParsePolicyFromAttr(policyBlock.GetAttribute("policy"), policyBlock, modules)
2437
if err != nil {
2538
return policy, err
@@ -96,14 +109,58 @@ func findPolicy(modules terraform.Modules) func(resource *terraform.Block) *iam.
96109

97110
func findAttachmentPolicy(modules terraform.Modules) func(resource *terraform.Block) *iam.Policy {
98111
return func(resource *terraform.Block) *iam.Policy {
99-
policyAttr := resource.GetAttribute("policy_arn")
100-
if policyAttr.IsNil() {
112+
attr := resource.GetAttribute("policy_arn")
113+
if attr.IsNil() {
101114
return nil
102115
}
103-
policyBlock, err := modules.GetReferencedBlock(policyAttr, resource)
104-
if err != nil {
105-
return nil
116+
117+
if attr.IsString() {
118+
arn := attr.Value().AsString()
119+
if doc, ok := awsManagedPolicies[arn]; ok {
120+
if block, err := modules.GetReferencedBlock(attr, resource); err == nil {
121+
meta := block.GetMetadata()
122+
if arnAttr := block.GetAttribute("arn"); arnAttr.IsNotNil() {
123+
meta = arnAttr.GetMetadata()
124+
}
125+
return &iam.Policy{
126+
Metadata: block.GetMetadata(),
127+
Document: iam.Document{
128+
Metadata: meta,
129+
Parsed: doc,
130+
},
131+
}
132+
}
133+
return &iam.Policy{
134+
Metadata: resource.GetMetadata(),
135+
Document: iam.Document{
136+
Metadata: attr.GetMetadata(),
137+
Parsed: doc,
138+
},
139+
}
140+
}
106141
}
107-
return findPolicy(modules)(policyBlock)
142+
143+
if block, err := modules.GetReferencedBlock(attr, resource); err == nil {
144+
return findPolicy(modules)(block)
145+
}
146+
147+
return nil
108148
}
109149
}
150+
151+
var awsManagedPolicies = map[string]iamgo.Document{
152+
// https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonS3FullAccess.html
153+
"arn:aws:iam::aws:policy/AmazonS3FullAccess": s3FullAccessPolicyDocument,
154+
"AmazonS3FullAccess": s3FullAccessPolicyDocument,
155+
}
156+
157+
var s3FullAccessPolicyDocument = iamgo.NewPolicyBuilder().
158+
WithVersion("2012-10-17").
159+
WithStatement(
160+
iamgo.NewStatementBuilder().
161+
WithEffect("Allow").
162+
WithActions([]string{"s3:*", "s3-object-lambda:*"}).
163+
WithResources([]string{"*"}).
164+
Build(),
165+
).
166+
Build()

pkg/iac/adapters/terraform/aws/iam/roles_test.go

+78
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,84 @@ data "aws_iam_policy_document" "s3_policy" {
260260
},
261261
},
262262
},
263+
{
264+
name: "attach AWS managed policy using ARN directly",
265+
terraform: `resource "aws_iam_role" "test" {
266+
name = "example-role"
267+
}
268+
269+
resource "aws_iam_role_policy_attachment" "test" {
270+
role = aws_iam_role.test.name
271+
policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
272+
}`,
273+
expected: []iam.Role{
274+
{
275+
Name: iacTypes.StringTest("example-role"),
276+
Policies: []iam.Policy{
277+
{
278+
Document: iam.Document{
279+
Parsed: s3FullAccessPolicyDocument,
280+
},
281+
},
282+
},
283+
},
284+
},
285+
},
286+
{
287+
name: "attach AWS managed policy using ARN from data source",
288+
terraform: `data "aws_iam_policy" "s3_full_access" {
289+
arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
290+
}
291+
292+
resource "aws_iam_role" "test" {
293+
name = "example-role"
294+
}
295+
296+
resource "aws_iam_role_policy_attachment" "test" {
297+
role = aws_iam_role.test.name
298+
policy_arn = data.aws_iam_policy.s3_full_access.arn
299+
}`,
300+
expected: []iam.Role{
301+
{
302+
Name: iacTypes.StringTest("example-role"),
303+
Policies: []iam.Policy{
304+
{
305+
Document: iam.Document{
306+
Parsed: s3FullAccessPolicyDocument,
307+
},
308+
},
309+
},
310+
},
311+
},
312+
},
313+
{
314+
name: "attach AWS managed policy using data source with policy name",
315+
terraform: `data "aws_iam_policy" "s3_full_access" {
316+
name = "AmazonS3FullAccess"
317+
}
318+
319+
resource "aws_iam_role" "test" {
320+
name = "example-role"
321+
}
322+
323+
resource "aws_iam_role_policy_attachment" "test" {
324+
role = aws_iam_role.test.name
325+
policy_arn = data.aws_iam_policy.s3_full_access.arn
326+
}`,
327+
expected: []iam.Role{
328+
{
329+
Name: iacTypes.StringTest("example-role"),
330+
Policies: []iam.Policy{
331+
{
332+
Name: iacTypes.StringTest("AmazonS3FullAccess"),
333+
Document: iam.Document{
334+
Parsed: s3FullAccessPolicyDocument,
335+
},
336+
},
337+
},
338+
},
339+
},
340+
},
263341
}
264342

265343
for _, test := range tests {

0 commit comments

Comments
 (0)