feat: Added Standard Logic App with Managed Identity and IP restriction (for HTTP trigger)#445
Merged
tom-reinders merged 5 commits intodevelopfrom Feb 11, 2025
Merged
Conversation
…on (for HTTP trigger)
tom-reinders
suggested changes
Feb 10, 2025
Contributor
|
For later reviewing of changes to the files compared to base files it probably copied from: diff --git a/modules/azure/logic_app_standard/main.tf b/modules/azure/logic_app_standard_http_managed_identity/main.tf
index 0b8c7e1..e56e9f4 100644
--- a/modules/azure/logic_app_standard/main.tf
+++ b/modules/azure/logic_app_standard_http_managed_identity/main.tf
@@ -10,6 +10,14 @@ terraform {
source = "hashicorp/archive"
version = "~> 2.3"
}
+ azapi = {
+ source = "Azure/azapi"
+ version = "~> 1.4"
+ }
+ azuread = {
+ source = "hashicorp/azuread"
+ version = "~> 2.36"
+ }
}
backend "azurerm" {}
@@ -23,8 +31,10 @@ 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 = concat(["api://${var.managed_identity_provider.create.application_name}"], var.managed_identity_provider.identifier_uris != null ? var.managed_identity_provider.identifier_uris : [])
+ allowed_audiences = concat(local.identifiers, var.managed_identity_provider.allowed_audiences != null ? var.managed_identity_provider.allowed_audiences : [])
}
resource "azurerm_logic_app_standard" "app" {
@@ -47,11 +57,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",
+ WEBSITE_NODE_DEFAULT_VERSION = "~18",
+ FUNCTIONS_WORKER_RUNTIME = "node",
+ MICROSOFT_PROVIDER_AUTHENTICATION_SECRET = "${var.managed_identity_provider != null ? azuread_application_password.password[0].value : ""}"
}, var.app_settings)
app_service_plan_id = var.service_plan_id
@@ -158,3 +193,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
+}
diff --git a/modules/azure/logic_app_standard/variables.tf b/modules/azure/logic_app_standard_http_managed_identity/variables.tf
index 7853ec4..c096e40 100644
--- a/modules/azure/logic_app_standard/variables.tf
+++ b/modules/azure/logic_app_standard_http_managed_identity/variables.tf
@@ -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 = []
+} |
Contributor
Author
This was created as a merge of the function app module and the standard logic app module. Based on Artiom's suggestion, I am checking now if we can put this change in the already existing standard logic app module. So far it seems it is possible, I am just ensuring there are no breaking changes and I'll push it soon |
tom-reinders
suggested changes
Feb 11, 2025
tom-reinders
approved these changes
Feb 11, 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.