Skip to content

Commit

Permalink
Deploy custom Linux Function Apps (#433)
Browse files Browse the repository at this point in the history
* Custom function apps can be deployed by supplying a zip file to the module

>[!WARNING]
>* Function Apps are deployed into a Serverless App Service Plan (SKU: Y1) which means they are not permitted to be 'always-on'
  • Loading branch information
DrizzlyOwl authored Oct 14, 2024
1 parent de3adfd commit 1e350ce
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 17 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ module "azure_container_apps_hosting" {
| [azurerm_eventhub_namespace.container_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/eventhub_namespace) | resource |
| [azurerm_key_vault.default](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault) | resource |
| [azurerm_key_vault_secret.secret_app_setting](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_linux_function_app.function_apps](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_function_app) | resource |
| [azurerm_linux_function_app.health_api](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_function_app) | resource |
| [azurerm_log_analytics_data_export_rule.container_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_data_export_rule) | resource |
| [azurerm_log_analytics_query_pack.container_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_query_pack) | resource |
Expand Down Expand Up @@ -850,6 +851,7 @@ module "azure_container_apps_hosting" {
| <a name="input_key_vault_access_ipv4"></a> [key\_vault\_access\_ipv4](#input\_key\_vault\_access\_ipv4) | List of IPv4 Addresses that are permitted to access the Key Vault | `list(string)` | `[]` | no |
| <a name="input_key_vault_managed_identity_assign_role"></a> [key\_vault\_managed\_identity\_assign\_role](#input\_key\_vault\_managed\_identity\_assign\_role) | Assign the Key Vault Secret User role to the Container App managed identity | `bool` | `false` | no |
| <a name="input_launch_in_vnet"></a> [launch\_in\_vnet](#input\_launch\_in\_vnet) | Conditionally launch into a VNet | `bool` | `true` | no |
| <a name="input_linux_function_apps"></a> [linux\_function\_apps](#input\_linux\_function\_apps) | A list of Linux Function Apps with their corresponding app settings | <pre>map(object({<br/> runtime = string<br/> runtime_version = string<br/> app_settings = optional(map(string), {})<br/> allowed_origins = optional(list(string), ["*"])<br/> ftp_publish_basic_authentication_enabled = optional(bool, false)<br/> webdeploy_publish_basic_authentication_enabled = optional(bool, false)<br/> ipv4_access = optional(list(string), [])<br/> }))</pre> | `{}` | no |
| <a name="input_monitor_email_receivers"></a> [monitor\_email\_receivers](#input\_monitor\_email\_receivers) | A list of email addresses that should be notified by monitoring alerts | `list(string)` | `[]` | no |
| <a name="input_monitor_endpoint_healthcheck"></a> [monitor\_endpoint\_healthcheck](#input\_monitor\_endpoint\_healthcheck) | Specify a route that should be monitored for a 200 OK status | `string` | `"/"` | no |
| <a name="input_mssql_azuread_admin_object_id"></a> [mssql\_azuread\_admin\_object\_id](#input\_mssql\_azuread\_admin\_object\_id) | Object ID of a User within Azure AD that you want to assign as the SQL Server Administrator | `string` | `""` | no |
Expand Down
24 changes: 12 additions & 12 deletions app-insights.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ resource "azurerm_application_insights" "main" {
tags = local.tags
}

resource "azurerm_application_insights" "function_apps" {
for_each = local.enable_app_insights_integration ? merge(local.linux_function_apps, local.linux_function_health_insights_api) : {}

name = "${local.resource_prefix}-${each.key}-insights"
location = local.resource_group.location
resource_group_name = local.resource_group.name
application_type = "web"
workspace_id = azurerm_log_analytics_workspace.app_insights[0].id
retention_in_days = local.app_insights_retention_days
tags = local.tags
}

resource "azurerm_log_analytics_workspace" "app_insights" {
count = local.enable_app_insights_integration ? 1 : 0

Expand Down Expand Up @@ -58,15 +70,3 @@ resource "azurerm_application_insights_standard_web_test" "main" {
{ "hidden-link:${azurerm_application_insights.main[0].id}" = "Resource" },
)
}

resource "azurerm_application_insights" "function_apps" {
for_each = local.enable_app_insights_integration ? local.linux_function_health_insights_api : {}

name = "${local.resource_prefix}-${each.key}-insights"
location = local.resource_group.location
resource_group_name = local.resource_group.name
application_type = "web"
workspace_id = azurerm_log_analytics_workspace.app_insights[0].id
retention_in_days = local.app_insights_retention_days
tags = local.tags
}
72 changes: 69 additions & 3 deletions function-app.tf
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ resource "azurerm_linux_function_app" "health_api" {

site_config {
always_on = false
application_insights_connection_string = azurerm_application_insights.function_apps[each.key].connection_string
application_insights_key = azurerm_application_insights.function_apps[each.key].instrumentation_key
application_insights_connection_string = local.enable_app_insights_integration ? azurerm_application_insights.function_apps[each.key].connection_string : null
application_insights_key = local.enable_app_insights_integration ? azurerm_application_insights.function_apps[each.key].instrumentation_key : null
app_scale_limit = 1
http2_enabled = true
ftps_state = each.value.ftp_publish_basic_authentication_enabled ? "FtpsOnly" : "Disabled"
Expand Down Expand Up @@ -81,8 +81,74 @@ resource "azurerm_linux_function_app" "health_api" {
}
}

resource "azurerm_linux_function_app" "function_apps" {
for_each = local.linux_function_apps

name = "${local.environment}${each.key}"
resource_group_name = local.resource_group.name
location = local.resource_group.location
storage_account_name = azurerm_storage_account.function_app_backing[0].name
storage_account_access_key = azurerm_storage_account.function_app_backing[0].primary_access_key
service_plan_id = azurerm_service_plan.function_apps[0].id
ftp_publish_basic_authentication_enabled = each.value.ftp_publish_basic_authentication_enabled
webdeploy_publish_basic_authentication_enabled = each.value.webdeploy_publish_basic_authentication_enabled
https_only = true
key_vault_reference_identity_id = azurerm_user_assigned_identity.function_apps[each.key].id

app_settings = merge(each.value.app_settings, {
"AZURE_CLIENT_ID" = azurerm_user_assigned_identity.function_apps[each.key].client_id
})

site_config {
always_on = false
application_insights_connection_string = local.enable_app_insights_integration ? azurerm_application_insights.function_apps[each.key].connection_string : null
application_insights_key = local.enable_app_insights_integration ? azurerm_application_insights.function_apps[each.key].instrumentation_key : null
app_scale_limit = 1
http2_enabled = true
ftps_state = each.value.ftp_publish_basic_authentication_enabled ? "FtpsOnly" : "Disabled"
ip_restriction_default_action = length(each.value.ipv4_access) > 0 ? "Deny" : "Allow"
scm_ip_restriction_default_action = length(each.value.ipv4_access) > 0 ? "Deny" : "Allow"
scm_use_main_ip_restriction = true

cors {
allowed_origins = each.value.allowed_origins
support_credentials = contains(each.value.allowed_origins, "*") ? false : true
}

dynamic "ip_restriction" {
for_each = each.value.ipv4_access

content {
action = "Allow"
name = "AllowIPInbound${ip_restriction.value}"
ip_address = ip_restriction.value
}
}

application_stack {
python_version = lower(each.value.runtime) == "python" ? each.value.runtime_version : null
dotnet_version = lower(each.value.runtime) == "dotnet" ? each.value.runtime_version : null
java_version = lower(each.value.runtime) == "java" ? each.value.runtime_version : null
node_version = lower(each.value.runtime) == "node" ? each.value.runtime_version : null
}
}

identity {
type = "UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.function_apps[each.key].id
]
}

tags = merge(local.tags, local.enable_app_insights_integration ? {
"hidden-link: /app-insights-conn-string" : azurerm_application_insights.function_apps[each.key].connection_string,
"hidden-link: /app-insights-instrumentation-key" : azurerm_application_insights.function_apps[each.key].instrumentation_key,
"hidden-link: /app-insights-resource-id" : azurerm_application_insights.function_apps[each.key].id,
} : {})
}

resource "azurerm_monitor_diagnostic_setting" "function_apps" {
for_each = local.linux_function_health_insights_api
for_each = merge(local.linux_function_apps, local.linux_function_health_insights_api)

name = "${azurerm_linux_function_app.health_api[each.key].name}-diagnostics"
target_resource_id = azurerm_linux_function_app.health_api[each.key].id
Expand Down
2 changes: 1 addition & 1 deletion identity.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ resource "azurerm_role_assignment" "mssql_storageblobdatacontributor" {
}

resource "azurerm_user_assigned_identity" "function_apps" {
for_each = local.enable_linux_function_apps ? local.linux_function_health_insights_api : {}
for_each = local.enable_linux_function_apps ? merge(local.linux_function_apps, local.linux_function_health_insights_api) : {}

location = local.resource_group.location
name = "${local.resource_prefix}-${each.key}-uami-function"
Expand Down
3 changes: 2 additions & 1 deletion locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ locals {
mssql_security_storage_cross_tenant_replication_enabled = var.mssql_security_storage_cross_tenant_replication_enabled

# Azure Functions
linux_function_apps = var.linux_function_apps
linux_function_health_insights_api = (local.enable_app_insights_integration && local.enable_monitoring && var.enable_health_insights_api) ? {
"health-api" = {
runtime = "python"
Expand All @@ -398,7 +399,7 @@ locals {
ipv4_access = var.health_insights_api_ipv4_allow_list
}
} : {}
enable_linux_function_apps = length(keys(local.linux_function_health_insights_api)) > 0 ? true : false
enable_linux_function_apps = (length(local.linux_function_apps) > 0 || length(keys(local.linux_function_health_insights_api)) > 0) ? true : false

# Azure DNS Zone
enable_dns_zone = var.enable_dns_zone
Expand Down
14 changes: 14 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -1229,3 +1229,17 @@ variable "health_insights_api_ipv4_allow_list" {
type = list(string)
default = []
}

variable "linux_function_apps" {
description = "A list of Linux Function Apps with their corresponding app settings"
type = map(object({
runtime = string
runtime_version = string
app_settings = optional(map(string), {})
allowed_origins = optional(list(string), ["*"])
ftp_publish_basic_authentication_enabled = optional(bool, false)
webdeploy_publish_basic_authentication_enabled = optional(bool, false)
ipv4_access = optional(list(string), [])
}))
default = {}
}

0 comments on commit 1e350ce

Please sign in to comment.