Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

Terraform Azure function app with private endpoint and storage account

In this article I am creating Azure Function App linked to Private Endpoint and Storage Account using Terraform. This terraform configuration file will deploy all these resources within couple of minute.

In this automation Resource Group, User Assigned Identity, Virtual Network, Subnet, Private DNS Zone and Network Link is already exist on Azure cloud platform. On top of using already existing resources next new Service App Plan, Function App, Private Endpoint, Subnet Service delegation, Storage Account, User Assigned Identity role assignment, outbound connection will be created with the given variable inputs. Below is the entire terraform configuration.

  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
provider "azurerm" {
  features {}
}

######################################

variable "resource_group_name" {
  default = "dev"
}

variable "virtual_network" {
  default = "vcloud-lab-dev"
}

variable "subnet" {
  default = "default"
}

variable "private_dns_zone" {
  default = "privatelink.azurewebsites.net"
}

variable "user_assigned_identity" {
  default = "vcloudlabuser"
}

variable "private_dns_zone_virtual_network_link" {
  default = "vcloud-lab-dev-privatelink"
}

####

variable "storage_account_name" {
  default = "vcloudlabsa"
}

variable "app_service_plan" {
  default = "vcloudlabasp"
}

####

variable "function_app" {
  default = "vcloudlabafa"
}

variable "application_stack" {
  type = map(any)
  default = {
    dotnet_version = null
    #use_dotnet_isolated_runtime = false
    java_version            = null
    node_version            = null
    python_version          = 3.9
    powershell_core_version = null
    #use_custom_runtime = false
  }
  validation {
    condition = length([for stack_name, stack_value in var.application_stack : stack_name if(stack_value != null)]) == 1
    #(&& stack_name != "use_dotnet_isolated_runtime" && stack_name != "use_custom_runtime" && stack_value != null)
    #(stack_name != "use_dotnet_isolated_runtime" && stack_name != "use_custom_runtime" && stack_value != "") #when value is ""
    error_message = "Exactly one value in 'application_stack' must be non-null."
  }
}

variable "app_settings" {
  default = {
    "FUNCTIONS_WORKER_RUNTIME1" = "python3"
  }
}

variable "function_app_os" {
  default = "Linux"
}

variable "delegation_subnet" {
  default = "delegationsubnet"
}

variable "delegation_subnet_address_prefixes" {
  type = list(string)
  default = ["10.0.1.0/24"]
}

######################################

data "azurerm_resource_group" "rg_info" {
  name = var.resource_group_name
}

data "azurerm_virtual_network" "vnet_info" {
  name                = var.virtual_network
  resource_group_name = data.azurerm_resource_group.rg_info.name
}

data "azurerm_subnet" "subnet_info" {
  name                 = var.subnet
  virtual_network_name = data.azurerm_virtual_network.vnet_info.name
  resource_group_name  = data.azurerm_resource_group.rg_info.name
}

data "azurerm_private_dns_zone" "pdz" {
  name                = var.private_dns_zone
  resource_group_name = data.azurerm_resource_group.rg_info.name
}

data "azurerm_user_assigned_identity" "uai" {
  name                = var.user_assigned_identity
  resource_group_name = data.azurerm_resource_group.rg_info.name
}

data "azurerm_private_dns_zone_virtual_network_link" "pdzvnl" {
  name                  = var.private_dns_zone_virtual_network_link
  resource_group_name   = data.azurerm_resource_group.rg_info.name
  private_dns_zone_name = data.azurerm_private_dns_zone.pdz.name
}

#######################################

resource "azurerm_storage_account" "sa" {
  name                     = var.storage_account_name
  resource_group_name      = data.azurerm_resource_group.rg_info.name
  location                 = data.azurerm_resource_group.rg_info.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

resource "azurerm_service_plan" "asp" {

  name                = var.app_service_plan
  resource_group_name = data.azurerm_resource_group.rg_info.name
  location            = data.azurerm_resource_group.rg_info.location
  os_type             = var.function_app_os
  sku_name            = "S1"
}

resource "azurerm_linux_function_app" "lfa" {
  name                 = var.function_app
  location             = data.azurerm_resource_group.rg_info.location
  resource_group_name  = data.azurerm_resource_group.rg_info.name
  service_plan_id      = azurerm_service_plan.asp.id
  storage_account_name = azurerm_storage_account.sa.name
  #storage_account_access_key    = azurerm_storage_account.sa.primary_access_key   #When using system managed identity
  storage_uses_managed_identity = true #When using user managed identity
  public_network_access_enabled = false

  #tags = var.tags

  app_settings = merge(
    var.app_settings,
    {
      "FUNCTIONS_WORKER_RUNTIME" = "python"
    }
  )

  site_config {
    application_stack {
      dotnet_version = var.application_stack["dotnet_version"]
      #use_dotnet_isolated_runtime = var.application_stack["use_dotnet_isolated_runtime"]
      java_version            = var.application_stack["java_version"]
      node_version            = var.application_stack["node_version"]
      python_version          = var.application_stack["python_version"]
      powershell_core_version = var.application_stack["powershell_core_version"]
      #use_custom_runtime          = var.application_stack["use_custom_runtime"]
    }
  }

  identity {
    type         = "UserAssigned" #When using user managed identity to access storage account / or use systemassigned
    identity_ids = [data.azurerm_user_assigned_identity.uai.id]
  }
}

### User mananged Privileges to storage account 

resource "azurerm_role_assignment" "sac" {
  scope                = azurerm_storage_account.sa.id
  principal_id         = data.azurerm_user_assigned_identity.uai.principal_id
  role_definition_name = "Storage Account Contributor"
}

resource "azurerm_role_assignment" "sbc" {
  scope                = azurerm_storage_account.sa.id
  principal_id         = data.azurerm_user_assigned_identity.uai.principal_id
  role_definition_name = "Storage Blob Data Contributor"
}

# if required
resource "azurerm_role_assignment" "sfdssc" {
  scope                = azurerm_storage_account.sa.id
  principal_id         = data.azurerm_user_assigned_identity.uai.principal_id
  role_definition_name = "Storage File Data SMB Share Contributor"
}

# resource "azurerm_private_dns_zone_virtual_network_link" "pdzvnl" {
#   name                  = "${resource.azurerm_linux_function_app.lfa.name}-private-link"
#   resource_group_name   = data.azurerm_resource_group.rg_info.name
#   private_dns_zone_name = data.azurerm_private_dns_zone.pdz.name
#   virtual_network_id    = data.azurerm_virtual_network.vnet_info.id
#   registration_enabled  = true
# }

resource "azurerm_private_endpoint" "sites_private_endpoint" {
  name                = "${resource.azurerm_linux_function_app.lfa.name}-ep"
  resource_group_name = data.azurerm_resource_group.rg_info.name
  location            = data.azurerm_resource_group.rg_info.location
  subnet_id           = data.azurerm_subnet.subnet_info.id

  private_service_connection {
    name                           = "${resource.azurerm_linux_function_app.lfa.name}-ep-connection"
    private_connection_resource_id = resource.azurerm_linux_function_app.lfa.id
    subresource_names              = ["sites"]
    is_manual_connection           = false
  }

  private_dns_zone_group {
    name                 = "${resource.azurerm_linux_function_app.lfa.name}-dnz-zone-group"
    private_dns_zone_ids = [data.azurerm_private_dns_zone.pdz.id]
  }
}

##############

#For outbound calls to other services, subnet should have delegation access
resource "azurerm_subnet" "delegation_subnet" {
  name                 = var.delegation_subnet
  virtual_network_name = data.azurerm_virtual_network.vnet_info.name
  resource_group_name  = data.azurerm_resource_group.rg_info.name
  address_prefixes     = var.delegation_subnet_address_prefixes
  delegation {
    name = "web-serverfarm"

    service_delegation {
      name = "Microsoft.Web/serverFarms"
      #actions = ["Microsoft.Network/virtualNetworks/subnets/join/action", "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action"]
    }
  }
}

#For outbound calls to other services, subnet should have delegation access
resource "azurerm_app_service_virtual_network_swift_connection" "apsvnsc" {
  app_service_id = azurerm_linux_function_app.lfa.id
  subnet_id      = resource.azurerm_subnet.delegation_subnet.id
}

##############

output "application_stack" {
  value     = resource.azurerm_linux_function_app.lfa.site_config[0].application_stack[0] #.node_version
  sensitive = false
}

output "app_settings" {
  value     = resource.azurerm_linux_function_app.lfa.app_settings
  sensitive = false
}

Download this Terraform_Function_App_Private_Endpoint.tf code here or it is also available on github.com.

Below is the output of the terraform apply.

  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
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
terraform apply --auto-approve  
data.azurerm_resource_group.rg_info: Reading...
data.azurerm_resource_group.rg_info: Read complete after 0s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev]
data.azurerm_user_assigned_identity.uai: Reading...
data.azurerm_virtual_network.vnet_info: Reading...
data.azurerm_private_dns_zone.pdz: Reading...
data.azurerm_private_dns_zone.pdz: Read complete after 0s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/privateDnsZones/privatelink.azurewebsites.net]
data.azurerm_private_dns_zone_virtual_network_link.pdzvnl: Reading...
data.azurerm_virtual_network.vnet_info: Read complete after 1s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/virtualNetworks/vcloud-lab-dev]
data.azurerm_subnet.subnet_info: Reading...
data.azurerm_private_dns_zone_virtual_network_link.pdzvnl: Read complete after 1s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/privateDnsZones/privatelink.azurewebsites.net/virtualNetworkLinks/vcloud-lab-dev-privatelink]
data.azurerm_user_assigned_identity.uai: Read complete after 1s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.ManagedIdentity/userAssignedIdentities/vcloudlabuser]
data.azurerm_subnet.subnet_info: Read complete after 0s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/virtualNetworks/vcloud-lab-dev/subnets/default]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_app_service_virtual_network_swift_connection.apsvnsc will be created
  + resource "azurerm_app_service_virtual_network_swift_connection" "apsvnsc" {
      + app_service_id = (known after apply)
      + id             = (known after apply)
      + subnet_id      = (known after apply)
    }

  # azurerm_linux_function_app.lfa will be created
  + resource "azurerm_linux_function_app" "lfa" {
      + app_settings                                   = {
          + "FUNCTIONS_WORKER_RUNTIME"  = "python"
          + "FUNCTIONS_WORKER_RUNTIME1" = "python3"
        }
      + builtin_logging_enabled                        = true
      + client_certificate_enabled                     = false
      + client_certificate_mode                        = "Optional"
      + content_share_force_disabled                   = false
      + custom_domain_verification_id                  = (sensitive value)
      + daily_memory_time_quota                        = 0
      + default_hostname                               = (known after apply)
      + enabled                                        = true
      + ftp_publish_basic_authentication_enabled       = true
      + functions_extension_version                    = "~4"
      + hosting_environment_id                         = (known after apply)
      + https_only                                     = false
      + id                                             = (known after apply)
      + key_vault_reference_identity_id                = (known after apply)
      + kind                                           = (known after apply)
      + location                                       = "eastus"
      + name                                           = "vcloudlabafa"
      + outbound_ip_address_list                       = (known after apply)
      + outbound_ip_addresses                          = (known after apply)
      + possible_outbound_ip_address_list              = (known after apply)
      + possible_outbound_ip_addresses                 = (known after apply)
      + public_network_access_enabled                  = false
      + resource_group_name                            = "dev"
      + service_plan_id                                = (known after apply)
      + site_credential                                = (sensitive value)
      + storage_account_name                           = "vcloudlabsa"
      + storage_uses_managed_identity                  = true
      + webdeploy_publish_basic_authentication_enabled = true
      + zip_deploy_file                                = (known after apply)

      + identity {
          + identity_ids = [
              + "/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.ManagedIdentity/userAssignedIdentities/vcloudlabuser",
            ]
          + principal_id = (known after apply)
          + tenant_id    = (known after apply)
          + type         = "UserAssigned"
        }

      + site_config {
          + always_on                               = (known after apply)
          + app_scale_limit                         = (known after apply)
          + container_registry_use_managed_identity = false
          + default_documents                       = (known after apply)
          + detailed_error_logging_enabled          = (known after apply)
          + elastic_instance_minimum                = (known after apply)
          + ftps_state                              = "Disabled"
          + health_check_eviction_time_in_min       = (known after apply)
          + http2_enabled                           = false
          + ip_restriction_default_action           = "Allow"
          + linux_fx_version                        = (known after apply)
          + load_balancing_mode                     = "LeastRequests"
          + managed_pipeline_mode                   = "Integrated"
          + minimum_tls_version                     = "1.2"
          + pre_warmed_instance_count               = (known after apply)
          + remote_debugging_enabled                = false
          + remote_debugging_version                = (known after apply)
          + scm_ip_restriction_default_action       = "Allow"
          + scm_minimum_tls_version                 = "1.2"
          + scm_type                                = (known after apply)
          + scm_use_main_ip_restriction             = false
          + use_32_bit_worker                       = false
          + vnet_route_all_enabled                  = false
          + websockets_enabled                      = false
          + worker_count                            = (known after apply)

          + application_stack {
              + python_version              = "3.9"
              + use_dotnet_isolated_runtime = false
            }
        }
    }

  # azurerm_private_endpoint.sites_private_endpoint will be created
  + resource "azurerm_private_endpoint" "sites_private_endpoint" {
      + custom_dns_configs       = (known after apply)
      + id                       = (known after apply)
      + location                 = "eastus"
      + name                     = "vcloudlabafa-ep"
      + network_interface        = (known after apply)
      + private_dns_zone_configs = (known after apply)
      + resource_group_name      = "dev"
      + subnet_id                = "/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/virtualNetworks/vcloud-lab-dev/subnets/default"

      + private_dns_zone_group {
          + id                   = (known after apply)
          + name                 = "vcloudlabafa-dnz-zone-group"
          + private_dns_zone_ids = [
              + "/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/privateDnsZones/privatelink.azurewebsites.net",
            ]
        }

      + private_service_connection {
          + is_manual_connection           = false
          + name                           = "vcloudlabafa-ep-connection"
          + private_connection_resource_id = (known after apply)
          + private_ip_address             = (known after apply)
          + subresource_names              = [
              + "sites",
            ]
        }
    }

  # azurerm_role_assignment.sac will be created
  + resource "azurerm_role_assignment" "sac" {
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = "5aa8a7e2-ebf2-40d2-9b41-2c375476dfe3"
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Storage Account Contributor"
      + scope                            = (known after apply)
      + skip_service_principal_aad_check = (known after apply)
    }

  # azurerm_role_assignment.sbc will be created
  + resource "azurerm_role_assignment" "sbc" {
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = "5aa8a7e2-ebf2-40d2-9b41-2c375476dfe3"
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Storage Blob Data Contributor"
      + scope                            = (known after apply)
      + skip_service_principal_aad_check = (known after apply)
    }

  # azurerm_role_assignment.sfdssc will be created
  + resource "azurerm_role_assignment" "sfdssc" {
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = "5aa8a7e2-ebf2-40d2-9b41-2c375476dfe3"
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Storage File Data SMB Share Contributor"
      + scope                            = (known after apply)
      + skip_service_principal_aad_check = (known after apply)
    }

  # azurerm_service_plan.asp will be created
  + resource "azurerm_service_plan" "asp" {
      + id                           = (known after apply)
      + kind                         = (known after apply)
      + location                     = "eastus"
      + maximum_elastic_worker_count = (known after apply)
      + name                         = "vcloudlabasp"
      + os_type                      = "Linux"
      + per_site_scaling_enabled     = false
      + reserved                     = (known after apply)
      + resource_group_name          = "dev"
      + sku_name                     = "S1"
      + worker_count                 = (known after apply)
    }

  # azurerm_storage_account.sa will be created
  + resource "azurerm_storage_account" "sa" {
      + access_tier                        = (known after apply)
      + account_kind                       = "StorageV2"
      + account_replication_type           = "LRS"
      + account_tier                       = "Standard"
      + allow_nested_items_to_be_public    = true
      + cross_tenant_replication_enabled   = true
      + default_to_oauth_authentication    = false
      + dns_endpoint_type                  = "Standard"
      + enable_https_traffic_only          = (known after apply)
      + https_traffic_only_enabled         = (known after apply)
      + id                                 = (known after apply)
      + infrastructure_encryption_enabled  = false
      + is_hns_enabled                     = false
      + large_file_share_enabled           = (known after apply)
      + local_user_enabled                 = true
      + location                           = "eastus"
      + min_tls_version                    = "TLS1_2"
      + name                               = "vcloudlabsa"
      + nfsv3_enabled                      = false
      + primary_access_key                 = (sensitive value)
      + primary_blob_connection_string     = (sensitive value)
      + primary_blob_endpoint              = (known after apply)
      + primary_blob_host                  = (known after apply)
      + primary_blob_internet_endpoint     = (known after apply)
      + primary_blob_internet_host         = (known after apply)
      + primary_blob_microsoft_endpoint    = (known after apply)
      + primary_blob_microsoft_host        = (known after apply)
      + primary_connection_string          = (sensitive value)
      + primary_dfs_endpoint               = (known after apply)
      + primary_dfs_host                   = (known after apply)
      + primary_dfs_internet_endpoint      = (known after apply)
      + primary_dfs_internet_host          = (known after apply)
      + primary_dfs_microsoft_endpoint     = (known after apply)
      + primary_dfs_microsoft_host         = (known after apply)
      + primary_file_endpoint              = (known after apply)
      + primary_file_host                  = (known after apply)
      + primary_file_internet_endpoint     = (known after apply)
      + primary_file_internet_host         = (known after apply)
      + primary_file_microsoft_endpoint    = (known after apply)
      + primary_file_microsoft_host        = (known after apply)
      + primary_location                   = (known after apply)
      + primary_queue_endpoint             = (known after apply)
      + primary_queue_host                 = (known after apply)
      + primary_queue_microsoft_endpoint   = (known after apply)
      + primary_queue_microsoft_host       = (known after apply)
      + primary_table_endpoint             = (known after apply)
      + primary_table_host                 = (known after apply)
      + primary_table_microsoft_endpoint   = (known after apply)
      + primary_table_microsoft_host       = (known after apply)
      + primary_web_endpoint               = (known after apply)
      + primary_web_host                   = (known after apply)
      + primary_web_internet_endpoint      = (known after apply)
      + primary_web_internet_host          = (known after apply)
      + primary_web_microsoft_endpoint     = (known after apply)
      + primary_web_microsoft_host         = (known after apply)
      + public_network_access_enabled      = true
      + queue_encryption_key_type          = "Service"
      + resource_group_name                = "dev"
      + secondary_access_key               = (sensitive value)
      + secondary_blob_connection_string   = (sensitive value)
      + secondary_blob_endpoint            = (known after apply)
      + secondary_blob_host                = (known after apply)
      + secondary_blob_internet_endpoint   = (known after apply)
      + secondary_blob_internet_host       = (known after apply)
      + secondary_blob_microsoft_endpoint  = (known after apply)
      + secondary_blob_microsoft_host      = (known after apply)
      + secondary_connection_string        = (sensitive value)
      + secondary_dfs_endpoint             = (known after apply)
      + secondary_dfs_host                 = (known after apply)
      + secondary_dfs_internet_endpoint    = (known after apply)
      + secondary_dfs_internet_host        = (known after apply)
      + secondary_dfs_microsoft_endpoint   = (known after apply)
      + secondary_dfs_microsoft_host       = (known after apply)
      + secondary_file_endpoint            = (known after apply)
      + secondary_file_host                = (known after apply)
      + secondary_file_internet_endpoint   = (known after apply)
      + secondary_file_internet_host       = (known after apply)
      + secondary_file_microsoft_endpoint  = (known after apply)
      + secondary_file_microsoft_host      = (known after apply)
      + secondary_location                 = (known after apply)
      + secondary_queue_endpoint           = (known after apply)
      + secondary_queue_host               = (known after apply)
      + secondary_queue_microsoft_endpoint = (known after apply)
      + secondary_queue_microsoft_host     = (known after apply)
      + secondary_table_endpoint           = (known after apply)
      + secondary_table_host               = (known after apply)
      + secondary_table_microsoft_endpoint = (known after apply)
      + secondary_table_microsoft_host     = (known after apply)
      + secondary_web_endpoint             = (known after apply)
      + secondary_web_host                 = (known after apply)
      + secondary_web_internet_endpoint    = (known after apply)
      + secondary_web_internet_host        = (known after apply)
      + secondary_web_microsoft_endpoint   = (known after apply)
      + secondary_web_microsoft_host       = (known after apply)
      + sftp_enabled                       = false
      + shared_access_key_enabled          = true
      + table_encryption_key_type          = "Service"

      + blob_properties (known after apply)

      + network_rules (known after apply)

      + queue_properties (known after apply)

      + routing (known after apply)

      + share_properties (known after apply)
    }

  # azurerm_subnet.delegation_subnet will be created
  + resource "azurerm_subnet" "delegation_subnet" {
      + address_prefixes                               = [
          + "10.0.1.0/24",
        ]
      + default_outbound_access_enabled                = true
      + enforce_private_link_endpoint_network_policies = (known after apply)
      + enforce_private_link_service_network_policies  = (known after apply)
      + id                                             = (known after apply)
      + name                                           = "delegationsubnet"
      + private_endpoint_network_policies              = (known after apply)
      + private_endpoint_network_policies_enabled      = (known after apply)
      + private_link_service_network_policies_enabled  = (known after apply)
      + resource_group_name                            = "dev"
      + virtual_network_name                           = "vcloud-lab-dev"

      + delegation {
          + name = "web-serverfarm"

          + service_delegation {
              + name = "Microsoft.Web/serverFarms"
            }
        }
    }

Plan: 9 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + app_settings      = {
      + FUNCTIONS_WORKER_RUNTIME  = "python"
      + FUNCTIONS_WORKER_RUNTIME1 = "python3"
    }
  + application_stack = {
      + docker                      = []
      + dotnet_version              = null
      + java_version                = null
      + node_version                = null
      + powershell_core_version     = null
      + python_version              = "3.9"
      + use_custom_runtime          = null
      + use_dotnet_isolated_runtime = false
    }
azurerm_service_plan.asp: Creating...
azurerm_subnet.delegation_subnet: Creating...
azurerm_storage_account.sa: Creating...
azurerm_subnet.delegation_subnet: Creation complete after 7s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/virtualNetworks/vcloud-lab-dev/subnets/delegationsubnet]
azurerm_service_plan.asp: Still creating... [10s elapsed]
azurerm_storage_account.sa: Still creating... [10s elapsed]
azurerm_service_plan.asp: Still creating... [20s elapsed]
azurerm_storage_account.sa: Still creating... [20s elapsed]
azurerm_service_plan.asp: Creation complete after 29s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Web/serverFarms/vcloudlabasp]
azurerm_storage_account.sa: Still creating... [30s elapsed]
azurerm_storage_account.sa: Still creating... [40s elapsed]
azurerm_storage_account.sa: Still creating... [50s elapsed]
azurerm_storage_account.sa: Still creating... [1m0s elapsed]
azurerm_storage_account.sa: Still creating... [1m10s elapsed]
azurerm_storage_account.sa: Creation complete after 1m17s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Storage/storageAccounts/vcloudlabsa]
azurerm_role_assignment.sbc: Creating...
azurerm_role_assignment.sfdssc: Creating...
azurerm_role_assignment.sac: Creating...
azurerm_linux_function_app.lfa: Creating...
azurerm_role_assignment.sbc: Still creating... [10s elapsed]
azurerm_role_assignment.sfdssc: Still creating... [10s elapsed]
azurerm_role_assignment.sac: Still creating... [10s elapsed]
azurerm_linux_function_app.lfa: Still creating... [10s elapsed]
azurerm_role_assignment.sbc: Still creating... [20s elapsed]
azurerm_role_assignment.sac: Still creating... [20s elapsed]
azurerm_role_assignment.sfdssc: Still creating... [20s elapsed]
azurerm_linux_function_app.lfa: Still creating... [20s elapsed]
azurerm_role_assignment.sac: Creation complete after 27s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Storage/storageAccounts/vcloudlabsa/providers/Microsoft.Authorization/roleAssignments/c3c1c052-c0d9-0dca-7aa7-7d7c1cde46c7]
azurerm_role_assignment.sbc: Creation complete after 29s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Storage/storageAccounts/vcloudlabsa/providers/Microsoft.Authorization/roleAssignments/2bbd883e-f5ae-cbb6-b63d-10fa279b66ff]
azurerm_role_assignment.sfdssc: Creation complete after 29s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Storage/storageAccounts/vcloudlabsa/providers/Microsoft.Authorization/roleAssignments/caa881fd-336c-ecd7-07bf-3d34cd10c614]
azurerm_linux_function_app.lfa: Still creating... [30s elapsed]
azurerm_linux_function_app.lfa: Still creating... [40s elapsed]
azurerm_linux_function_app.lfa: Still creating... [51s elapsed]
azurerm_linux_function_app.lfa: Still creating... [1m1s elapsed]
azurerm_linux_function_app.lfa: Still creating... [1m11s elapsed]
azurerm_linux_function_app.lfa: Still creating... [1m21s elapsed]
azurerm_linux_function_app.lfa: Creation complete after 1m25s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Web/sites/vcloudlabafa]
azurerm_app_service_virtual_network_swift_connection.apsvnsc: Creating...
azurerm_private_endpoint.sites_private_endpoint: Creating...
azurerm_private_endpoint.sites_private_endpoint: Still creating... [10s elapsed]
azurerm_app_service_virtual_network_swift_connection.apsvnsc: Still creating... [10s elapsed]
azurerm_app_service_virtual_network_swift_connection.apsvnsc: Creation complete after 20s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Web/sites/vcloudlabafa/config/virtualNetwork]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [20s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [30s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [40s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [50s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [1m0s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [1m10s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [1m20s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [1m30s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Still creating... [1m40s elapsed]
azurerm_private_endpoint.sites_private_endpoint: Creation complete after 1m41s [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/dev/providers/Microsoft.Network/privateEndpoints/vcloudlabafa-ep]

Apply complete! Resources: 9 added, 0 changed, 0 destroyed.

Outputs:

app_settings = tomap({
  "FUNCTIONS_WORKER_RUNTIME" = "python"
  "FUNCTIONS_WORKER_RUNTIME1" = "python3"
})
application_stack = {
  "docker" = tolist([])
  "dotnet_version" = tostring(null)
  "java_version" = tostring(null)
  "node_version" = tostring(null)
  "powershell_core_version" = tostring(null)
  "python_version" = "3.9"
  "use_custom_runtime" = tobool(null)
  "use_dotnet_isolated_runtime" = false
}

This how it looks the configured and deployed resources on the Azure portal.

Terraform Microsoft Azure 3 tier architecture PrivateLink azurewebsites.net private dns zone, virtual network vnet function app service app plan private endpoint user manged identity storage account.png

Useful Articles
Hashicorp Terraform map and object inside module and variable example
Terraform one module deploy null or multiple resources based on input
Terraform A reference to a resource type must be followed by at least one attribute access, specifying the resource name
Terraform fore_each for loop filter with if condition example
Terraform remote-exec provisioner with ssh connection in null_resource
Terraform count vs for_each for examples with map of objects
Terraform one module deploy null or multiple resources based on input (nested for loop) Example of Terraform functions flatten() and coalesce()
Terraform Azure Create Private Endpoint to existing Storage Account with Custom Private DNS zone record link
Creating a Private Endpoint for Azure Storage Account with required sub services using Terraform Example Terraform functions of lookup() and lower()
Using element function with count meta argument example Terraform Azure subnets Example Terraform functions of element()count() and sum()
Terraform create Azure Virtual Network subnets from map of object and show name in the header Header name change in the output
Creating a Private Endpoint for Azure Storage Account with Terraform example 2 Example of for_each with toset() function
Creating a Private Endpoint for Azure Storage Account with Terraform example 3

Go Back

Comment

Blog Search

Page Views

12086074

Follow me on Blogarama