{"content":"The ability to assign managed identities to Dataverse plug-ins was recently introduced in the Power Platform and was received with waves of likes and thumbs up from the Power Platform community.\nRightfully so, this powerful feature enables Dataverse plug-ins to securely connect with Azure resources without the hassle of managing credentials.\nHowever, due to technical constraints and limited documentation, setting up plug-in managed identities is not that straightforward and can prove to be a daunting process, even for seasoned Power Platform developers.\nOne aspect that I found unintuitive is the creation of managed identity records in Dataverse and their association to plug-in assemblies. This sparked the idea for my latest community tool the Plugin Identity Manager for the XrmToolBox.\nYou can use the tool to:\n🔧 Create, Update and Delete Managed identity records in Dataverse\n🔗 Link Managed Identity to plugin assemblies\n👀 Inspect existing Plugin/Identity configuration\nIn the following, I will show how to setup a managed identity for a Dataverse plug-in from scratch and use the Plugin Identity Manager tool for the final configuration step.\nImportant! at the time of writing, managed identities for Dataverse plug-ins is still in preview. Some features and implementation details might change in the future.\nManaged Identities for Dataverse Plugins In a nutshell, Azure Managed Identity enables secure, password-free access to Azure resources, simplifying both security and management in the application lifecycle. Any Azure resource that supports Azure Entra authentication can be accessed by a managed identity, opening up a wide range of scenarios.\nI highly recommend these resources that goes deeper on the matter🔗Power Platform’s protection — Managed Identity for Dataverse plug-ins by MVP Raphaël Pothin 🔗Developer introduction and guidelines - Managed identities for Azure resources | Microsoft Learn\nAs a proof of concept, I will demonstrate how to access a secret stored in an Azure Key Vault from within a Dataverse plug-in using a managed identity, removing the burden of credential management to the Azure resource.\nI\u0026rsquo;ll create a Custom API—mainly for easier testing—that takes the name of a Key Vault and the name of a secret in the Key Vault as input and return its value as output. I’ll also output the token for testing purposes. Screenshot from my Custom API Manager tool for XrmToolBox\nThe code looks like this and basically recreate the following Rest Api call to the key vault.\nGET {vaultBaseUrl}/secrets/{secret-name}/{secret-version}?api-version=7.4\nusing Microsoft.Xrm.Sdk; using System; using System.Collections.Generic; using System.Net.Http.Headers; using System.Net.Http; namespace Dataverse.ManagedIdentity.Plugin { public class GetSecretValue : IPlugin { public void Execute(IServiceProvider serviceProvider) { // Get Services. var pluginExecutionContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); var identityService = (IManagedIdentityService)serviceProvider.GetService(typeof(IManagedIdentityService)); var inputparameters = pluginExecutionContext.InputParameters; var outputparameters = pluginExecutionContext.OutputParameters; //INPUT of the Custom API var keyvaultname = (string)inputparameters[\u0026#34;KeyVaultName\u0026#34;]; var secretname = (string)inputparameters[\u0026#34;SecretName\u0026#34;]; // Get Token var scopes = new List\u0026lt;string\u0026gt; { \u0026#34;https://vault.azure.net/.default\u0026#34; }; var token = identityService.AcquireToken(scopes); outputparameters[\u0026#34;Token\u0026#34;] = token; outputparameters[\u0026#34;Message\u0026#34;] = string.Empty; var keyvaultsecretUrl = $\u0026#34;https://{keyvaultname}.vault.azure.net/secrets/{secretname}?api-version=7.4\u0026#34;; try { using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\u0026#34;Bearer\u0026#34;, token); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\u0026#34;application/json\u0026#34;)); var request = new HttpRequestMessage(HttpMethod.Get, new Uri(keyvaultsecretUrl)); var response = client.SendAsync(request).Result; string json = response.Content.ReadAsStringAsync().Result; var keyVaultResponse = System.Text.Json.JsonSerializer.Deserialize\u0026lt;KeyVaultResponse\u0026gt;(json); outputparameters[\u0026#34;SecretValue\u0026#34;] = keyVaultResponse.value; outputparameters[\u0026#34;Success\u0026#34;] = true; } } catch (Exception ex) { outputparameters[\u0026#34;Success\u0026#34;] = false; outputparameters[\u0026#34;Message\u0026#34;] = ex.Message; } } } } public class KeyVaultResponse { public string value { get; set; } public string id { get; set; } } All the magic lies in the AcquireToken method call of the IManagedIdentityService. Without proper configuration of the managed identity on both the Azure and Dataverse sides, accessing key vault secrets will be out of reach to the plug-in code.\nI will follow the official documentation and try to fill the gaps where needed.\n🔗Set up managed identity for Power Platform (preview) - Power Platform | Microsoft Learn\nStep #1 : Sign the plugin with a certificate One of the first step in the process is to sign the plugin assembly with a certificate (.pfx signing) . This is essential otherwise an error will be thrown while trying to associate a Dataverse managed identity record to the plugin assembly.\nDespite years of development on the platform, I never signed plug-in assemblies with a certificate (.pfx) and had always relied on the simpler strong name signing (.snk). As a result, this part proved to be a bit tedious for me as I am not a security expert.\nThe official doc is a bit scarce on this aspect but I followed the recipe described in this great post by Clive Oldridge. It shows how to create a self-signed certificate ( not recommended for production) that will be enough for our experimentations.\nI\u0026rsquo;m copying the powershell script here but go see the entire blog post for more context\n🔗 Set up managed identity for Power Platform Plugins - Clive Oldridge on Power Platform Blog\n$ku_codeSigning = \u0026#34;1.3.6.1.5.5.7.3.3\u0026#34;; $codeSignCert = New-SelfSignedCertificate ` -Type \u0026#34;CodeSigningCert\u0026#34; ` -KeyExportPolicy \u0026#34;Exportable\u0026#34; ` -Subject \u0026#34;ManagedIdentityPlugin\u0026#34; ` -KeyUsageProperty @(\u0026#34;Sign\u0026#34;) ` -KeyUsage @(\u0026#34;DigitalSignature\u0026#34;) ` -TextExtension @(\u0026#34;2.5.29.37={text}$($ku_codeSigning)\u0026#34;, \u0026#34;2.5.29.19={text}false\u0026#34;) ` -CertStoreLocation cert:\\CurrentUser\\My ` -KeyLength 2048 ` -NotAfter ([DateTime]::Now.AddDays(90)) ` -Provider \u0026#34;Microsoft Software Key Storage Provider\u0026#34;; Once created, you can inspect the certificate with certmgr. Grab the value of the thumbprint, it will be needed later.\nNow, with the certificate at hand the plug-in assembly can be signed using this command.\nsigntool sign /n {{CERTIFICATENAME}} /fd SHA256 {{ASSEMBLYNAME}}.dll Although I much prefer setting up a post-build command in Visual Studio to automatically sign the assembly upon every successful build of the plug-in project.\n\u0026#34;C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.22621.0\\x64\\signtool.exe\u0026#34; sign /n {{CERTIFICATENAME}} /fd SHA256 $(SolutionDir)bin\\$(Configuration)\\{{ASSEMBLYNAME}}.dll Once the plug-in assembly is signed, you can assess the presence of the signature by inspecting the file properties.\nThat’s one big step down! Now, let’s head over to the Azure setup.\nStep #2 : Configure the managed identity in Azure Two types of managed identities can be configured: a user-assigned managed identity or an application registered in Microsoft Entra ID.\nFor the current scenario, I will create a user-assigned managed identity, easily available to create from the Azure Portal.\nAssign the identity to a resource group and give it a name.\nOnce created, keep the Client ID at hand it will be needed later on.\nNext, grant the newly created identity access to the required Azure resources via the Azure role assignment tab. Here the Key Vault Secrets User RBAC role is given on the Key Vault we want to expose to the plug-in.\nNow on to the trickiest—and, in my opinion, under-documented—part: configuring federated credentials for managed identity.\nBefore starting the configuration have these info at hand\nDataverse Environment Id Thumbprint of the certificate Navigate to the Federated credentials tab and click on Add Credential\nSelect Other as Federated credential scenario\nAnd enter the following configurations.\nIssuer Url: Take the Dataverse Environment ID (GUID), remove the dashes, and format it by placing a period between the first 30 characters and the last 2 characters to construct the Issuer URL.\nhttps://{ENVID_FIRST30}.{ENVID_LAST2}.environment.api.powerplatform.com/sts\nex. https://3608895ef8844a53a065b306837e60.96.environment.api.powerplatform.com/sts\n2- Subject : Important! I went through some trial and error here, but this configuration finally worked for me. The thumbprint must be in uppercase, and the environment Id should be in the usual GUID format (lowercase with dashes)\ncomponent:pluginassembly,thumbprint:{THUMBPRINT_UPPERCASE},environment:{ENVID}\nex. component:pluginassembly,thumbprint:6C79AFBC726410ECB5A821F7C4663EC0299CD748,environment:3608895e-f884-4a53-a065-b306837e6096\nAudience : By default the audience is set to api://AzureADTokenExchange. I found out that the audience needed to be set in lowercase api://azureadtokenexchange otherwise errors where thrown\nHere is the error I got when using the default value, after I changed the audience to lowercase, it went through correctly.\nAn unexpected error occurred: Microsoft.Identity.Client.MsalServiceException: A configuration issue is preventing authentication - check the error message from the server for details. You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS7002122: No matching federated identity record found for presented assertion audience \u0026rsquo; api://azureadtokenexchange\u0026rsquo;. The audience matches with case-insensitive comparison, but not with case-sensitive comparison. Please check your federated identity credential Subject, Audience and Issuer against the presented assertion. https://learn.microsoft.com/entra/workload-id/workload-identity-federation\nAnd now, the final piece of the puzzle—where I finally get to show off my tool! 😉\nStep #3 : Configure the managed identity in Dataverse Now that all is set in Azure, its time to register the managed identity in Dataverse and associate the record to the plugin assembly.\nSince there is no available UI for Managed Identity records in Dataverse, the official documentation instruct the user to make 2 platform WebApi requests.\nPOST https://\u0026laquo;orgURL\u0026raquo;/api/data/v9.0/managedidentities\n{ \u0026#34;applicationid\u0026#34;:\u0026#34;\u0026lt;\u0026lt;appId\u0026gt;\u0026gt;\u0026#34;, \u0026#34;managedidentityid\u0026#34;:\u0026#34;\u0026lt;\u0026lt;anyGuid\u0026gt;\u0026gt;\u0026#34;, \u0026#34;credentialsource\u0026#34;:2, \u0026#34;subjectscope\u0026#34;:1, \u0026#34;tenantid\u0026#34;:\u0026#34;\u0026lt;\u0026lt;tenantId\u0026gt;\u0026gt;\u0026#34; } PATCH https:// \u0026laquo;orgURL\u0026raquo;/api/data/v9.0/pluginassemblies(\u0026laquo;PluginAssemblyId\u0026raquo;)\n{ \u0026#34;managedidentityid@odata.bind\u0026#34;: \u0026#34;/managedidentities(\u0026lt;\u0026lt;ManagedIdentityGuid\u0026gt;\u0026gt;)\u0026#34; } While, there\u0026rsquo;s nothing wrong with making Web API calls if you\u0026rsquo;re comfortable with it, I think it falls short in terms of intuitive user experience. This is where the Plugin Identity Manager for the XrmToolBox comes in and brings value to the table.\nYou can download the tool from the Tool Library of the XrmToolBox\nSelect plugin assembly The first thing to do after firing up the tool is to choose your plug-in assembly. You have the choice to list all the plugins assembly installed in the environment of choose a given solution. You can also filter out managed or unmanaged assemblies.\nCreate and Assign a new Managed Identity Record Once the plug-in selected, you can create a new Managed Identity record to associate with the assembly by clicking Link to New Identity\nIn the creation screen you are invited to set these parameters :\nName : I have defaulted to \u0026rsquo; {Plugin Name} Identity\u0026rsquo; but you can enter what you want. The official docs doesn\u0026rsquo;t highlight the Name field in the Web API call example, but it’s good practice to assign a name to the record. This makes it easier to manage and include in a solution later on.\nApplicationId: This is the ClientId of of the managed identity created in Azure. TenantId: the GUID of the tenant where the Azure resource is located Credential Source : I am defaulting and forcing the \u0026rsquo; IsManaged (2)\u0026rsquo; value as the other available values seems to be reserved by Microsoft for internal scenarios. Drop me a line in the Github repo if you want me to open this. Subject Scope : I default to \u0026rsquo; Environment Scope (1)\u0026rsquo; but there are 2 other values. Global Scope or DevOnly Scope. Environment Scope limits the managed identity to the same tenant as the Dataverse environment. Global scope, on the other hand, would enable access to Azure resources located on another tenant. Note that I haven\u0026rsquo;t tested Global scope yet and am unsure if it\u0026rsquo;s available in the preview release of the feature.\nBy clicking on Create and Link, the managed identity record will be created and associated with the selected plug-in assembly.\nAt this point all the configuration is done and we can proceed to the testing phase. But here are some additional features of the tool.\nAssign to an existing Managed Identity Record If the desired Managed Identity record already exists, you also have the choice to Link to existing Identity\nThis will display a list of the Managed Identity records where credential source is \u0026rsquo; IsManaged (2)\u0026rsquo; allowing you to link them to the selected plug-in.\nUpdate/Delete a Managed Identity Record The tool allows modification of a Managed Identity record\u0026hellip;\n\u0026hellip; And deletion as well\nWithout further ado, let\u0026rsquo;s proceed to the testing phase.\nStep #4 : Test the plug-in Now comes the moment of truth—testing whether the plugin code can successfully access the Azure Key Vault secret.\nIn the Key Vault ( kv-isv-dev) that I’ve granted access to the managed identity, I have created a secret named MySecret.\nUsing the Custom API Tester Tool from Jonas Rapp, I can execute the plug-in code.\nWith the GetSecretValue Custom API ( described earlier) selected, simply provide the name of the Azure Key Vault, the name of the secret and Execute the API.\nIf all is well configured, the value of the secret is correctly retrieved by the plug-in code. All without any credentials, thanks to the managed identity and the federated credential.\nThat is all for now ;)\nTake Away Overall, managed identities for Dataverse plug-ins is a great new feature that deserves to be on Power Platform developers radar. But, you\u0026rsquo;ll have to admit that there is a certain complexity associated with the process. It’s important to weigh the pros and cons before pursuing this approach.\nI hope that some of you will find the Plugin Identity Manager tool useful to make the setup experience more enjoyable and coherent. Please submit any comments or ideas to improve the tool in the github repo\nThere’s much more to discuss on the subject, such as current limitations and ALM considerations, but that’s beyond the scope of this blog post. I will certainly continue my experimentations and share my findings.\nUntil then,\nLinks GitHub - drivardxrm/Driv.XTB.PluginIdentityManager: XrmToolBox Tool to help manage Managed Identity records in Dataverse XrmToolBox Tool to help manage Managed Identity records in Dataverse - drivardxrm/Driv.XTB.PluginIdentityManager github.com Power Platform managed identity overview (preview) - Power Platform Learn about managed identity for Power Platform and Dynamics 365 apps. learn.microsoft.com Set up managed identity for Power Platform (preview) - Power Platform Learn how to set up Power Platform managed identity. learn.microsoft.com Set up managed identity for Power Platform Plugins - Clive Oldridge on Power Platform Blog In the following blog, I’m going to guide you on the set up of managed identity for Power Platform. Once we have finished you should have everything you need to be able to create a plugin that can communicate with an azure resource. Why do we want to use manage identity? Managed identity allows your […] coldridge.azurewebsites.net Power Platform’s protection — Managed Identity for Dataverse plug-ins Once the network traffic is secured it is time to get out of the way identity credentials to integrate with Azure resources medium.com Use managed identities for Dataverse plug-ins Power Platform managed identities allow publishers of Dataverse plug-ins to securely connect to Azure resources without having to store or expose credentials. learn.microsoft.com Power Platform | Managed Identity – bearer token generation w/o Application Id and Secret Reference – [Note : This is in Preview] Power Platform managed identity allows Dataverse plug-ins to connect with Azure resources supporting managed identity without the need of credentials. … malvankaraniket.wordpress.com Image by freepik\n","date":"2024-11-03T19:41:42Z","image":"/how-to-secure-a-dataverse-plug-in-with-managed-identity-using-plugin-identity-manager-for-xrmtoolbox/3148275-min-scaled.jpg","permalink":"/how-to-secure-a-dataverse-plug-in-with-managed-identity-using-plugin-identity-manager-for-xrmtoolbox/","title":"How to Secure a Dataverse Plug-in with Managed Identity using Plugin Identity Manager for XrmToolBox"}