Skip to content

Commit 6a45222

Browse files
authored
Add optional linting rules for govcloud IAM policies (#55)
* add optional linting rules for govcloud iam policies * address PR review, ensure nested blocks in data source dont break
1 parent 9b7659a commit 6a45222

11 files changed

+963
-0
lines changed

docs/rules/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ These rules warn of possible errors that can occur at `terraform apply`. Rules m
2222
|aws_elb_invalid_instance||
2323
|aws_elb_invalid_security_group||
2424
|aws_elb_invalid_subnet||
25+
|[aws_iam_policy_document_gov_friendly](aws_iam_policy_document_gov_friendly.md)||
26+
|[aws_iam_policy_gov_friendly](aws_iam_policy_gov_friendly.md)||
27+
|[aws_iam_role_policy_gov_friendly](aws_iam_role_policy_gov_friendly.md)||
2528
|aws_instance_invalid_ami||
2629
|aws_instance_invalid_iam_profile||
2730
|aws_instance_invalid_key_name||
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# aws_iam_policy_document_gov_friendly
2+
3+
Ensure `iam_policy_document` data sources do not contain `arn:aws:` ARN's.
4+
5+
## Configuration
6+
7+
```hcl
8+
rule "aws_iam_policy_document_gov_friendly" {
9+
enabled = true
10+
}
11+
```
12+
13+
## Examples
14+
15+
```hcl
16+
data "aws_iam_policy_document" "example" {
17+
statement {
18+
sid = "1"
19+
actions = [
20+
"s3:ListAllMyBuckets",
21+
"s3:GetBucketLocation",
22+
]
23+
resources = [
24+
"arn:aws:s3:::*",
25+
]
26+
}
27+
28+
statement {
29+
sid = "1"
30+
actions = [
31+
"s3:ListAllMyBuckets",
32+
"s3:GetBucketLocation",
33+
]
34+
resources = [
35+
"arn:aws-us-gov:s3:::*",
36+
]
37+
}
38+
}
39+
```
40+
41+
```sh
42+
❯ tflint policy.tf
43+
1 issue(s) found:
44+
45+
Warning: ARN detected in IAM policy document that could potentially fail in AWS GovCloud due to resource pattern: arn:aws:.* (aws_iam_policy_document_gov_friendly_arns)
46+
47+
on policy.tf line 8:
48+
8: resources = [
49+
9: "arn:aws:s3:::*",
50+
10: ]
51+
```
52+
53+
## Why
54+
55+
1. Some firms have strict requirements for what AWS resources have access to government accounts. Usually only resources within the `arn:aws-us-gov:` scope are allowed.
56+
2. When developing reusable terraform modules for many AWS accounts, arn separators are usually converted into variables when creating resources in gov and non-gov accounts like so :
57+
58+
```hcl
59+
locals {
60+
arn_sep = var.is_govcloud ? "aws-us-gov" : "aws"
61+
}
62+
63+
resource "aws_iam_policy_document" "example" {
64+
statement {
65+
sid = "1"
66+
actions = [
67+
"s3:ListAllMyBuckets",
68+
"s3:GetBucketLocation",
69+
]
70+
resources = [
71+
"arn:${local.arn_sep}:s3:::my_bucket",
72+
]
73+
}
74+
}
75+
```
76+
77+
## How To Fix
78+
79+
Ensure there are no `arn:aws:` scoped ARN's in your policy documents.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# aws_iam_policy_gov_friendly
2+
3+
Ensure `iam_policy` resources do not contain `arn:aws:` ARN's.
4+
5+
## Configuration
6+
7+
```hcl
8+
rule "aws_iam_policy_gov_friendly" {
9+
enabled = true
10+
}
11+
```
12+
13+
## Examples
14+
15+
```hcl
16+
resource "aws_iam_policy" "policy" {
17+
name = "test_policy"
18+
path = "/"
19+
description = "My test policy"
20+
policy = <<EOF
21+
{
22+
"Version": "2012-10-17",
23+
"Statement": [
24+
{
25+
"Action": [
26+
"ec2:Describe*"
27+
],
28+
"Effect": "Allow",
29+
"Resource": "arn:aws:s3:::<bucketname>/*""
30+
}
31+
]
32+
}
33+
EOF
34+
}
35+
```
36+
37+
```sh
38+
❯ tflint policy.tf
39+
1 issue(s) found:
40+
41+
Warning: ARN detected in IAM policy that could potentially fail in AWS GovCloud due to resource pattern: arn:aws:.* (aws_iam_policy_gov_friendly_arns)
42+
43+
on policy.tf line 5:
44+
5: policy = <<EOF
45+
6: {
46+
7: "Version": "2012-10-17",
47+
8: "Statement": [
48+
9: {
49+
10: "Action": [
50+
11: "ec2:Describe*"
51+
12: ],
52+
13: "Effect": "Allow",
53+
14: "Resource": "arn:aws:s3:::<bucketname>/*""
54+
15: }
55+
16: ]
56+
17: }
57+
18: EOF
58+
```
59+
60+
## Why
61+
62+
1. Some firms have strict requirements for what AWS resources have access to government accounts. Usually only resources within the `arn:aws-us-gov:` scope are allowed.
63+
2. When developing reusable terraform modules for many AWS accounts, arn separators are usually converted into variables when creating resources in gov and non-gov accounts like so :
64+
65+
```hcl
66+
locals {
67+
arn_sep = var.is_govcloud ? "aws-us-gov" : "aws"
68+
}
69+
70+
resource "aws_iam_policy" "policy" {
71+
name = "test_policy"
72+
path = "/"
73+
description = "My test policy"
74+
policy = <<EOF
75+
{
76+
"Version": "2012-10-17",
77+
"Statement": [
78+
{
79+
"Action": [
80+
"ec2:Describe*"
81+
],
82+
"Effect": "Allow",
83+
"Resource": "arn:${local.arn_sep}:s3:::my_bucket/*""
84+
}
85+
]
86+
}
87+
EOF
88+
}
89+
```
90+
91+
## How To Fix
92+
93+
Ensure there are no `arn:aws:` scoped ARN's in your policy documents.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# aws_iam_role_policy_gov_friendly
2+
3+
Ensure `iam_role_policy` resources do not contain `arn:aws:` ARN's.
4+
5+
## Configuration
6+
7+
```hcl
8+
rule "aws_iam_role_policy_gov_friendly" {
9+
enabled = true
10+
}
11+
```
12+
13+
## Examples
14+
15+
```hcl
16+
resource "aws_iam_role_policy" "test_policy" {
17+
name = "test_policy"
18+
role = "test_role"
19+
policy = <<-EOF
20+
{
21+
"Version": "2012-10-17",
22+
"Statement": [
23+
{
24+
"Action": [
25+
"ec2:Describe*"
26+
],
27+
"Effect": "Allow",
28+
"Resource": "arn:aws:s3:::<bucketname>/*"
29+
}
30+
]
31+
}
32+
EOF
33+
}
34+
```
35+
36+
```sh
37+
❯ tflint policy.tf
38+
1 issue(s) found:
39+
40+
Warning: ARN detected in IAM role policy that could potentially fail in AWS GovCloud due to resource pattern: arn:aws:.* (aws_iam_role_policy_gov_friendly_arns)
41+
42+
on policy.tf line 4:
43+
4: policy = <<-EOF
44+
5: {
45+
6: "Version": "2012-10-17",
46+
7: "Statement": [
47+
8: {
48+
9: "Action": [
49+
10: "ec2:Describe*"
50+
11: ],
51+
12: "Effect": "Allow",
52+
13: "Resource": "arn:aws:s3:::<bucketname>/*"
53+
14: }
54+
15: ]
55+
16: }
56+
17: EOF
57+
```
58+
59+
## Why
60+
61+
1. Some firms have strict requirements for what AWS resources have access to government accounts. Usually only resources within the `arn:aws-us-gov:` scope are allowed.
62+
2. When developing reusable terraform modules for many AWS accounts, arn separators are usually converted into variables when creating resources in gov and non-gov accounts like so :
63+
64+
```hcl
65+
locals {
66+
arn_sep = var.is_govcloud ? "aws-us-gov" : "aws"
67+
}
68+
69+
resource "aws_iam_policy" "policy" {
70+
name = "test_policy"
71+
path = "/"
72+
description = "My test policy"
73+
policy = <<EOF
74+
{
75+
"Version": "2012-10-17",
76+
"Statement": [
77+
{
78+
"Action": [
79+
"ec2:Describe*"
80+
],
81+
"Effect": "Allow",
82+
"Resource": "arn:${local.arn_sep}:s3:::mu_bucket/*""
83+
}
84+
]
85+
}
86+
EOF
87+
}
88+
```
89+
90+
## How To Fix
91+
92+
Ensure there are no `arn:aws:` scoped ARN's in your policy documents.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package rules
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"regexp"
7+
8+
hcl "github.com/hashicorp/hcl/v2"
9+
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
10+
"github.com/terraform-linters/tflint-ruleset-aws/project"
11+
)
12+
13+
const statementBlockName = "statement"
14+
15+
// AwsIAMPolicyDocumentGovFriendlyArnsRule checks for non-GovCloud arns
16+
type AwsIAMPolicyDocumentGovFriendlyArnsRule struct {
17+
resourceType string
18+
attributeName string
19+
pattern *regexp.Regexp
20+
}
21+
22+
// AwsIAMPolicyDocumentGovFriendlyArnsRule returns new rule with default attributes
23+
func NewAwsIAMPolicyDocumentGovFriendlyArnsRule() *AwsIAMPolicyDocumentGovFriendlyArnsRule {
24+
return &AwsIAMPolicyDocumentGovFriendlyArnsRule{
25+
resourceType: "aws_iam_policy_document",
26+
attributeName: "resources",
27+
// AWS GovCloud arn separator is arn:aws-us-gov
28+
// https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/using-govcloud-arns.html
29+
pattern: regexp.MustCompile(`arn:aws:.*`),
30+
}
31+
}
32+
33+
// Name returns the rule name
34+
func (r *AwsIAMPolicyDocumentGovFriendlyArnsRule) Name() string {
35+
return "aws_iam_policy_document_gov_friendly_arns"
36+
}
37+
38+
// Enabled returns whether the rule is enabled by default
39+
func (r *AwsIAMPolicyDocumentGovFriendlyArnsRule) Enabled() bool {
40+
return false
41+
}
42+
43+
// Severity returns the rule severity
44+
func (r *AwsIAMPolicyDocumentGovFriendlyArnsRule) Severity() string {
45+
return tflint.WARNING
46+
}
47+
48+
// Link returns the rule reference link
49+
func (r *AwsIAMPolicyDocumentGovFriendlyArnsRule) Link() string {
50+
return project.ReferenceLink(r.Name())
51+
}
52+
53+
// Check checks the pattern is valid
54+
func (r *AwsIAMPolicyDocumentGovFriendlyArnsRule) Check(runner tflint.Runner) error {
55+
log.Printf("[TRACE] Check `%s` rule", r.Name())
56+
return runner.WalkResourceBlocks(r.resourceType, statementBlockName, func(statementBlock *hcl.Block) error {
57+
content, _, diags := statementBlock.Body.PartialContent(&hcl.BodySchema{
58+
Attributes: []hcl.AttributeSchema{
59+
{Name: r.attributeName},
60+
},
61+
})
62+
if diags.HasErrors() {
63+
return diags
64+
}
65+
var val []string
66+
err := runner.EvaluateExpr(content.Attributes[r.attributeName].Expr, &val, nil)
67+
return runner.EnsureNoError(err, func() error {
68+
for _, arn := range val {
69+
if r.pattern.MatchString(arn) {
70+
runner.EmitIssueOnExpr(
71+
r,
72+
fmt.Sprintf(`ARN detected in IAM policy document that could potentially fail in AWS GovCloud due to resource pattern: %s`, r.pattern),
73+
content.Attributes[r.attributeName].Expr,
74+
)
75+
}
76+
}
77+
return nil
78+
})
79+
})
80+
}

0 commit comments

Comments
 (0)