Search code examples
azure-logic-appsazure-logic-app-standard

Managed API connections deployed from ARM templates throw 403 error - Standard Logic Apps


I have problems with authentication in Standard (not Consumption) Logic Apps that use managed connections deployed from ARM templates.

My Logic Apps don't have a system-assigned managed identity. They use a user-assigned managed identity to communicate with the internal token store.

As well as azureblob and azuredatafactory (managed identity authentication), so and sharepointonline (authenticated by a user manually) API connections, although deployed successfully, give the same error when I try using them from a Logic App workflow:

Error from token exchange: Permission denied due to missing connection ACL

403 Error from token exchange: Permission denied due to missing connection ACL

{
  "status": 403,
  "source": "https://logic-apis-uksouth.token.azure-apim.net:443/tokens/logic-apis-uksouth/****************/azuredatafactory/********************************/exchange",
  "message": "Error from token exchange: Permission denied due to missing connection ACL: User = ********-****-****-****-************@********-****-****-****-************ appid=********-****-****-****-************, connection=logic-apis-uksouth/azuredatafactory/********************************"
}

For the API connection deployment, I'm using the following ARM template, as described here: ARM template for API connections and managed identities

{
    "type": "Microsoft.Web/connections",
    "name": "[parameters('connection-name')]",
    "apiVersion": "2016-06-01",
    "location": "[parameters('location')]",
    "kind": "V2",
    "properties": {
        "api": {
            "id": "[subscriptionResourceId('Microsoft.Web/locations/managedApis', parameters('location'), 'azuredatafactory')]"
        },
        "customParameterValues": {},
        "displayName": "[parameters('connection-displayname')]",
        "parameterValueType": "Alternative"
    }
}

The connections.json file looks as described here: Logic app resource definition and connections that use a managed identity

{
    "managedApiConnections": {
        "azuredatafactory": {
            "api": {
                "id": "/subscriptions/{Azure-subscription-ID}/providers/Microsoft.Web/locations/uksouth/managedApis/azuredatafactory"
            },
            "authentication": {
                "type": "ManagedServiceIdentity",
                "identity": "<user-assigned-identity>"
            },
            "connection": {
                "id": "/subscriptions/{Azure-subscription-ID}/resourceGroups/{resource-group-name}/providers/Microsoft.Web/connections/<connection-name>"
            },
            "connectionProperties": {
                "authentication": {
                    "audience": "https://management.core.windows.net/",
                    "type": "ManagedServiceIdentity",
                    "identity": "<user-assigned-identity>"
                }
            },
            "connectionRuntimeUrl": "<connection-runtime-URL>"
        }
    }
}

The workflow gives the error message above if the managed API connection is deployed from the ARM template, however it works fine with the managed API connection created manually from the Logic App workflow designer.

From this - Set up advanced control over API connection authentication - I understand something could be wrong with the first authentication section used for communicating with the internal token store. However, this section is identical for the manually created API connections (which work) and for the API connections deployed from ARM templates (which don't work). Therefore, it seems that something is wrong with the deployed API connections and not with connections.json.

Update: I am using the following workaround for now -

  1. create the API connection from the ARM template (it wouldn't be working yet)
  2. create another API connection from the Logic App manually, using the same user-assigned managed identity
  3. edit the Logic App workflow to use the manually created API connection and then run the workflow - the API connection would work
  4. remove these changes by editing the Logic App workflow to use the first API connection (deployed from the ARM template) and run the workflow again
  5. the connection wouldn't work immediately, but it would start working when the workflow is run in a few minutes again

I'd appreciate if someone could point me in the right direction, what is the problem here? What the API connection deployed from the ARM template doesn't work as it should straight away?


Solution

  • The problem is with the access policies that have to be set up (in this case - deployed) in the V2 API connections.

    The user-assigned managed identity used to authenticate for the internal token store needs to be given access to the API connection - similar to how it's done in the ARM template for API connections and managed identities section of the Microsoft article.

    For user-assigned managed identities the ARM template will look like this:

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "connection_name": {
          "type": "string",
          "metadata": {
            "description": "Name of the API connection"
          }
        },
        "location": {
          "type": "string",
          "defaultValue": "[resourceGroup().location]",
          "metadata": {
            "description": "Location of the connection"
          }
        },
        "managedIdentity_resourceId": {
          "type": "string",
          "metadata": {
            "description": "Resource ID of the managed identity used by the Logic App"
          }
        },
        "managedIdentity_principalId": {
          "type": "string",
          "metadata": {
            "description": "Principal ID of the managed identity used by the Logic App"
          }
        }
      },
      "resources": [
        {
          "type": "Microsoft.Web/connections/accesspolicies",
          "apiVersion": "2016-06-01",
          "name": "[concat(parameters('connection_name'), '/', last(split(parameters('managedIdentity_resourceId'), '/')), '-', parameters('managedIdentity_principalId'))]",
          "location": "[parameters('location')]",
          "dependsOn": [
            "[resourceId('Microsoft.Web/connections', parameters('connection_name'))]"
          ],
          "properties": {
            "principal": {
              "type": "ActiveDirectory",
              "identity": {
                "objectId": "[parameters('managedIdentity_principalId')]",
                "tenantId": "[subscription().tenantId]"
              }
            }
          }
        }
      ]
    }
    

    Once the access policies have been set up on the API connection as required, the "Error from token exchange: Permission denied due to missing connection ACL" error should disappear.