Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 139 additions & 10 deletions modules/azure/logic_app_standard/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ terraform {
source = "hashicorp/azurerm"
version = "~> 3.48"
}
archive = {
source = "hashicorp/archive"
version = "~> 2.3"
azapi = {
source = "Azure/azapi"
version = "~> 1.4"
}
azuread = {
source = "hashicorp/azuread"
version = "~> 2.36"
}
}

Expand All @@ -19,12 +23,11 @@ provider "azurerm" {
features {}
}

provider "archive" {
}

locals {
identity_type = var.use_managed_identity && length(var.identity_ids) > 0 ? "SystemAssigned, UserAssigned" : var.use_managed_identity ? "SystemAssigned" : length(var.identity_ids) > 0 ? "UserAssigned" : null
is_linux = length(regexall("/home/", lower(abspath(path.root)))) > 0
identity_type = var.use_managed_identity && length(var.identity_ids) > 0 ? "SystemAssigned, UserAssigned" : var.use_managed_identity ? "SystemAssigned" : length(var.identity_ids) > 0 ? "UserAssigned" : null
is_linux = length(regexall("/home/", lower(abspath(path.root)))) > 0
identifiers = var.managed_identity_provider != null ? concat(["api://${var.managed_identity_provider.create.application_name}"], var.managed_identity_provider.identifier_uris != null ? var.managed_identity_provider.identifier_uris : []) : []
allowed_audiences = var.managed_identity_provider != null ? concat(local.identifiers, var.managed_identity_provider.allowed_audiences != null ? var.managed_identity_provider.allowed_audiences : []) : []
}

resource "azurerm_logic_app_standard" "app" {
Expand All @@ -47,12 +50,36 @@ resource "azurerm_logic_app_standard" "app" {
ftps_state = "Disabled"
elastic_instance_minimum = var.elastic_instance_minimum
pre_warmed_instance_count = var.pre_warmed_instance_count

dynamic "ip_restriction" {
for_each = var.ip_restrictions

content {
ip_address = ip_restriction.value.ip_address
service_tag = ip_restriction.value.service_tag
virtual_network_subnet_id = ip_restriction.value.virtual_network_subnet_id
name = ip_restriction.value.name
priority = ip_restriction.value.priority
action = ip_restriction.value.action

dynamic "headers" {
for_each = ip_restriction.value.headers

content {
x_azure_fdid = headers.value.x_azure_fdid
x_fd_health_probe = headers.value.x_fd_health_probe
x_forwarded_for = headers.value.x_forwarded_for
x_forwarded_host = headers.value.x_forwarded_host
}
}
}
}
}

app_settings = merge({
WEBSITE_NODE_DEFAULT_VERSION = "~18",
FUNCTIONS_WORKER_RUNTIME = "node",
}, var.app_settings)
FUNCTIONS_WORKER_RUNTIME = "node"
}, var.managed_identity_provider != null ? { MICROSOFT_PROVIDER_AUTHENTICATION_SECRET = azuread_application_password.password[0].value } : {}, var.app_settings)

app_service_plan_id = var.service_plan_id
storage_account_access_key = var.storage_account_access_key
Expand Down Expand Up @@ -158,3 +185,105 @@ resource "azurerm_monitor_diagnostic_setting" "diagnostic_setting" {
}
}
}

# Managed Identity Provider
data "azuread_client_config" "current" {}

resource "random_uuid" "oath2_uuid" {}

resource "azuread_application" "application" {
count = var.managed_identity_provider != null ? 1 : 0
display_name = var.managed_identity_provider.create.display_name
owners = var.managed_identity_provider.create.owners != null ? concat([data.azuread_client_config.current.object_id], var.managed_identity_provider.create.owners) : [data.azuread_client_config.current.object_id]
sign_in_audience = "AzureADMyOrg"
identifier_uris = local.identifiers

api {
requested_access_token_version = 2

oauth2_permission_scope {
admin_consent_description = var.managed_identity_provider.create.oauth2_settings.admin_consent_description
admin_consent_display_name = var.managed_identity_provider.create.oauth2_settings.admin_consent_display_name
enabled = var.managed_identity_provider.create.oauth2_settings.enabled
id = random_uuid.oath2_uuid.result
type = var.managed_identity_provider.create.oauth2_settings.type
user_consent_description = var.managed_identity_provider.create.oauth2_settings.user_consent_description
user_consent_display_name = var.managed_identity_provider.create.oauth2_settings.user_consent_display_name
value = var.managed_identity_provider.create.oauth2_settings.role_value
}
}

web {
redirect_uris = ["https://${var.logic_app_name}.azurewebsites.net/.auth/login/aad/callback"]

implicit_grant {
access_token_issuance_enabled = false
id_token_issuance_enabled = true
}
}

required_resource_access {
resource_app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph

resource_access {
id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # User.Read
type = "Scope"
}
}
}

resource "null_resource" "always_run" {
triggers = {
timestamp = "${timestamp()}"
}
}

resource "azapi_update_resource" "setup_auth_settings" {
count = var.managed_identity_provider != null ? 1 : 0
type = "Microsoft.Web/sites/config@2020-12-01"
resource_id = "${azurerm_logic_app_standard.app.id}/config/web"

depends_on = [
azurerm_logic_app_standard.app,
null_resource.always_run
]

body = jsonencode({
properties = {
siteAuthSettingsV2 = {
globalValidation = {
excludedPaths = []
require_authentication = true,
// Even though is looks weird, it is needed. Otherwise, the app and also the designer in Azure Portal are not working
// https://techcommunity.microsoft.com/blog/integrationsonazureblog/trigger-workflows-in-standard-logic-apps-with-easy-auth/3207378
unauthenticatedClientAction = "AllowAnonymous"
},
IdentityProviders = {
azureActiveDirectory = {
enabled = true,
registration = {
clientId = azuread_application.application[0].application_id
clientSecretSettingName = "MICROSOFT_PROVIDER_AUTHENTICATION_SECRET"
},
validation = {
allowedAudiences = local.allowed_audiences
}
}
}
}
}
})
lifecycle {
/* This action should always be replaces since is works under the hood as an api call
* So it does not really track issues with the function app properly
*/
replace_triggered_by = [
null_resource.always_run
]
}
}

resource "azuread_application_password" "password" {
count = var.managed_identity_provider != null ? 1 : 0
application_object_id = azuread_application.application[0].object_id
}
53 changes: 53 additions & 0 deletions modules/azure/logic_app_standard/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,56 @@ variable "log_analytics_diagnostic_categories" {
description = "Optional list of diagnostic categories to override the default categories."
default = []
}

variable "managed_identity_provider" {
type = object({
existing = optional(object({
client_id = string
client_secret = string
}))
create = optional(object({
application_name = string
display_name = string
oauth2_settings = object({
admin_consent_description = string
admin_consent_display_name = string
enabled = bool
type = string
user_consent_description = string
user_consent_display_name = string
role_value = string
})
owners = optional(list(string)) # Deployment user will be added as owner by default
redirect_uris = optional(list(string)) # Only for additional URIs, function uri will be added by default
group_id = optional(string) # Group ID where service principal of the existing application will belong to
}))
identifier_uris = optional(list(string)) # api://<application_name> will be added by default if application is create
allowed_audiences = optional(list(string)) # api://<application-name> will be added by default
})
validation {
condition = var.managed_identity_provider.existing != null || var.managed_identity_provider.create != null
error_message = "Variable managed_identity_provider has to provide either an existing managed identity provider or given information to create one"
}
description = "The managed identity provider to use for connections on this function app"
default = null
}

variable "ip_restrictions" {
type = list(object({
ip_address = optional(string),
service_tag = optional(string),
virtual_network_subnet_id = optional(string),
name = optional(string),
priority = optional(number),
action = optional(string),

headers = optional(list(object({
x_azure_fdid = optional(list(string)),
x_fd_health_probe = optional(list(string)),
x_forwarded_for = optional(list(string)),
x_forwarded_host = optional(list(string))
})))
}))
description = "A List of objects representing IP restrictions."
default = []
}