Skip to content

Commit 8047cf5

Browse files
authored
aws_iam_policy_length (#153)
* aws_iam_policy_length - Added a rule to check against IAM policy length. fixes #26 * formated * Update name of rule, update character count, ignore whitespace
1 parent ccdd4aa commit 8047cf5

File tree

5 files changed

+179
-2
lines changed

5 files changed

+179
-2
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# aws_iam_policy_too_long_policy
2+
3+
This makes sure that a IAM policy is not longer than the 6144 AWS character limit.
4+
5+
## Example
6+
7+
```hcl
8+
resource "aws_iam_policy" "policy" {
9+
name = "test_policy"
10+
path = "/"
11+
description = "My test policy"
12+
policy = <<EOF
13+
{
14+
STRING LONGER THAN 6144
15+
}
16+
EOF
17+
}
18+
```
19+
20+
```
21+
$ tflint
22+
1 issue(s) found:
23+
Error: The policy length is %d characters and is limited to 6144 characters. (aws_iam_policy_too_long_policy)
24+
on template.tf line 6:
25+
6: policy = "{POLICY}" // Policy is too long,!
26+
27+
```
28+
29+
## Why
30+
31+
Terraform does not check against this rule, but it will error if an apply is attempted.
32+
33+
## How To Fix
34+
35+
Update policy to reduce characters. Some methods are splitting into multiple policies, or switching to using a combination of deny and allow statements to optimize the policy.

rules/aws_iam_policy_sid_invalid_characters.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ package rules
22

33
import (
44
"encoding/json"
5+
"fmt"
56
hcl "github.com/hashicorp/hcl/v2"
67
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
78
"github.com/terraform-linters/tflint-ruleset-aws/project"
89
"regexp"
9-
"fmt"
1010
)
11+
1112
type AwsIAMPolicySidInvalidCharactersStatementStruct struct {
1213
Sid string `json:"Sid"`
1314
}
@@ -58,7 +59,7 @@ func (r *AwsIAMPolicySidInvalidCharactersRule) Check(runner tflint.Runner) error
5859
err := runner.EvaluateExpr(attribute.Expr, &val, nil)
5960
unMarshaledPolicy := AwsIAMPolicySidInvalidCharactersPolicyStruct{}
6061
if jsonErr := json.Unmarshal([]byte(val), &unMarshaledPolicy); jsonErr != nil {
61-
return jsonErr;
62+
return jsonErr
6263
}
6364
statements := unMarshaledPolicy.Statement
6465

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package rules
2+
3+
import (
4+
"fmt"
5+
hcl "github.com/hashicorp/hcl/v2"
6+
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
7+
"github.com/terraform-linters/tflint-ruleset-aws/project"
8+
"regexp"
9+
)
10+
11+
// AwsIAMPolicyTooLongPolicyRule checks that the policy length is less than 6,144 characters
12+
type AwsIAMPolicyTooLongPolicyRule struct {
13+
resourceType string
14+
attributeName string
15+
}
16+
17+
// NewAwsIAMPolicyTooLongPolicyRule returns new rule with default attributes
18+
func NewAwsIAMPolicyTooLongPolicyRule() *AwsIAMPolicyTooLongPolicyRule {
19+
return &AwsIAMPolicyTooLongPolicyRule{
20+
resourceType: "aws_iam_policy",
21+
attributeName: "policy",
22+
}
23+
}
24+
25+
// Name returns the rule name
26+
func (r *AwsIAMPolicyTooLongPolicyRule) Name() string {
27+
return "aws_iam_policy_too_long_policy"
28+
}
29+
30+
// Enabled returns whether the rule is enabled by default
31+
func (r *AwsIAMPolicyTooLongPolicyRule) Enabled() bool {
32+
return true
33+
}
34+
35+
// Severity returns the rule severity
36+
func (r *AwsIAMPolicyTooLongPolicyRule) Severity() string {
37+
return tflint.ERROR
38+
}
39+
40+
// Link returns the rule reference link
41+
func (r *AwsIAMPolicyTooLongPolicyRule) Link() string {
42+
return project.ReferenceLink(r.Name())
43+
}
44+
45+
// Check checks the length of the policy
46+
func (r *AwsIAMPolicyTooLongPolicyRule) Check(runner tflint.Runner) error {
47+
return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error {
48+
var policy string
49+
err := runner.EvaluateExpr(attribute.Expr, &policy, nil)
50+
whitespaceRegex := regexp.MustCompile(`\s+`)
51+
policy = whitespaceRegex.ReplaceAllString(policy, "")
52+
return runner.EnsureNoError(err, func() error {
53+
if len(policy) > 6144 {
54+
runner.EmitIssueOnExpr(
55+
r,
56+
fmt.Sprintf("The policy length is %d characters and is limited to 6144 characters.", len(policy)),
57+
attribute.Expr,
58+
)
59+
}
60+
return nil
61+
})
62+
})
63+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package rules
2+
3+
import (
4+
"math/rand"
5+
"testing"
6+
"time"
7+
8+
hcl "github.com/hashicorp/hcl/v2"
9+
"github.com/terraform-linters/tflint-plugin-sdk/helper"
10+
)
11+
12+
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
13+
14+
func randSeq(n int) string {
15+
b := make([]rune, n)
16+
for i := range b {
17+
b[i] = letters[rand.Intn(len(letters))]
18+
}
19+
return string(b)
20+
}
21+
22+
func Test_AwsIAMPolicyTooLongPolicy(t *testing.T) {
23+
rand.Seed(time.Now().UnixNano())
24+
cases := []struct {
25+
Name string
26+
Content string
27+
Expected helper.Issues
28+
}{
29+
{
30+
Name: "policy is too long",
31+
Content: `
32+
resource "aws_iam_policy" "policy" {
33+
name = "test_policy"
34+
path = "/"
35+
description = "My test policy"
36+
policy = <<EOF
37+
{
38+
"Version": "2012-10-17",
39+
"Statement": [
40+
{
41+
"Action": [
42+
` + randSeq(6034) + `
43+
],
44+
"Effect": "Allow",
45+
"Resource": "arn:aws:s3:::<bucketname>/*""
46+
}
47+
]
48+
}
49+
EOF
50+
}
51+
`,
52+
Expected: helper.Issues{
53+
{
54+
Rule: NewAwsIAMPolicyTooLongPolicyRule(),
55+
Message: "The policy length is 6145 characters and is limited to 6144 characters.",
56+
Range: hcl.Range{
57+
Filename: "resource.tf",
58+
Start: hcl.Pos{Line: 6, Column: 11},
59+
End: hcl.Pos{Line: 19, Column: 4},
60+
},
61+
},
62+
},
63+
},
64+
}
65+
66+
rule := NewAwsIAMPolicyTooLongPolicyRule()
67+
68+
for _, tc := range cases {
69+
runner := helper.TestRunner(t, map[string]string{"resource.tf": tc.Content})
70+
71+
if err := rule.Check(runner); err != nil {
72+
t.Fatalf("Unexpected error occurred: %s", err)
73+
}
74+
75+
helper.AssertIssues(t, tc.Expected, runner.Issues)
76+
}
77+
}

rules/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ var Rules = append([]tflint.Rule{
3333
NewAwsElastiCacheReplicationGroupInvalidTypeRule(),
3434
NewAwsElastiCacheReplicationGroupPreviousTypeRule(),
3535
NewAwsIAMPolicySidInvalidCharactersRule(),
36+
NewAwsIAMPolicyTooLongPolicyRule(),
3637
}, models.Rules...)

0 commit comments

Comments
 (0)