forked from Azure/terraform-azurerm-caf-enterprise-scale
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocals.policy_assignments.tf
250 lines (233 loc) · 10.5 KB
/
locals.policy_assignments.tf
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# The following locals are used to extract the Policy Assignment
# configuration from the archetype module outputs.
locals {
es_policy_assignments_by_management_group = flatten([
for archetype in values(module.management_group_archetypes) :
archetype.configuration.azurerm_policy_assignment
])
es_policy_assignments_by_subscription = []
es_policy_assignments = concat(
local.es_policy_assignments_by_management_group,
local.es_policy_assignments_by_subscription,
)
}
# The following locals are used to build the map of Policy
# Assignments to deploy and then split them by scope type.
locals {
azurerm_policy_assignment_enterprise_scale = {
for assignment in local.es_policy_assignments :
assignment.resource_id => assignment
}
azurerm_management_group_policy_assignment_enterprise_scale = {
for pak, pav in local.azurerm_policy_assignment_enterprise_scale :
pak => pav
if length(regexall(local.regex_scope_is_management_group, pav.scope_id)) > 0
}
}
# To support the creation of Role Assignments for Policy Assignments
# using a Managed Identity, we need to identify the associated
# Role Definition(s) relating to the assigned Policy [Set] Definition
# within each Policy Assignment. This requires the following logic
# to determine which Role Assignments to create.
# Generate a list of internal Policy Definitions and Policy
# Set Definitions.
locals {
internal_policy_definition_ids = [
for policy_definition in local.es_policy_definitions :
policy_definition.resource_id
]
internal_policy_set_definition_ids = [
for policy_set_definition in local.es_policy_set_definitions :
policy_set_definition.resource_id
]
}
# Determine which Policy Assignments use a Managed Identity.
locals {
policy_assignments_with_managed_identity = {
for assignment in local.es_policy_assignments :
assignment.resource_id => assignment.template.properties.policyDefinitionId
if assignment.template.identity.type == "SystemAssigned"
}
}
# Determine which of these Policy Assignments assign a Policy
# Definition or Policy Set Definition which is either built-in,
# or deployed to Azure using a process outside of this module.
locals {
# Policy Definitions
policy_assignments_with_managed_identity_using_external_policy_definition = {
for policy_assignment_id, policy_definition_id in local.policy_assignments_with_managed_identity :
policy_assignment_id => [
policy_definition_id,
]
if length(regexall(local.resource_types.policy_definition, policy_definition_id)) > 0
&& contains(local.internal_policy_definition_ids, policy_definition_id) != true
&& contains(keys(local.custom_policy_roles), policy_definition_id) != true
}
# Policy Set Definitions
policy_assignments_with_managed_identity_using_external_policy_set_definition = {
for policy_assignment_id, policy_set_definition_id in local.policy_assignments_with_managed_identity :
policy_assignment_id => [
policy_set_definition_id,
]
if length(regexall(local.resource_types.policy_set_definition, policy_set_definition_id)) > 0
&& contains(local.internal_policy_set_definition_ids, policy_set_definition_id) != true
&& contains(keys(local.custom_policy_roles), policy_set_definition_id) != true
}
}
# Generate list of Policy Set Definitions to lookup from Azure.
locals {
azurerm_policy_set_definition_external_lookup = {
for policy_set_definition_id in keys(transpose(local.policy_assignments_with_managed_identity_using_external_policy_set_definition)) :
policy_set_definition_id => {
name = basename(policy_set_definition_id)
management_group_name = regex(local.regex_split_resource_id, policy_set_definition_id)[0] == "/providers/Microsoft.Management/managementGroups/" ? regex(local.regex_split_resource_id, policy_set_definition_id)[1] : null
}
}
}
# Perform a lookup of the Policy Set Definitions not deployed by this module.
data "azurerm_policy_set_definition" "external_lookup" {
for_each = local.azurerm_policy_set_definition_external_lookup
name = each.value.name
management_group_name = each.value.management_group_name
}
# Create a list of Policy Definitions IDs used by all assigned Policy Set Definitions
locals {
policy_definition_ids_from_internal_policy_set_definitions = {
for policy_set_definition in local.es_policy_set_definitions :
policy_set_definition.resource_id => [
for policy_definition in policy_set_definition.template.properties.policyDefinitions :
policy_definition.policyDefinitionId
]
}
policy_definition_ids_from_external_policy_set_definitions = {
for policy_set_definition_id, policy_set_definition_config in data.azurerm_policy_set_definition.external_lookup :
policy_set_definition_id => [
for policy_definition in policy_set_definition_config.policy_definition_reference :
policy_definition.policy_definition_id
]
}
policy_definition_ids_from_policy_set_definitions = merge(
local.policy_definition_ids_from_internal_policy_set_definitions,
local.policy_definition_ids_from_external_policy_set_definitions,
)
}
# Identify all Policy Definitions which are external to this module
locals {
# From Policy Assignments using Policy Set Definitions
external_policy_definition_ids_from_policy_set_definitions = distinct(flatten([
for policy_definition_ids in values(local.policy_definition_ids_from_policy_set_definitions) : [
for policy_definition_id in policy_definition_ids :
policy_definition_id
if contains(local.internal_policy_definition_ids, policy_definition_id) != true
]
]))
external_policy_definitions_from_azurerm_policy_set_definition_external_lookup = {
for policy_definition_id in local.external_policy_definition_ids_from_policy_set_definitions :
policy_definition_id => {
name = basename(policy_definition_id)
management_group_name = regex(local.regex_split_resource_id, policy_definition_id)[0] == "/providers/Microsoft.Management/managementGroups/" ? regex(local.regex_split_resource_id, policy_definition_id)[1] : null
}
}
# From Policy Assignments using Policy Definitions
external_policy_definitions_from_internal_policy_assignments = {
for policy_definition_id in keys(transpose(local.policy_assignments_with_managed_identity_using_external_policy_definition)) :
policy_definition_id => {
name = basename(policy_definition_id)
management_group_name = regex(local.regex_split_resource_id, policy_definition_id)[0] == "/providers/Microsoft.Management/managementGroups/" ? regex(local.regex_split_resource_id, policy_definition_id)[1] : null
}
}
# Then create a single list containing all Policy Definitions to lookup from Azure
azurerm_policy_definition_external_lookup = merge(
local.external_policy_definitions_from_azurerm_policy_set_definition_external_lookup,
local.external_policy_definitions_from_internal_policy_assignments,
)
}
# Perform a lookup of the Policy Definitions not deployed by this module.
data "azurerm_policy_definition" "external_lookup" {
for_each = local.azurerm_policy_definition_external_lookup
name = each.value.name
management_group_name = each.value.management_group_name
}
# Extract the Role Definition IDs from the internal and external
# Policy Definitions, then combine into a single lookup map.
# Loop on list of roleDefinitionIds ensures correct character
# case to prevent duplicate values
locals {
internal_policy_definition_roles = {
for policy_definition in local.es_policy_definitions :
policy_definition.resource_id => try(
[
for role_definition in policy_definition.template.properties.policyRule.then.details.roleDefinitionIds :
"/providers/Microsoft.Authorization/roleDefinitions/${basename(role_definition)}"
],
local.empty_list
)
}
external_policy_definition_roles = {
for policy_definition_id, policy_definition_config in data.azurerm_policy_definition.external_lookup :
policy_definition_id => try(
[
for role_definition in jsondecode(policy_definition_config.policy_rule).then.details.roleDefinitionIds :
"/providers/Microsoft.Authorization/roleDefinitions/${basename(role_definition)}"
],
local.empty_list
)
}
policy_definition_roles = merge(
local.internal_policy_definition_roles,
local.external_policy_definition_roles,
)
}
# Merge the map of Policy Definitions from internal and
# external Policy Set Definitions then generate the map
# of roles for each.
locals {
policy_set_definition_roles = {
for policy_set_definition_id, policy_definition_ids in local.policy_definition_ids_from_policy_set_definitions :
policy_set_definition_id => distinct(flatten([
for policy_definition_id in policy_definition_ids :
local.policy_definition_roles[policy_definition_id]
]))
}
}
# Merge the map of roles for Policy Definitions and
# Policy Set Definitions.
locals {
policy_roles = merge(
local.policy_definition_roles,
local.policy_set_definition_roles,
local.custom_policy_roles
)
}
# Generate a list of principal_id values by Policy Assignment
locals {
merge_policy_assignments_by_type = merge(
azurerm_management_group_policy_assignment.enterprise_scale,
)
principal_id_by_policy_assignment = {
for pak, pav in local.merge_policy_assignments_by_type :
pak => try(pav.identity[0].principal_id, null)
}
}
# Construct the array used to determine the list of
# Role Assignments to create for the Managed Identities
# used by Policy Assignments.
# The "identity" object is an array containing a single
# identity item.
# The try() logic below is to prevent errors when running
# 'terraform destroy'.
locals {
es_role_assignments_by_policy_assignment = flatten([
for policy_assignment_id, policy_id in local.policy_assignments_with_managed_identity : [
for role_definition_id in try(local.policy_roles[policy_id], local.empty_list) : [
{
resource_id = "${local.azurerm_policy_assignment_enterprise_scale[policy_assignment_id].scope_id}${local.provider_path.role_assignment}${uuidv5(uuidv5("url", role_definition_id), policy_assignment_id)}"
scope_id = local.azurerm_policy_assignment_enterprise_scale[policy_assignment_id].scope_id
principal_id = try(local.principal_id_by_policy_assignment[policy_assignment_id], null)
role_definition_name = null
role_definition_id = role_definition_id
}
]
]
])
}