Skip to content

Commit 38385e1

Browse files
committed
added prevent-non-root-providers.sentinel
1 parent f854f7f commit 38385e1

File tree

9 files changed

+853
-0
lines changed

9 files changed

+853
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# This policy uses the tfconfig import to prevent providers from being declared
2+
# in non-root modules, aligning with the best practices given in:
3+
# https://www.terraform.io/docs/configuration/modules.html
4+
5+
##### Imports #####
6+
import "tfconfig"
7+
import "strings"
8+
9+
##### Functions #####
10+
11+
# Prevent providers in non-root modules
12+
prevent_non_root_providers = func() {
13+
14+
validated = true
15+
16+
# Iterate over all modules in the tfconfig import
17+
for tfconfig.module_paths as path {
18+
# Check non-root modules
19+
if length(path) > 0 {
20+
# Iterate over providers of given type in module
21+
providers = tfconfig.module(path).providers
22+
if length(providers) > 0 {
23+
print("Module module." + strings.join(path, ".module.") +
24+
" has providers.")
25+
validated = false
26+
}
27+
}
28+
}
29+
30+
return validated
31+
}
32+
33+
##### Rules #####
34+
35+
# Main rule
36+
providers_validated = prevent_non_root_providers()
37+
main = rule {
38+
providers_validated
39+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"mock": {
3+
"tfconfig": "mock-tfconfig-fail-0.11.sentinel"
4+
},
5+
"test": {
6+
"main": false
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"mock": {
3+
"tfconfig": "mock-tfconfig-fail-0.12.sentinel"
4+
},
5+
"test": {
6+
"main": false
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import "strings"
2+
import "types"
3+
4+
_modules = {
5+
"root": {
6+
"data": {},
7+
"modules": {
8+
"first": {
9+
"config": {},
10+
"source": "./module",
11+
"version": "",
12+
},
13+
},
14+
"outputs": {},
15+
"providers": {
16+
"aws": {
17+
"alias": {
18+
"": {
19+
"config": {
20+
"region": "us-east-2",
21+
},
22+
"version": "",
23+
},
24+
"root-east": {
25+
"config": {
26+
"region": "us-east-1",
27+
},
28+
"version": "",
29+
},
30+
"root-west": {
31+
"config": {
32+
"region": "us-west-1",
33+
},
34+
"version": "",
35+
},
36+
},
37+
"config": {
38+
"region": "us-east-2",
39+
},
40+
"version": "",
41+
},
42+
},
43+
"resources": {
44+
"aws_instance": {
45+
"web": {
46+
"config": {
47+
"ami": "ami-2e1ef954",
48+
"instance_type": "t2.micro",
49+
"tags": [
50+
{
51+
"Name": "root module instance",
52+
},
53+
],
54+
},
55+
"provisioners": null,
56+
},
57+
},
58+
},
59+
"variables": {},
60+
},
61+
62+
"module.first": {
63+
"data": {},
64+
"modules": {
65+
"second": {
66+
"config": {},
67+
"source": "./module",
68+
"version": "",
69+
},
70+
},
71+
"outputs": {},
72+
"providers": {
73+
"aws": {
74+
"alias": {
75+
"": {
76+
"config": {
77+
"region": "us-east-2",
78+
},
79+
"version": "",
80+
},
81+
"first-east": {
82+
"config": {
83+
"region": "us-east-1",
84+
},
85+
"version": "",
86+
},
87+
"first-west": {
88+
"config": {
89+
"region": "us-west-1",
90+
},
91+
"version": "",
92+
},
93+
},
94+
"config": {
95+
"region": "us-east-2",
96+
},
97+
"version": "",
98+
},
99+
},
100+
"resources": {
101+
"aws_instance": {
102+
"web": {
103+
"config": {
104+
"ami": "ami-2e1ef954",
105+
"instance_type": "t2.micro",
106+
"tags": [
107+
{
108+
"Name": "first module instance",
109+
},
110+
],
111+
},
112+
"provisioners": null,
113+
},
114+
},
115+
},
116+
"variables": {},
117+
},
118+
119+
"module.first.module.second": {
120+
"data": {},
121+
"modules": {},
122+
"outputs": {},
123+
"providers": {
124+
"aws": {
125+
"alias": {
126+
"": {
127+
"config": {
128+
"region": "us-east-2",
129+
},
130+
"version": "",
131+
},
132+
"second-east": {
133+
"config": {
134+
"region": "us-east-1",
135+
},
136+
"version": "",
137+
},
138+
"second-west": {
139+
"config": {
140+
"region": "us-west-1",
141+
},
142+
"version": "",
143+
},
144+
},
145+
"config": {
146+
"region": "us-east-2",
147+
},
148+
"version": "",
149+
},
150+
},
151+
"resources": {
152+
"aws_instance": {
153+
"web": {
154+
"config": {
155+
"ami": "ami-2e1ef954",
156+
"instance_type": "t2.micro",
157+
"tags": [
158+
{
159+
"Name": "second module instance",
160+
},
161+
],
162+
},
163+
"provisioners": null,
164+
},
165+
},
166+
},
167+
"variables": {},
168+
},
169+
}
170+
171+
module_paths = [
172+
[],
173+
[
174+
"first",
175+
],
176+
[
177+
"first",
178+
"second",
179+
],
180+
]
181+
182+
module = func(path) {
183+
if types.type_of(path) is not "list" {
184+
error("expected list, got", types.type_of(path))
185+
}
186+
187+
if length(path) < 1 {
188+
return _modules.root
189+
}
190+
191+
addr = []
192+
for path as p {
193+
append(addr, "module")
194+
append(addr, p)
195+
}
196+
197+
return _modules[strings.join(addr, ".")]
198+
}
199+
200+
data = _modules.root.data
201+
modules = _modules.root.modules
202+
providers = _modules.root.providers
203+
resources = _modules.root.resources
204+
variables = _modules.root.variables
205+
outputs = _modules.root.outputs

0 commit comments

Comments
 (0)