Skip to content

Commit aa9d51b

Browse files
committed
blacklist providers and datasources
1 parent 9c8f3be commit aa9d51b

24 files changed

+1561
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# This policy prevents the use of blacklisted datasources
2+
# using the tfconfig import
3+
4+
##### Imports #####
5+
import "tfconfig"
6+
import "strings"
7+
8+
##### Functions #####
9+
10+
# Find all datasources of specific type from all modules
11+
# using the tfconfig import
12+
find_datasources_from_config = func(type) {
13+
14+
datasources = {}
15+
16+
# Iterate over all modules in the tfconfig import
17+
for tfconfig.module_paths as path {
18+
# Iterate over the named datasources of desired type in the module
19+
for tfconfig.module(path).data[type] else {} as name, d {
20+
21+
# Get the address of the datasource
22+
if length(path) == 0 {
23+
# root module
24+
address = type + "." + name
25+
} else {
26+
# non-root module
27+
address = "module." + strings.join(path, ".module.") + "." +
28+
type + "." + name
29+
}
30+
31+
# Add the datasource to datasources map, setting the key to the address
32+
datasources[address] = d
33+
}
34+
}
35+
36+
return datasources
37+
}
38+
39+
40+
# Validate that blacklisted datasources are not present
41+
validate_datasources = func(blacklist) {
42+
valid = true
43+
44+
for blacklist as type {
45+
found_datasources = find_datasources_from_config(type)
46+
47+
for found_datasources as address, d {
48+
print("Blacklisted datasource", address, "was found")
49+
valid = false
50+
}
51+
}
52+
return valid
53+
}
54+
55+
##### Lists #####
56+
57+
# List of blacklisted datasources
58+
blacklist = [
59+
"external",
60+
"http",
61+
]
62+
63+
##### Rules #####
64+
65+
# Main rule
66+
datasources_validated = validate_datasources(blacklist)
67+
main = rule {
68+
datasources_validated
69+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# This policy uses the tfconfig import to blacklist specified providers
2+
# across all modules
3+
4+
##### Imports #####
5+
import "tfconfig"
6+
import "strings"
7+
8+
##### Functions #####
9+
10+
# Prevent providers in non-root modules
11+
validate_providers = func(blacklist) {
12+
13+
validated = true
14+
15+
# Iterate over all modules in the tfconfig import
16+
for tfconfig.module_paths as path {
17+
providers = tfconfig.module(path).providers
18+
# Iterate over providers of the module
19+
for providers as provider {
20+
if provider in blacklist {
21+
if length(path) is 0 {
22+
print("The root module has provider", provider,
23+
"from the blacklist:", blacklist )
24+
} else {
25+
print("The module module." + strings.join(path, ".module."),
26+
"has provider", provider, "from the blacklist:", blacklist )
27+
}
28+
29+
validated = false
30+
} // end provider check
31+
} // end providers loop
32+
} // end module loop
33+
34+
return validated
35+
}
36+
37+
##### Lists #####
38+
39+
# List of blacklisted providers
40+
blacklist = [
41+
"external",
42+
"http",
43+
]
44+
45+
##### Rules #####
46+
47+
# Main rule
48+
providers_validated = validate_providers(blacklist)
49+
main = rule {
50+
providers_validated
51+
}
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+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import "strings"
2+
import "types"
3+
4+
_modules = {
5+
"root": {
6+
"data": {
7+
"external": {
8+
"example": {
9+
"config": {
10+
"program": [
11+
"./datasource-example.sh",
12+
],
13+
},
14+
"provisioners": null,
15+
},
16+
},
17+
"http": {
18+
"example": {
19+
"config": {
20+
"url": "https://checkpoint-api.hashicorp.com/v1/check/terraform",
21+
},
22+
"provisioners": null,
23+
},
24+
},
25+
},
26+
"modules": {},
27+
"outputs": {},
28+
"providers": {},
29+
"resources": {},
30+
"variables": {},
31+
},
32+
33+
"module.first": {
34+
"data": {
35+
"external": {
36+
"example": {
37+
"config": {
38+
"program": [
39+
"./datasource-example.sh",
40+
],
41+
},
42+
"provisioners": null,
43+
},
44+
},
45+
},
46+
"modules": {},
47+
"outputs": {},
48+
"providers": {
49+
"external": {
50+
"alias": {
51+
"": {
52+
"config": {},
53+
"version": "",
54+
},
55+
},
56+
"config": {},
57+
"version": "",
58+
},
59+
},
60+
"resources": {},
61+
"variables": {},
62+
},
63+
}
64+
65+
module_paths = [
66+
[],
67+
[
68+
"first",
69+
],
70+
]
71+
72+
module = func(path) {
73+
if types.type_of(path) is not "list" {
74+
error("expected list, got", types.type_of(path))
75+
}
76+
77+
if length(path) < 1 {
78+
return _modules.root
79+
}
80+
81+
addr = []
82+
for path as p {
83+
append(addr, "module")
84+
append(addr, p)
85+
}
86+
87+
return _modules[strings.join(addr, ".")]
88+
}
89+
90+
data = _modules.root.data
91+
modules = _modules.root.modules
92+
providers = _modules.root.providers
93+
resources = _modules.root.resources
94+
variables = _modules.root.variables
95+
outputs = _modules.root.outputs
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import "strings"
2+
import "types"
3+
4+
_modules = {
5+
"root": {
6+
"data": {
7+
"external": {
8+
"example": {
9+
"config": {
10+
"program": [
11+
"./datasource-example.sh",
12+
],
13+
},
14+
"provisioners": null,
15+
"references": {
16+
"program": [],
17+
},
18+
},
19+
},
20+
"http": {
21+
"example": {
22+
"config": {
23+
"url": "https://checkpoint-api.hashicorp.com/v1/check/terraform",
24+
},
25+
"provisioners": null,
26+
"references": {
27+
"url": [],
28+
},
29+
},
30+
},
31+
},
32+
"modules": {},
33+
"outputs": {},
34+
"providers": {
35+
"external": {
36+
"alias": {
37+
"": {
38+
"config": {},
39+
"references": {},
40+
"version": "",
41+
},
42+
},
43+
"config": {},
44+
"references": {},
45+
"version": "",
46+
},
47+
"http": {
48+
"alias": {
49+
"": {
50+
"config": {},
51+
"references": {},
52+
"version": "",
53+
},
54+
},
55+
"config": {},
56+
"references": {},
57+
"version": "",
58+
},
59+
},
60+
"resources": {},
61+
"variables": {},
62+
},
63+
64+
"module.first": {
65+
"data": {
66+
"external": {
67+
"example": {
68+
"config": {
69+
"program": [
70+
"./datasource-example.sh",
71+
],
72+
},
73+
"provisioners": null,
74+
"references": {
75+
"program": [],
76+
},
77+
},
78+
},
79+
},
80+
"modules": {},
81+
"outputs": {},
82+
"providers": {
83+
"external": {
84+
"alias": {
85+
"": {
86+
"config": {},
87+
"references": {},
88+
"version": "",
89+
},
90+
},
91+
"config": {},
92+
"references": {},
93+
"version": "",
94+
},
95+
},
96+
"resources": {},
97+
"variables": {},
98+
},
99+
}
100+
101+
module_paths = [
102+
[],
103+
[
104+
"first",
105+
],
106+
]
107+
108+
module = func(path) {
109+
if types.type_of(path) is not "list" {
110+
error("expected list, got", types.type_of(path))
111+
}
112+
113+
if length(path) < 1 {
114+
return _modules.root
115+
}
116+
117+
addr = []
118+
for path as p {
119+
append(addr, "module")
120+
append(addr, p)
121+
}
122+
123+
return _modules[strings.join(addr, ".")]
124+
}
125+
126+
data = _modules.root.data
127+
modules = _modules.root.modules
128+
providers = _modules.root.providers
129+
resources = _modules.root.resources
130+
variables = _modules.root.variables
131+
outputs = _modules.root.outputs

0 commit comments

Comments
 (0)