Skip to content

Commit c7d5cbd

Browse files
authored
Merge pull request hashicorp#153 from hashicorp/restrict-aws-sgs
Restrict aws sgs
2 parents 2145e0a + 787e3c2 commit c7d5cbd

File tree

6 files changed

+931
-9
lines changed

6 files changed

+931
-9
lines changed

governance/second-generation/aws/restrict-ingress-sg-rule-cidr-blocks.sentinel

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
# This policy uses the Sentinel tfplan import to validate that
2-
# no security group rules have the CIDR "0.0.0.0/0"
1+
# This policy uses the Sentinel tfplan import to validate that no security group
2+
# rules have the CIDR "0.0.0.0/0". It covers both the aws_security_group and
3+
# the aws_security_group_rule resources.
34

45
##### Imports #####
56

@@ -42,21 +43,21 @@ find_resources_from_plan = func(type) {
4243

4344
# Validate that all AWS ingress security group rules
4445
# do not have cidr_block 0.0.0.0/0
45-
validate_sgr_cidr_blocks = func() {
46+
validate_cidr_blocks = func() {
4647

4748
validated = true
4849

49-
# Get all resources of specified type
50-
resource_instances = find_resources_from_plan("aws_security_group_rule")
50+
# Get all AWS security group rules
51+
sgr_instances = find_resources_from_plan("aws_security_group_rule")
5152

5253
# Loop through the resource instances
53-
for resource_instances as address, r {
54+
for sgr_instances as address, r {
5455

5556
# Skip resources that are being destroyed
5657
# to avoid unnecessary policy violations.
5758
# Used to be: if length(r.diff) == 0
5859
if r.destroy and not r.requires_new {
59-
print("Skipping resource", address, "that is being destroyed.")
60+
print("Skipping security group rule", address, "that is being destroyed.")
6061
continue
6162
}
6263

@@ -83,15 +84,80 @@ validate_sgr_cidr_blocks = func() {
8384
}
8485
} // end computed check
8586

86-
} // end resource instances
87+
} // end security group rule instances
88+
89+
# Get all AWS security groups
90+
sg_instances = find_resources_from_plan("aws_security_group")
91+
92+
# Loop through the resource instances
93+
for sg_instances as address, r {
94+
95+
# Skip resources that are being destroyed
96+
# to avoid unnecessary policy violations.
97+
# Used to be: if length(r.diff) == 0
98+
if r.destroy and not r.requires_new {
99+
print("Skipping security group", address, "that is being destroyed.")
100+
continue
101+
}
102+
103+
# Check if there are ingress blocks that are not computed
104+
if (r.diff["ingress.#"].computed else false) is true {
105+
print("Security group", address, "does not have any ingress blocks",
106+
"or, they are computed.")
107+
# If you want computed values to cause the policy to fail,
108+
# uncomment the next line.
109+
# validated = false
110+
} else {
111+
# Check if r.applied.ingress is a list (to be safe)
112+
if types.type_of(r.applied.ingress) is "list" {
113+
114+
ingress_count = 0
115+
116+
for r.applied.ingress as i {
117+
118+
# Determine if ingress.<n>.cidr_blocks.# attribute is computed
119+
# Note that this approach works for Terraform 0.12, but not
120+
# for Terraform 0.11 which has diff expressions like
121+
# "ingress.3167104115.cidr_blocks.#" rather than using 0, 1, 2
122+
# after "ingress".
123+
ingress_cidr_blocks = "ingress." + string(ingress_count) + ".cidr_blocks.#"
124+
if (r.diff[ingress_cidr_blocks].computed else false) is true {
125+
print("Ingress block #", ingress_count, "of security group",
126+
address, "has cidr_blocks that is computed.")
127+
# If you want computed values to cause the policy to fail,
128+
# uncomment the next line.
129+
# validated = false
130+
} else {
131+
# Validate that the ingress rule does not have disallowed value
132+
# Since cidr_blocks is optional and could be computed,
133+
# We check that it is present and really a list
134+
# before checking whether it contains "0.0.0.0/0"
135+
if i.cidr_blocks else null is not null and
136+
types.type_of(i.cidr_blocks) is "list" and
137+
i.cidr_blocks contains "0.0.0.0/0" {
138+
print("Ingress block #", ingress_count, "of security group",
139+
address, "contains disallowed cidr_block 0.0.0.0/0" )
140+
validated = false
141+
}
142+
} // end cidr_blocks.# computed check
143+
144+
# increment ingress_count
145+
ingress_count += 1
146+
147+
} // end ingress loop
148+
149+
} // end if r.applied.ingress a list
150+
} // end if diff[ingress.#] computed
151+
152+
} // end security group instances
87153

88154
return validated
89155
}
90156

91157
##### Rules #####
92158

93159
# Call the validation function and assign results
94-
sgrs_validated = validate_sgr_cidr_blocks()
160+
sgrs_validated = validate_cidr_blocks()
95161

96162
# Main rule
97163
main = rule {

governance/second-generation/aws/test/restrict-ingress-sg-rule-cidr-blocks/mock-tfplan-fail-0.11.sentinel

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,205 @@ _modules = {
55
"data": {},
66
"path": [],
77
"resources": {
8+
"aws_security_group": {
9+
"allow_tls": {
10+
0: {
11+
"applied": {
12+
"arn": "74D93920-ED26-11E3-AC10-0800200C9A66",
13+
"description": "Allow TLS inbound traffic",
14+
"egress": "74D93920-ED26-11E3-AC10-0800200C9A66",
15+
"id": "74D93920-ED26-11E3-AC10-0800200C9A66",
16+
"ingress": [
17+
{
18+
"cidr_blocks": [],
19+
"description": "",
20+
"from_port": "443",
21+
"ipv6_cidr_blocks": [],
22+
"prefix_list_ids": [],
23+
"protocol": "tcp",
24+
"security_groups": [],
25+
"self": true,
26+
"to_port": "443",
27+
},
28+
{
29+
"cidr_blocks": [
30+
"0.0.0.0/0",
31+
],
32+
"description": "",
33+
"from_port": "444",
34+
"ipv6_cidr_blocks": [],
35+
"prefix_list_ids": [],
36+
"protocol": "tcp",
37+
"security_groups": [],
38+
"self": false,
39+
"to_port": "444",
40+
},
41+
],
42+
"name": "allow_tls",
43+
"owner_id": "74D93920-ED26-11E3-AC10-0800200C9A66",
44+
"revoke_rules_on_delete": false,
45+
"tags": {
46+
"Name": "allow_all",
47+
},
48+
"vpc_id": "74D93920-ED26-11E3-AC10-0800200C9A66",
49+
},
50+
"destroy": false,
51+
"diff": {
52+
"arn": {
53+
"computed": true,
54+
"new": "",
55+
"old": "",
56+
},
57+
"description": {
58+
"computed": false,
59+
"new": "Allow TLS inbound traffic",
60+
"old": "",
61+
},
62+
"egress.#": {
63+
"computed": true,
64+
"new": "",
65+
"old": "",
66+
},
67+
"id": {
68+
"computed": true,
69+
"new": "",
70+
"old": "",
71+
},
72+
"ingress.#": {
73+
"computed": false,
74+
"new": "2",
75+
"old": "",
76+
},
77+
"ingress.3167104115.cidr_blocks.#": {
78+
"computed": false,
79+
"new": "0",
80+
"old": "",
81+
},
82+
"ingress.3167104115.description": {
83+
"computed": false,
84+
"new": "",
85+
"old": "",
86+
},
87+
"ingress.3167104115.from_port": {
88+
"computed": false,
89+
"new": "443",
90+
"old": "",
91+
},
92+
"ingress.3167104115.ipv6_cidr_blocks.#": {
93+
"computed": false,
94+
"new": "0",
95+
"old": "",
96+
},
97+
"ingress.3167104115.prefix_list_ids.#": {
98+
"computed": false,
99+
"new": "0",
100+
"old": "",
101+
},
102+
"ingress.3167104115.protocol": {
103+
"computed": false,
104+
"new": "tcp",
105+
"old": "",
106+
},
107+
"ingress.3167104115.security_groups.#": {
108+
"computed": false,
109+
"new": "0",
110+
"old": "",
111+
},
112+
"ingress.3167104115.self": {
113+
"computed": false,
114+
"new": "true",
115+
"old": "",
116+
},
117+
"ingress.3167104115.to_port": {
118+
"computed": false,
119+
"new": "443",
120+
"old": "",
121+
},
122+
"ingress.4122917492.cidr_blocks.#": {
123+
"computed": false,
124+
"new": "1",
125+
"old": "",
126+
},
127+
"ingress.4122917492.cidr_blocks.0": {
128+
"computed": false,
129+
"new": "0.0.0.0/0",
130+
"old": "",
131+
},
132+
"ingress.4122917492.description": {
133+
"computed": false,
134+
"new": "",
135+
"old": "",
136+
},
137+
"ingress.4122917492.from_port": {
138+
"computed": false,
139+
"new": "444",
140+
"old": "",
141+
},
142+
"ingress.4122917492.ipv6_cidr_blocks.#": {
143+
"computed": false,
144+
"new": "0",
145+
"old": "",
146+
},
147+
"ingress.4122917492.prefix_list_ids.#": {
148+
"computed": false,
149+
"new": "0",
150+
"old": "",
151+
},
152+
"ingress.4122917492.protocol": {
153+
"computed": false,
154+
"new": "tcp",
155+
"old": "",
156+
},
157+
"ingress.4122917492.security_groups.#": {
158+
"computed": false,
159+
"new": "0",
160+
"old": "",
161+
},
162+
"ingress.4122917492.self": {
163+
"computed": false,
164+
"new": "false",
165+
"old": "",
166+
},
167+
"ingress.4122917492.to_port": {
168+
"computed": false,
169+
"new": "444",
170+
"old": "",
171+
},
172+
"name": {
173+
"computed": false,
174+
"new": "allow_tls",
175+
"old": "",
176+
},
177+
"owner_id": {
178+
"computed": true,
179+
"new": "",
180+
"old": "",
181+
},
182+
"revoke_rules_on_delete": {
183+
"computed": false,
184+
"new": "false",
185+
"old": "",
186+
},
187+
"tags.%": {
188+
"computed": false,
189+
"new": "1",
190+
"old": "",
191+
},
192+
"tags.Name": {
193+
"computed": false,
194+
"new": "allow_all",
195+
"old": "",
196+
},
197+
"vpc_id": {
198+
"computed": true,
199+
"new": "",
200+
"old": "",
201+
},
202+
},
203+
"requires_new": false,
204+
},
205+
},
206+
},
8207
"aws_security_group_rule": {
9208
"allow_all": {
10209
0: {

0 commit comments

Comments
 (0)