-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenforce_https.sentinel
147 lines (129 loc) · 4 KB
/
enforce_https.sentinel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
##### restrict-app-service-to-https.sentinel #####
# This policy uses the Sentinel tfplan import to require that
# all Azure app services have https_only set to true so that
# they can only be accessed via HTTPS
##### Imports #####
import "tfplan/v2" as tfplan
import "strings"
import "types"
##### Functions #####
### find_resources ###
find_resources = func(type) {
resources = filter tfplan.resource_changes as address, rc {
rc.type is type and
rc.mode is "managed" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
return resources
}
### filter_attribute_is_not_value ###
filter_attribute_is_not_value = func(resources, attr, value, prtmsg) {
violators = {}
messages = {}
for resources as address, rc {
v = evaluate_attribute(rc, attr) else null
if v is null {
# Add the resource and a warning message to the violators list
message = to_string(address) + " has " + to_string(attr) +
" that is null or undefined"
violators[address] = rc
messages[address] = message
if prtmsg {
print(message)
}
} else if v is not value {
# Add the resource and a warning message to the violators list
message = to_string(address) + " has " + to_string(attr) + " with value " +
to_string(v) + " that is not equal to " + to_string(value)
violators[address] = rc
messages[address] = message
if prtmsg {
print(message)
}
}
}
return {"resources":violators,"messages":messages}
}
### evaluate_attribute ###
evaluate_attribute = func(r, attribute) {
# Split the attribute into a list, using "." as the separator
attributes = strings.split(attribute, ".")
# Convert numeric strings to integers for indices
if attributes[0] matches "^[0-9]+$" {
a = int(attributes[0])
# Make sure r is of type list
if types.type_of(r) is not "list" {
return undefined
}
} else {
a = attributes[0]
}
# Append the current attribute to the resource instance
if (types.type_of(r) is "map" and "change" in keys(r)) and
(types.type_of(r.change) is "map" and "after" in keys(r.change)) {
new_r = r.change.after[a] else null
} else {
new_r = r[a] else null
}
# Process based on length of attributes
# being greater than or equal to 1
if length(attributes) > 1 {
# Strip first element from attributes
attributes = attributes[1:length(attributes)]
attribute = strings.join(attributes, ".")
# Make recursive call
return evaluate_attribute(new_r, attribute)
} else {
# We reached the end of the attribute and can stop the
# recursive calls and return the value of the attribute
return new_r
}
}
### to_string ###
to_string = func(obj) {
case types.type_of(obj) {
when "string":
return obj
when "int", "float", "bool":
return string(obj)
when "null":
return "null"
when "undefined":
return "undefined"
when "list":
output = "["
lastIndex = length(obj) - 1
for obj as index, value {
if index < lastIndex {
output += to_string(value) + ", "
} else {
output += to_string(value) + "]"
}
}
return output
when "map":
output = "{"
theKeys = keys(obj)
lastIndex = length(theKeys) - 1
for theKeys as index, key {
if index < lastIndex {
output += to_string(key) + ": " + to_string(obj[key]) + ", "
} else {
output += to_string(key) + ": " + to_string(obj[key]) + "}"
}
}
return output
else:
return ""
}
}
# Get all Azure app services
allAzureAppServices = find_resources("azurerm_app_service")
# Filter to Azure app services with violations
# Warnings will be printed for all violations since the last parameter is true
violatingAzureAppServices = filter_attribute_is_not_value(allAzureAppServices,
"https_only", true, true)
# Main rule
main = rule {
length(violatingAzureAppServices["messages"]) is 0
}