How to use Azure Functions to extend Power Platform - Part 2

Geschrieben von Alan Rachid am 21.11.2024

This is part 2 of my series on how to use Azure functions to extend the Microsoft Power Platform. In the first article, I described what Azure Functions are and how to connect to a Dataverse environment using the ServiceClient class and appsettings in combination with Azure Key Vault. If you haven't read it yet, I suggest you read it first. In this article I will describe what Managed Identities are in Azure and how you could use a Managed Identity to connect to Dataverse from within an Azure Function.

What is a Managed Identity?

Managed Identity in Azure is a feature to simplify and streamline the authentication process when applications and services interact with each other. As described in Part 1 of this blog series, a common approach to authentication is to use secrets or credentials. By using Managed Identities the need to use and store credentials in you application is eliminated. A Managed Identity creates an automatically managed identity in Microsoft Entra Id, which can be used by applications to connect to Azure Services that support Microsoft Entra authentication. There are two types of Managed Identity:

  • System-assigned: Many Azure resources nowadays allow you to directly enable a managed identity. When enabling this a service principal is created in Microsoft Entra Id. The service principal automatically gets deleted when you delete the corresponding Azure resource. This managed identity can only be used by the resource and you are able to authorize the identity to use other Azure services. We are using a system-assigned identity in this tutorial!
  • User-assigned: A user-assigned identity is managed as a separate resource. Unlike a system-assigned identity, a user-assigned identity can be used by multiple resources. This also means that if you delete a resource that uses the user-assigned identity, the identity is not deleted.
The authentication process of a managed identity is handled by first acquire an OAuth 2.0 token from Microsoft Entra Id to authenticate to other resources like Dataverse. The managed identity uses the token to access the target service without needing a clientId or secret.

Prerequisites to get started

Before we get started to trying out how to integrate Dataverse with Azure Functions by using Managed Identity there are some steps which you need to process before:
  • Enable Managed Identity in the Function App: To enable the system-assigned identity for your function app, open the function app in azure and navigate to the settings area. In the settings area click on identity. Make sure that you are on the tab "system assigned" and switch the Status to on.
  • After enabling the system-assigned managed identity you should be able to find the identity in the enterprise application area of Microsoft Entra Id. Copy the application ID and save it somewhere. You will need it in the next step.
  • Add managed identity as app user to your Dataverse environment: The second step to use the managed identity of your function app inside of a function to connect to Dataverse is to add the identity as app user to the relevant environment. Therefore open the admin center of power platform, navigate to the corresponding environment, open the users list and switch to app users. Add a new one and in the "Add an app"-button past the application id you copied from the step before. Assign a business unit and security role to the app user.
After my first attempt, I was super excited that my code, which follows in the next section, worked like a charm. I tested everything locally, but after deploying my function app to the cloud, my function didn't work anymore. It took me some time and several Google searches to find out why (or to find a blog post by someone who knew why). In this blog post , the author also shows how to connect to Dataverse using a managed identity, and explains the order in which the DefaultAzureCredential class (used in the code below) figures out which credentials to use. Long story short, it worked locally because the DefaultAzureCredential class took my Visual Studio code credentials locally. But because I didn't add the managed identity as an application user in my Dataverse environment, the code couldn't work in the cloud.

Use a managed identity to connect to Dataverse from within an Azure Function

In this section, I will demonstrate the code I have written to not use secrets or connection strings to connect to Dataverse from within an Azure Function. The sample code shown in this section uses .Net 8 in the isolated worker model of Azure Functions. The first thing you need to do is install the appropriate nuget packages:
Azure Functions Core Tools
I wrote this article using the Youtube video from the Power Maverick channel, in which he demonstrates the use of Managed Identity to connect to Dataverse. Credits to the author! In this video, the author explains how to use Dependency Injection on the ServiceClient class (connection to the Dataverse), so that the connection can be shared between functions in a function application. The biggest difference between his code and my code is the way how Dependecy Injection is handled. I assume this is because of the new isolated worker model. In the traditional approach to injecting something on function startup, you had to create a class (StartUp.cs) that inherited from FunctionsStartup. In the new model, the Program.cs file is the entry point, and dependency injection is configured using standard ASP.NET Core patterns. This change makes Azure Functions more like a typical .NET application. Let's have a look at the code to connect to Dataverse with the help of Managed Identity:
Setup Managed Identity to connect to Dataverse using extension method for IServiceCollection
In the Function App Project I have added a new Class "DependencyInjection.cs". This class implements an extension method for the IServiceCollection, so that all the relevant dependencies for our function app can be registered in one place and the main program.cs stays small and clear. At a high level, this class registers an instance of DefaultAzureCredential with the DI container, which allows us to use authentication with Azure services using Managed Identity. It also registers a ServiceClient instance, which provides an implementation of IOrganizationService for interacting with Microsoft Dataverse. Both services are registered to the DI container as singletons. This means that the service is created once and reused for all subsequent requests. The DependencyInjection.cs also implements a custom token provider function to obtain access tokens for authenticating requests to Dataverse. It uses the DefaultAzureCredential to authenticate and caches tokens to avoid redundant requests.

The function "AddFunctionDependencies" is than called in the Program.cs of the function app.
call extension method for dependency injection in Program.cs
The final step in using Managed Identity with dependency injection is to update your function code. You will need to pass the IOrganizationService as a parameter to the constructor and store it in a private field.
Function with new constructor parameter
That's it. Your function will now connect to dataverse without using a specific appregistration, secret or connectionstring. It'S all handled by the managed identity.

NOTE: In the DependencyInjection class we are still using a environment variable to access the URL of your Dataverse instance. Make sure you have this in you appsettings locally and in the environment variables in the cloud.

Recap and Outlook

This article showed how to connect to a Dataverse instance using Azure Functions and the ServiceClient class from the Microsoft.PowerPlatform.Dataverse.Client nuget package. We removed all maintenance overhead and security risk by using Managed Identity. We learned that there are two types of managed identity: system-assigned and user-assigned. The easiest way to use Managed Identity with Azure Functions is to enable the out-of-the-box system-assigned identity. Don't forget the necessary step to add the managed identity as an application user in your Dataverse environment. Locally, your code may work because the DefaultAzureCredential class can figure out your credentials using your Visual Studio user, but in the cloud it will fail. Of course, the biggest benefit of using Managed Identity is that you no longer have to worry about managing secrets and reducing security risks because no secrets are stored in any app settings files or environment variables.

In my next article about Azure Functions and Dataverse I will dive deeper into scenarios where Dataverse benefits from the usage of Azure Functions.

Again credits to:
Natraj Yegnaraman
Danish Naglekar

They provided some great content, which was really helpful!

As I am still on a learning journey, the blog post may contain errors or areas that can be better addressed. As always, I am grateful for feedback.

If you have any questions about our best practices or need support with implementing Microsoft Power Platform or Dynamics 365, please feel free to reach out to us. We look forward to connecting with you.

Nachricht senden