-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.tf
More file actions
383 lines (329 loc) · 16.9 KB
/
Copy pathmain.tf
File metadata and controls
383 lines (329 loc) · 16.9 KB
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
locals {
# Wrapper metadata
mcd_wrapper_version = "1.0.5"
mcd_agent_platform = "AZURE"
mcd_agent_deployment_type = "TERRAFORM"
# Docker properties
docker_scheme = "https"
docker_registry_url = "docker.io"
mcd_agent_name = split(":", var.image)[0]
mcd_agent_tag = split(":", var.image)[1]
# Service properties
mcd_agent_naming_prefix = "mcd-agent"
# Data store properties
mcd_agent_store_container_name = "mcdstore"
mcd_agent_store_data_prefix = "mcd"
# Function properties
mcd_agent_function_name = "${local.mcd_agent_naming_prefix}-service-${random_id.mcd_agent_id.hex}"
mcd_agent_identity_types = "UserAssigned"
mcd_agent_function_app_settings_base = {
# Function configuration
always_on = true
AzureWebJobsDisableHomepage = true
FUNCTION_APP_EDIT_MODE = "readOnly"
FUNCTIONS_EXTENSION_VERSION = "~4"
DOCKER_REGISTRY_SERVER_URL = "${local.docker_scheme}://${local.docker_registry_url}"
DOCKER_CUSTOM_IMAGE_NAME = "${local.docker_registry_url}/${var.image}"
WEBSITES_ENABLE_APP_SERVICE_STORAGE = false
AZURE_CLIENT_ID = azurerm_user_assigned_identity.mcd_agent_service_identity.client_id
APPINSIGHTS_RESOURCE_ID = azurerm_application_insights.mcd_agent_service_insights.id
FUNCTIONS_WORKER_PROCESS_COUNT = 5
PYTHON_THREADPOOL_THREAD_COUNT = 5
AzureFunctionsJobHost__extensions__durableTask__maxConcurrentActivityFunctions = 20
AzureFunctionsJobHost__functionTimeout = "00:15:00"
# MC properties and configuration
MCD_AGENT_IMAGE_TAG = var.image
MCD_AGENT_CLOUD_PLATFORM = local.mcd_agent_platform
MCD_AGENT_WRAPPER_TYPE = local.mcd_agent_deployment_type
MCD_AGENT_WRAPPER_VERSION = local.mcd_wrapper_version
MCD_AGENT_IS_REMOTE_UPGRADABLE : var.remote_upgradable ? "true" : "false"
MCD_STORAGE_ACCOUNT_NAME = local.agent_data_storage_account_name
MCD_STORAGE_BUCKET_NAME = local.agent_data_storage_container_name
MCD_AUTH_TYPE = var.auth_type
}
mcd_agent_function_app_settings = try(var.existing_storage_accounts.private_access, false) ? merge({
"WEBSITE_CONTENTOVERVNET" = "1"
"WEBSITE_CONTENTSHARE" = var.existing_storage_accounts.agent_durable_function_storage_account_share_name
}, local.mcd_agent_function_app_settings_base) : local.mcd_agent_function_app_settings_base
}
resource "random_id" "mcd_agent_id" {
byte_length = 4
}
## ---------------------------------------------------------------------------------------------------------------------
## Agent Resources
## MCD agent core components: Azure function for service execution and storage for troubleshooting and temporary data.
## See details here: https://docs.getmontecarlo.com/docs/platform-architecture#customer-hosted-agent--object-storage-deployment
## ---------------------------------------------------------------------------------------------------------------------
resource "azurerm_resource_group" "mcd_agent_rg" {
count = var.existing_resource_group_name == null ? 1 : 0
name = "${local.mcd_agent_naming_prefix}-group-${random_id.mcd_agent_id.hex}"
location = var.location
}
locals {
mcd_agent_resource_group_name = var.existing_resource_group_name == null ? azurerm_resource_group.mcd_agent_rg[0].name : var.existing_resource_group_name
mcd_agent_resource_group_location = var.existing_resource_group_name == null ? azurerm_resource_group.mcd_agent_rg[0].location : var.location
use_existing_storage_accounts = var.existing_storage_accounts != null
}
resource "azurerm_storage_account" "mcd_agent_storage" {
count = local.use_existing_storage_accounts ? 0 : 2
name = "mcdagent${count.index}fs${random_id.mcd_agent_id.hex}"
resource_group_name = local.mcd_agent_resource_group_name
location = local.mcd_agent_resource_group_location
account_tier = "Standard"
account_replication_type = "GRS"
https_traffic_only_enabled = true
allow_nested_items_to_be_public = false
infrastructure_encryption_enabled = true
} # Key: Index 0 - Function Storage (e.g. durable function data). Index 1 - App storage (e.g. MC sampling)
locals {
durable_function_storage_account_name = local.use_existing_storage_accounts ? var.existing_storage_accounts.agent_durable_function_storage_account_name : azurerm_storage_account.mcd_agent_storage[0].name
durable_function_storage_access_key = local.use_existing_storage_accounts ? var.existing_storage_accounts.agent_durable_function_storage_account_access_key : azurerm_storage_account.mcd_agent_storage[0].primary_access_key
agent_data_storage_account_name = local.use_existing_storage_accounts ? var.existing_storage_accounts.agent_data_storage_account_name : azurerm_storage_account.mcd_agent_storage[1].name
agent_data_storage_container_name = local.use_existing_storage_accounts ? var.existing_storage_accounts.agent_data_storage_container_name : local.mcd_agent_store_container_name
}
resource "azurerm_storage_container" "mcd_agent_storage_container" {
count = local.use_existing_storage_accounts ? 0 : 1
name = local.mcd_agent_store_container_name
storage_account_name = azurerm_storage_account.mcd_agent_storage[1].name
container_access_type = "private"
}
resource "azurerm_storage_management_policy" "mcd_agent_storage_lifecycle" {
count = local.use_existing_storage_accounts ? 0 : 1
storage_account_id = azurerm_storage_account.mcd_agent_storage[1].id
rule {
name = "obj-expiration"
enabled = true
filters {
blob_types = ["blockBlob", "appendBlob"]
prefix_match = ["${local.agent_data_storage_container_name}/${local.mcd_agent_store_data_prefix}"]
}
actions {
base_blob {
delete_after_days_since_creation_greater_than = 90
}
}
}
rule {
name = "temp-expiration"
enabled = true
filters {
blob_types = ["blockBlob", "appendBlob"]
prefix_match = ["${local.agent_data_storage_container_name}/${local.mcd_agent_store_data_prefix}/tmp"]
}
actions {
base_blob {
delete_after_days_since_creation_greater_than = 2
}
}
}
}
resource "azurerm_service_plan" "mcd_agent_service_plan" {
name = "${local.mcd_agent_naming_prefix}-service-plan"
resource_group_name = local.mcd_agent_resource_group_name
location = local.mcd_agent_resource_group_location
os_type = "Linux"
sku_name = "EP1"
}
resource "azurerm_log_analytics_workspace" "mcd_agent_service_analytics_workspace" {
name = "analytics-workspace-${local.mcd_agent_function_name}"
resource_group_name = local.mcd_agent_resource_group_name
location = local.mcd_agent_resource_group_location
sku = "PerGB2018"
retention_in_days = 30
}
resource "azurerm_application_insights" "mcd_agent_service_insights" {
name = "application-insights-${local.mcd_agent_function_name}"
resource_group_name = local.mcd_agent_resource_group_name
location = local.mcd_agent_resource_group_location
workspace_id = azurerm_log_analytics_workspace.mcd_agent_service_analytics_workspace.id
application_type = "other"
}
resource "azurerm_user_assigned_identity" "mcd_agent_service_identity" {
name = "${local.mcd_agent_function_name}-identity"
resource_group_name = local.mcd_agent_resource_group_name
location = local.mcd_agent_resource_group_location
}
resource "azurerm_role_assignment" "mcd_agent_storage_cont_ra" {
count = local.use_existing_storage_accounts ? 0 : 1
scope = azurerm_storage_account.mcd_agent_storage[1].id
principal_id = azurerm_user_assigned_identity.mcd_agent_service_identity.principal_id
role_definition_name = "Storage Blob Data Contributor"
}
resource "azurerm_role_assignment" "mcd_agent_storage_key_ra" {
count = local.use_existing_storage_accounts ? 0 : 1
scope = azurerm_storage_account.mcd_agent_storage[1].id
principal_id = azurerm_user_assigned_identity.mcd_agent_service_identity.principal_id
role_definition_name = "Storage Account Key Operator Service Role"
}
resource "azurerm_role_assignment" "mcd_agent_service_ra" {
scope = var.remote_upgradable ? azurerm_linux_function_app.mcd_agent_service_with_remote_upgrade_support[0].id : azurerm_linux_function_app.mcd_agent_service[0].id
principal_id = azurerm_user_assigned_identity.mcd_agent_service_identity.principal_id
role_definition_name = var.remote_upgradable ? "Contributor" : "Reader"
}
resource "azurerm_role_assignment" "mcd_agent_logs_ra" {
scope = azurerm_application_insights.mcd_agent_service_insights.id
principal_id = azurerm_user_assigned_identity.mcd_agent_service_identity.principal_id
role_definition_name = "Log Analytics Reader"
}
## ---------------------------------------------------------------------------------------------------------------------
## Entra ID Resources (Service Principal Auth)
## Conditional on auth_type == "AZURE_FUNCTION_SERVICE_PRINCIPAL". Creates app registrations and
## service principals for OAuth 2.0 client credentials grant authentication.
## ---------------------------------------------------------------------------------------------------------------------
data "azurerm_subscription" "current" {}
data "azuread_client_config" "current" {}
locals {
use_sp_auth = var.auth_type == "AZURE_FUNCTION_SERVICE_PRINCIPAL"
}
# Function App's app registration — defines the audience for token validation
resource "azuread_application" "mcd_agent_function_app" {
count = local.use_sp_auth ? 1 : 0
display_name = "${local.mcd_agent_function_name}-app"
identifier_uris = ["api://${local.mcd_agent_function_name}"]
api {
requested_access_token_version = 2
}
app_role {
allowed_member_types = ["Application"]
description = "Allow the application to access the Function App"
display_name = "FunctionApp.Call"
enabled = true
id = "d5495a08-1104-4689-a64f-7edbe6506a10"
value = "FunctionApp.Call"
}
}
resource "azuread_service_principal" "mcd_agent_function_app" {
count = local.use_sp_auth ? 1 : 0
client_id = azuread_application.mcd_agent_function_app[0].client_id
}
# Caller app registration — the identity Monte Carlo Platform uses to authenticate
resource "azuread_application" "mcd_agent_caller" {
count = local.use_sp_auth ? 1 : 0
display_name = "${local.mcd_agent_function_name}-caller"
}
resource "azuread_service_principal" "mcd_agent_caller" {
count = local.use_sp_auth ? 1 : 0
client_id = azuread_application.mcd_agent_caller[0].client_id
}
resource "azuread_application_password" "mcd_agent_caller_secret" {
count = local.use_sp_auth ? 1 : 0
application_id = azuread_application.mcd_agent_caller[0].id
display_name = "Monte Carlo Platform credential"
}
# Grant the caller service principal access to the Function App's API
resource "azuread_app_role_assignment" "mcd_agent_caller_access" {
count = local.use_sp_auth ? 1 : 0
app_role_id = one(azuread_application.mcd_agent_function_app[0].app_role).id
principal_object_id = azuread_service_principal.mcd_agent_caller[0].object_id
resource_object_id = azuread_service_principal.mcd_agent_function_app[0].object_id
}
resource "azurerm_linux_function_app" "mcd_agent_service" {
count = var.remote_upgradable ? 0 : 1
name = local.mcd_agent_function_name
resource_group_name = local.mcd_agent_resource_group_name
location = local.mcd_agent_resource_group_location
builtin_logging_enabled = false
storage_account_name = local.durable_function_storage_account_name
storage_account_access_key = local.durable_function_storage_access_key
service_plan_id = azurerm_service_plan.mcd_agent_service_plan.id
public_network_access_enabled = !var.disable_public_inbound
virtual_network_subnet_id = var.subnet_id
site_config {
application_insights_key = azurerm_application_insights.mcd_agent_service_insights.instrumentation_key
application_insights_connection_string = azurerm_application_insights.mcd_agent_service_insights.connection_string
application_stack {
docker {
registry_url = local.docker_registry_url
image_name = local.mcd_agent_name
image_tag = local.mcd_agent_tag
}
}
}
https_only = true
identity {
type = local.mcd_agent_identity_types
identity_ids = [azurerm_user_assigned_identity.mcd_agent_service_identity.id]
}
app_settings = local.mcd_agent_function_app_settings
dynamic "auth_settings_v2" {
for_each = local.use_sp_auth ? [1] : []
content {
auth_enabled = true
require_authentication = true
unauthenticated_action = "Return401"
active_directory_v2 {
client_id = azuread_application.mcd_agent_function_app[0].client_id
tenant_auth_endpoint = "https://login.microsoftonline.com/${data.azuread_client_config.current.tenant_id}/v2.0"
allowed_audiences = ["api://${local.mcd_agent_function_name}", azuread_application.mcd_agent_function_app[0].client_id]
}
login {}
}
}
lifecycle {
ignore_changes = [
site_config[0].application_stack[0].docker[0].registry_url,
app_settings["DOCKER_REGISTRY_SERVER_URL"],
app_settings["FUNCTIONS_EXTENSION_VERSION"],
tags["hidden-link: /app-insights-resource-id"],
]
} # Necessary due to a bug in the azure terraform provider where these values are re-applied sans scheme in every run
}
# Terraform lifecycle meta arguments do not support conditions so two copies of the resource are required to ignore
# remote (agent sourced) image upgrades.
resource "azurerm_linux_function_app" "mcd_agent_service_with_remote_upgrade_support" {
count = var.remote_upgradable ? 1 : 0
name = local.mcd_agent_function_name
resource_group_name = local.mcd_agent_resource_group_name
location = local.mcd_agent_resource_group_location
builtin_logging_enabled = false
storage_account_name = local.durable_function_storage_account_name
storage_account_access_key = local.durable_function_storage_access_key
service_plan_id = azurerm_service_plan.mcd_agent_service_plan.id
public_network_access_enabled = !var.disable_public_inbound
virtual_network_subnet_id = var.subnet_id
site_config {
application_insights_key = azurerm_application_insights.mcd_agent_service_insights.instrumentation_key
application_insights_connection_string = azurerm_application_insights.mcd_agent_service_insights.connection_string
application_stack {
docker {
registry_url = local.docker_registry_url
image_name = local.mcd_agent_name
image_tag = local.mcd_agent_tag
}
}
}
https_only = true
identity {
type = local.mcd_agent_identity_types
identity_ids = [azurerm_user_assigned_identity.mcd_agent_service_identity.id]
}
app_settings = local.mcd_agent_function_app_settings
dynamic "auth_settings_v2" {
for_each = local.use_sp_auth ? [1] : []
content {
auth_enabled = true
require_authentication = true
unauthenticated_action = "Return401"
active_directory_v2 {
client_id = azuread_application.mcd_agent_function_app[0].client_id
tenant_auth_endpoint = "https://login.microsoftonline.com/${data.azuread_client_config.current.tenant_id}/v2.0"
allowed_audiences = ["api://${local.mcd_agent_function_name}", azuread_application.mcd_agent_function_app[0].client_id]
}
login {}
}
}
lifecycle {
ignore_changes = [
site_config[0].application_stack[0],
app_settings["DOCKER_REGISTRY_SERVER_URL"],
app_settings["FUNCTIONS_EXTENSION_VERSION"],
app_settings["DOCKER_CUSTOM_IMAGE_NAME"],
app_settings["MCD_AGENT_IMAGE_TAG"],
app_settings["FUNCTIONS_WORKER_PROCESS_COUNT"],
app_settings["PYTHON_THREADPOOL_THREAD_COUNT"],
app_settings["AzureFunctionsJobHost__extensions__durableTask__maxConcurrentActivityFunctions"],
app_settings["AzureFunctionsJobHost__functionTimeout"],
tags["hidden-link: /app-insights-resource-id"],
]
}
}