-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add aws_iam_policy_attachment_exclusive_attachment rule #786
Changes from 10 commits
a637712
7b2143d
77bfa62
2c659b4
94a7cb0
115097f
ab27152
7ff5121
e8a14e9
593ea17
7b9bda8
ff47d05
a370312
526da1a
7893a42
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
.idea/ | ||
|
||
tools/provider-schema/.terraform/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# aws_iam_policy_attachment_exclusive_attachment | ||
|
||
Consider alternative resources to `aws_iam_policy_attachment`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Get a little bit of the why up here. The section below can expand but this intro should give the reader a 1-2 sentence summary of what and why. |
||
|
||
## Configuration | ||
|
||
```hcl | ||
rule "aws_iam_policy_attachment_exclusive_attachment" { | ||
enabled = true | ||
} | ||
``` | ||
|
||
## Example | ||
|
||
```hcl | ||
resource "aws_iam_policy_attachment" "attachment" { | ||
name = "test_attachment" | ||
} | ||
``` | ||
|
||
```shell | ||
$ tflint | ||
1 issue(s) found: | ||
Warning: Consider aws_iam_role_policy_attachment, aws_iam_user_policy_attachment, or aws_iam_group_policy_attachment instead. (aws_iam_policy_attachment_has_alternatives) | ||
on template.tf line 2: | ||
2: name "test_attachment" | ||
``` | ||
|
||
## Why | ||
|
||
The `aws_iam_policy_attachment` resource creates exclusive attachments of IAM policies. Across the entire AWS account, all the users/roles/groups to which a single policy is attached must be declared by a single `aws_iam_policy_attachment` resource. This means that even any users/roles/groups that have the attached policy via any other mechanism (including other Terraform resources) will have that attached policy revoked by this resource. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hyperlink the first use of the identifier (in backticks) instead of appending the URL at the end |
||
|
||
## How To Fix | ||
|
||
Consider using `aws_iam_role_policy_attachment`, `aws_iam_user_policy_attachment`, or `aws_iam_group_policy_attachment` instead. These resources do not enforce exclusive attachment of an IAM policy. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package rules | ||
|
||
import ( | ||
"github.com/terraform-linters/tflint-plugin-sdk/hclext" | ||
"github.com/terraform-linters/tflint-plugin-sdk/tflint" | ||
"github.com/terraform-linters/tflint-ruleset-aws/project" | ||
) | ||
|
||
// AwsIAMPolicyAttachmentExclusiveAttachmentRule warns that the resource has alternatives recommended | ||
type AwsIAMPolicyAttachmentExclusiveAttachmentRule struct { | ||
tflint.DefaultRule | ||
|
||
resourceType string | ||
attributeName string | ||
} | ||
|
||
// AwsIAMPolicyAttachmentExclusiveAttachmentRule returns new rule with default attributes | ||
func NewAwsIAMPolicyAttachmentExclusiveAttachmentRule() *AwsIAMPolicyAttachmentExclusiveAttachmentRule { | ||
return &AwsIAMPolicyAttachmentExclusiveAttachmentRule{ | ||
resourceType: "aws_iam_policy_attachment", | ||
attributeName: "name", | ||
} | ||
} | ||
|
||
// Name returns the rule name | ||
func (r *AwsIAMPolicyAttachmentExclusiveAttachmentRule) Name() string { | ||
return "aws_iam_policy_attachment_exclusive_attachment" | ||
} | ||
|
||
// Enabled returns whether the rule is enabled by default | ||
func (r *AwsIAMPolicyAttachmentExclusiveAttachmentRule) Enabled() bool { | ||
return false | ||
} | ||
|
||
// Severity returns the rule severity | ||
func (r *AwsIAMPolicyAttachmentExclusiveAttachmentRule) Severity() tflint.Severity { | ||
return tflint.WARNING | ||
} | ||
|
||
// Link returns the rule reference link | ||
func (r *AwsIAMPolicyAttachmentExclusiveAttachmentRule) Link() string { | ||
return project.ReferenceLink(r.Name()) | ||
} | ||
|
||
// Check that the resource is not used | ||
func (r *AwsIAMPolicyAttachmentExclusiveAttachmentRule) Check(runner tflint.Runner) error { | ||
resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{ | ||
Attributes: []hclext.AttributeSchema{{Name: r.attributeName}}, | ||
}, nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, resource := range resources.Blocks { | ||
attribute, exists := resource.Body.Attributes[r.attributeName] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this logic apply? If there's no name attribute, the resource should be skipped? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see this logic on my machine. We don't need it here. |
||
if !exists { | ||
continue | ||
} | ||
|
||
runner.EmitIssue( | ||
r, | ||
"Consider aws_iam_role_policy_attachment, aws_iam_user_policy_attachment, or aws_iam_group_policy_attachment instead.", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Include a brief bit of why here (exclusive for whole account) |
||
attribute.Expr.Range(), | ||
) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package rules | ||
|
||
import ( | ||
"math/rand" | ||
"testing" | ||
"time" | ||
|
||
hcl "github.com/hashicorp/hcl/v2" | ||
"github.com/terraform-linters/tflint-plugin-sdk/helper" | ||
) | ||
|
||
func Test_AwsIAMPolicyAttachmentExclusiveAttachmentRule(t *testing.T) { | ||
rand.Seed(time.Now().UnixNano()) | ||
|
||
cases := []struct { | ||
Name string | ||
Content string | ||
Expected helper.Issues | ||
}{ | ||
{ | ||
Name: "resource has alternatives", | ||
Content: ` | ||
resource "aws_iam_policy_attachment" "attachment" { | ||
name = "test_attachment" | ||
} | ||
`, | ||
Expected: helper.Issues{ | ||
{ | ||
Rule: NewAwsIAMPolicyAttachmentExclusiveAttachmentRule(), | ||
Message: "Consider aws_iam_role_policy_attachment, aws_iam_user_policy_attachment, or aws_iam_group_policy_attachment instead.", | ||
Range: hcl.Range{ | ||
Filename: "resource.tf", | ||
Start: hcl.Pos{Line: 3, Column: 9}, | ||
End: hcl.Pos{Line: 3, Column: 26}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
Name: "no issues with resource", | ||
Content: ` | ||
resource "aws_iam_role_policy_attachment" "attachment" { | ||
role = "test_role" | ||
} | ||
`, | ||
Expected: helper.Issues{}, | ||
}, | ||
} | ||
|
||
rule := NewAwsIAMPolicyAttachmentExclusiveAttachmentRule() | ||
|
||
for _, tc := range cases { | ||
runner := helper.TestRunner(t, map[string]string{"resource.tf": tc.Content}) | ||
|
||
if err := rule.Check(runner); err != nil { | ||
t.Fatalf("Unexpected error occurred: %s", err) | ||
} | ||
|
||
helper.AssertIssues(t, tc.Expected, runner.Issues) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert this