Skip to content

Azure Key Vault Secrets in Dataverse

Environment variables in Dataverse are a powerful vehicule to develop portable customizations between different environment. Recently, a new Secret Data Type was introduced that enables the use of secrets stored in Azure Key Vaults 🔐 .

The integration between Dataverse and Azure Key Vault was long-awaited and I am really happy to see it materialize. It brings new kind of use cases and an additional security layer to protect sensitive information needed in platform customizations.

In this post, I will share my findings setting up the key vaults. And, while most of the documentation and videos out there are showing how to consume secret environment variables in PowerAutomate Flows, I will focus on their usage inside Dataverse Plugin code.

Azure Key Vault setup

The first step is to setup an Azure Key Vault to hold the secrets and give Dataverse environments the right to read the secrets stored in the vault.

The official documentation gives really good instructions on how to configure your key vaults so I will not repeat everything here. The main steps are :

  1. Enable Microsoft.PowerPlatform as a resource provider in your Azure subscription
  2. Create a Key Vault
  3. Give proper security role to the Dataverse application

There are 2 permission model available in a Key Vault

  • Vault access policy
  • Azure role-based access control (RBAC)
Key vault with RBAC permission model

The official documentation assumes that the permission model of the Key Vault is ‘Vault access policy‘ follow the instructions if that is your case.

If you use Role-based access control (RBAC), you need to grant the Key Vault Secrets User role to the Dataverse application. Here’s how to do it in the Azure portal :

Head to the Access control (IAM) blade and add a Role Assignment, and select Key Vault Secrets User.

You will be prompted to select the members. Type Dataverse in the search box and the Dataverse application service principal will be proposed. Select the Dataverse application and save.

In the Access control (IAM) , you can now assess that the Dataverse application as proper access to ther Key Vault.

🔔 Be aware that once you granted the read secrets permissions to the Dataverse application on a given Key Vault, all the Dataverse environments in your tenant are entitled to read secrets from this vault.

So as a best practice, its a good idea to have dedicated Key Vaults for Dataverse secrets usage only and don’t mix up secrets from other systems.

It’s also recommended to have seperate key vaults for all your different environments (ex. DEV, QA, PROD)

Create a Secret in the Key Vault

For our example, we will create a secret with the following properties.

  • Name : TopSecret
  • Value : ‘🔐 For Your Eyes 👀 Only 🔐’

Given that your user has admin rights on the key vault secrets, head to the Secrets blade of the Key Vault and select Generate/Import.

Notice that you can even set an an activation and/or expiration date. That’s a feature that is not possible using a normal Environment variable. This could be quite useful in certain scenarios.

Create a Secret Environment Variable

We’re almost there. Now we need to create an Environment Variable of type Secret in Dataverse that will reference the secret that we just created in the key vault.

Switch to the PowerApps Maker portal and open a solution. Here, I created a solution called ‘KeyVault Test’ and added an Environment Variable from the ‘New‘ option in the top menu.

Navigate to a solution
Create an Environment Variable

Note : The user who creates the environment variable must have read permission on the specific key vault . This provides an additional layer of security

Be sure to choose the ‘Secret‘ data type and ‘Azure Key Vault‘ as the Secret Store. Then click on New Azure Key Vault secret reference where you’ll be asked to enter the info needed to resolve your key.

  • Azure subscription Id
  • Resource Group Name
  • Azure Key Vault Name
  • Secret Name : we will use ‘TopSecret’ wich is the name of the secret defined earlier

Once saved, the Environment Variable will only hold the reference to the secret in the key vault without storing its value inside your Dataverse environment. Think of it as a pointer.

The reference to the key vault secret will be stored in the EnvironmentVariableValue table using this form :

/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupname}/providers/Microsoft.KeyVault/vaults/{keyvaultname}/secrets/{secretname}

Retrieve the Secret Value

In order to retrieve the Environment variable secret value, the platform exposes an unbound Custom Api called RetrieveEnvironmentVariableSecretValue that can be called at runtime inside customizations.

One of the easiest way to test this API is to fire-up the XrmToolBox and open the Custom API Tester tool by Jonas Rapp.

Select the RetrieveEnvironmentVariableSecretValue custom API and set the name of the variable to fetch as the EnvironmentVariableName input. Execute the API and the secret value will be received in the EnvironmentVariableSecretValue output, as seen in the image below.

Retrieve EnvironmentVariable Secret using Custom API tester

Since the Custom API is adressable, it’s also possible to make a direct call to the Dataverse web API to retrieve the secret value.

POST => https://{{baseurl}}/api/data/v9.2/RetrieveEnvironmentVariableSecretValue

BODY :
{
    "EnvironmentVariableName" : "{VariableName}"
}

Using Secrets in Plugin code

Awesome, now let see how we can leverage the usage of a Secret Environment Variable in a Dataverse Plugin.

It’s only a matter of making a call to the RetrieveEnvironmentVariableSecretValue API inside the code of the plugin.

Here’s an example using Late Bound coding style. You need to create an OrganizationRequest object and set the EnvironmentVariableName parameter. Upon execution of the request, the secret value will be found in the EnvironmentVariableSecretValue Results collection of the response.

I personally prefer the Early Bound coding style for my plugin development. Early bound classes can be generated not only for Tables (Entities) but also for Custom Actions/API.

My weapon of choice for early bound classes generation is the spkl Task Runner by Scott Durow. Just add RetrieveEnvironmentVariableSecretValue in the “actions” section of the spkl.json configuration file.

This will produce specialized RetrieveEnvironmentVariableSecretValueRequest and RetrieveEnvironmentVariableSecretValueResponse that can be used instead of the generic OrganizationRequest used in the late bound example. Difference here is that there are no magic strings only concrete objects with properly typed properties.

Now, when deployed and registered on Create of a contact record, eighter of the plugins showed above will produce the following. I’m just throwing an error with the secret value.

I used the technique showed above to enhance my own Dataverse-CustomApis collection community project.

In this project I expose a Custom API called GetEnvironmentVariable. This API takes the name of an environmenmt variable as an Input and returns a bunch of information on the variable. Most importantly, it casts the value accordingly depending on the type (String, Boolean, Number and now … 🎉 Secret).

As you can see below, when the GetEnvironmentVariable API is called with a variable Key of type Secret. The secret value is resolved in the ValueSecret output property.

Install the latest release of the solution if you want to try it.

Takeaway

I’m thrilled by the addition of the Secret data type for Dataverse Environment Variables and I see a lot of potential use cases in my current projects.

There are a lot of benefits to store secrets in Key vaults instead of Dataverse tables. Think about logging, monitoring, key rotation just to name a few.

Here are some other great resources and use cases on the subject :

Photo by George Becker from Pexels

Published inBlog

11 Comments

  1. Nishant Rana

    thanks David for his wonderful article

  2. Mahesh Ghori

    Thanks David for detailed information. I am able to call this request from plugin and javascript but since last couple of days I am getting “Access Denied” error although it is working fine from Power automate.

    Do you have any idea what may be the reason behind this ?

    • David Rivard

      Hi Mahesh,
      I would have to do some testing on my side, I havent played with it lately.
      My guess is that it as something to do with the user making the request.

      I’ll let you know if I find anything.

      • Manish

        Hi David,
        Did you tried looking into the issue stated by Mahesh, It’s similar for me too. It’s working from Power Automate Flows but not from a custom Action. Throwing access denied error.

          • Victor

            Hi, does anyone have any workaround in order to change this RetrieveEnvironmentVariableSecretValue somehow? We need the client secret to be stored secured, but all the workarounds are inside D365. Does anyone achieve this somehow?

          • David Rivard

            Hi Victor,
            Hi havent tried it yet, but since the RetrieveEnvironmentVariableSecretValue is only accessible via PowerAutomate now, maybe having an HTTP triggered Flow that receives the key, makes the call RetrieveEnvironmentVariableSecretValue, and returns the secretvalue in the response would work. This endpoint could then be call from plugins or javascript. Kind of defeat the purpose of a secret though.

  3. Daniel Rumbak

    Hi David,

    Great article! Thank you for making this available.

    What is the benefit of using environment variables and dataverse connectors to get the secrets from Azure key vault over using the azure get secret connector?

    • David Rivard

      Thanks Daniel,
      One benefit I can see is that environment variables are solution-aware, meaning that you can package them in solutions and deploy them between environments. Also the value can be customized in each environment to point to a different key-vault. (think DEV-QA-PROD etc..). I never personally used the Azure Get Secret Connector, I will have look.

  4. Loroji

    Hello David,

    Thanks for the clear explanation, a very detailed guide!
    I’m only struggeling to provide the right permissions to Dataverse.
    The “Dataverse” service principal does not show up from the list.
    Any idea why I don’t have this in my environment?

    Best regards

Leave a Reply

Your email address will not be published. Required fields are marked *