Month: September 2021

Deploying secure communication with APIm and Functions using Managed Identity

Yes I know, not the snappiest title.
In my previous post Secure communication with APIm and Functions using Managed Identity, I showed how easy it is to setup OAUTH-based authentication in front of your Azure Functions, and how to configure an APIm policy to call that function, thereby uping the security level of your Azure Function communication.

CI/CD using ARM

I like ARM and after some serious digging I found the ARM template definition for how to secure your Azure Function. I prefer to use version V2, but you should look at V1 as well, as it has better documentation.

You can find the V2 template definition here, and here is V1.

When you deploy your function app you are using CI/CD and ARM. In order to add the functionality of the authourization setting you need to add a resourse called Microsoft.Web/sites/config and set its name to yourfunctionappname/authsettingsV2. You can either add this to your existing ARM-template or as a separate template. If you add it to your existing ARM template, do not forget to add the dependsOn property.

Minimal ARM Template

Here is my ARM-template that will deploy the settings addressed in the other post.

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
      "appClientId": {
        "type": "string",
        "metadata": {
          "description": "The Client ID of the AppReg that the function is a part of."
        }
      },
      "sites_function_name": {
        "type": "string",
        "metadata": {
          "description": "The function app name"
        }
      },
      "tenantID": {
        "type": "string",
        "metadata": {
          "description": "The ID of the tenant providing auth token"
        }
      }
    },
    "resources": [
      {
        "name": "[concat(parameters('sites_function_name'), '/authsettingsV2')]",
        "type": "Microsoft.Web/sites/config",
        "apiVersion": "2020-12-01",
        "properties": {
          "platform": {
            "enabled": true
          },
          "globalValidation": {
            "requireAuthentication": true,
            "unauthenticatedClientAction": "Return401"
          },
          "identityProviders": {
            "azureActiveDirectory": {
              "enabled": true,
              "registration": {
                "openIdIssuer": "[concat('https://sts.windows.net/',parameters('tenantID'),'/')]",
                "clientId": "[parameters('appClientId')]"
              }
            },
            "isAutoProvisioned": false
          },
          "login": {
            "tokenStore": {
              "enabled": true
            }
          },
          "httpSettings": {
            "requireHttps": true
          }
        }
      }
    ],
    "outputs": {}
  }

I will go thru some of the properties
properties/platform/enabled This basically enables the setting. You can switch this between true or false if you, for instance, have different rules for TEST and PROD. Simply turn it off for TEST and enable it for PROD.
globalValidation/requireAuthentication Should be set to true but in some cases you might want to be able to handle unauthorized calls as well.
globalValidation/unauthenticatedClientAction Set this to Return401 if the function should be called as APIs. For other scenarios, consult the documentation.
identityProviders/azureActiveDirectory This object contains all the settings needed for the AAD type authentication.
identityProviders/azureActiveDirectory/registration/openIdIssuer This points to your tenant using its GUID. If you do not know your tenant GUID you can visit whatismytenantid.com. This setting makes sure that the authenticating token is issued by your Azure tenant.
identityProviders/azureActiveDirectory/registration/clientId This is the ID of Application Registration that was created when you setup the function authentication. If this is the first run, create an application registration first and use it with this function. I made an easy walkthru post a while back.
properties/httpSettings/requireHttps always require HTTPs.

Additional settings

Consider reading the documentation for additional settings. There are a lot of properties relating to other authentication providers, but also some settings relating to authentication and AAD that you might find useful .
jwtClaimChecks/allowedGroups If you are using claims and groups/roles, you can make sure that the caller has the right credentials (I have not validated this functionality with APIm)
allowedClientApplications Stop callers that are not APIm simply by adding the clientID of your APIm (I think, I have not tried this)
allowedAudiences Might be useful to add other clients as audiences as well. The connected Application Registration ID (the clientID in the ARM-template) is always allowed, even if it is not added as allowed.

Next step

You should now add your version of the ARM template to your CI/CD process, and let me know how it works out for you. You can find me on Twitter.

Secure communication with APIm and Functions using Managed Identity.

Using manage service identity is an easy to configure, out of the box, functionality that ups your level of security within your organization.


Having an Azure Function exposed using Azure API management is very easy. So easy in fact that I will not address it here, but here is a good source if you need to know it, and here is a very basic one. In some cases, the level of security given by the Function’s out of the box functionality is too low. Just having a “code” to protect the function is not enough in my opinion. Especially since it is so easy to set this up. This post provides a walkthrough for using built-in functionality for Managed Service Identity (or MSI for short). As always, I try to show this in a simple, just make it work, way.

What is an MSI?

But I still need to explain the basics of an MSI. You want a service or a process to have an account, a way of showing its “identity” and you want that identity to be protected, but you do not want to handle (and send) passwords everywhere. This is where the Managed Service Identity comes into play. It is connected to the Azure AD, but the actual authentication is handled by Azure. You never need to send credentials. The authentication, and authenticity of the service is handled by Azure AD.

Looking at the concrete stuff, the MSI is an Enterprise Application in your AAD, viable only for that service instance.

Using MSI for other integration services

This “built-in” functionality means that you can use this way of securing not only functions but Logic Apps and Azure Service Bus as well. The service bus even allows you to combine it with RBAC.
Here is some documentation for securing Logic Apps in (almost) the same way, and here is a great post on how to setup MSI for Azure Service Bus.

What we need to make it work

  1. Your APIm instance must have a “Managed Identity” configured.
  2. Your function must have “Authentication” configured.
  3. The APIm has an updated policy.
  4. A successful test.

1: The APIm MSI

You can set that up using this documentation. Note that the screen capture in that post is a bit dated, but all the names are the same. I suggest you use System Assigned as the User Assigned is (still) in preview.

2: Configure Authentication for your function

This is easy but requires a couple of steps.

Find the authentication setting

In the left menu, you can find it under Settings.
Authmenu

Update Authentication Settings

Find and click Add Provider. This will setup everything you need.

Start by selecting Microsoft from the dropdown. Note that there are other IdP:s.

Fill in the rest according to this:

The name is up to you. I would just like to add that you should use an environment identifier in there somewhere.
Make sure you select 401 under Unauthenticated requests, the click Add to complete the configuration.

Back at the Authentication page, you can see that Azure created an Identity for your function. The App (client) ID will be used later. Note that you can only have one identity per Azure Function App. Every function in the App will be protected the same way.

3: The APIm Policy

We now have everything we need and can add the policy the APIm. This policy basically states that we would like to authenticate to a particular App ID using Managed Identity.

Open the Policy you need to update and add this before calling the function, in the inbound policy.

<authentication-managed-identity resource="e23a1800-0000-0000-0000-00000009a0" output-token-variable-name="msi-access-token" ignore-error="false" />
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + (string)context.Variables["msi-access-token"])</value>
</set-header>

The GUID value for the resource attribute is the App (client) ID of your function, simply paste yours instead of mine from the example.

4: A successful test

Use your favorite way of invoking the API and then call it. You do not need to change anything on the caller’s side. The API client does not need to update anything related to authentication.

If you want to make sure your authentication is working properly, remove the policy and call the API again. If everything is working properly, you should receive an authentication error.

Automation using CI/CD

I made a blog post about this. You can read it here.