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.
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.