Certificate-Based Authentication with Dynamics 365 and Azure Functions/Key Vault
There are two main ways to main ways to perform Server-to-Server (S2S) authentication: with a client id/client secret or with certificates. People most commonly use the client secret option as it is much easier to implement -- you create a new secret on the App Registration and you can use it. However, certificate-based authentication is generally considered to be more secure than using a client secret (which is effectively just a password). It seems that most people shy away from using certificates for authentication because of the perceived complexity in using them.
In this blog, I'll show that it is actually very easy to maintain self-signed certificates in an Azure Key Vault and use them to connect to Dynamics 365 through an Azure Function -- all with minimal configuration and code.
Configuration
In order to wire this up, we need to configure a few resources in Azure and Dynamics 365.
Azure Key Vault
This is where we will create and store the self-signed certificate. Alternatively, you could import a certificate you previously generated.
- Create a new Key Vault resource in Azure.
- Go to Certificates > Generate/Import
- Set the Certificate Name
- Set the Subject (can be anything)
- Click
Create
- After the certificate has generated, export it
- Download in CER format
- Copy the
Secret Identifier
from the bottom of the page.
- Download in CER format
Azure Active Directory
We need to register a new application in Azure AD and configure the certificate on it. This is the application that our Azure Function will use to get a valid OAuth access token which is authorized to access Dynamics 365.
- Go to Azure Active Directory > App Registrations
- Click
New Registration
- Give it a Name, you can leave the Redirect URI blank
- Copy the Application (client) ID value
- Click on
Certificates & secrets
- Upload the .cer file you downloaded above
- Upload the .cer file you downloaded above
Dynamics 365
Next, we need to configure an Application User in Dynamics 365. This user is mapped to the Azure AD App Registration, and it is granted a security role which controls what the user can access. For more details on this, check out this link.
- Go to Settings > Security > Users
- Switch the view to
Application Users
- Create a new User
- Switch to the
Application User
form - Populate the
Application ID
with theApplication ID
from the App Registration
- Switch to the
- Assign a security role to the user
Azure Function
Finally, we deploy the Azure Function which will use the certificate from the Key Vault to connect to our Dynamics 365 environment. The Azure Function uses a system
- Deploy the Azure Function
- See the next section for the code
- Go to Platform Features > Identity
- Turn the System Assigned identity to
On
- Turn the System Assigned identity to
- Go back to the Azure Key Vault.
- Click on Access Policies > Add New
- Select the principal that matches the managed identity of the Azure Function (should have the same name)
- Grant it "Get" access for "Secret permissions"
- Click OK
- Go back to the Azure Function
- Open the Configuration/Application Settings
- Set the "Certificate" application setting, replacing URI with the Secret Identifier you copied above.
@Microsoft.KeyVault(SecretUri=https://bguidinger.vault.azure.net/secrets/CertificateName/VersionNumber)
Development
The code for the Azure Function can be found here.
As you can see, the Function code is very simple -- we don't need to wire up any code to pull the certificate from the Azure Key Vault. Instead, we we just pull the configuration values from the App Settings...which includes the Certificate
setting value (which is the Base64 encoded certificate with the public and private key).
var certificateString = ConfigurationManager.AppSettings["Certificate"];
var certificateBytes = Convert.FromBase64String(certificateString);
var certificate = new X509Certificate2(certificateBytes, string.Empty, X509KeyStorageFlags.MachineKeySet);
Once we have the X509Certificate2
object, we can use it with the CrmServiceClient
. Note that the second and third parameters (certificate store/thumbprint) are not required since we are directly passing the certificate in.
var client = new CrmServiceClient(certificate, StoreName.My, null, instanceUri, true, null, clientId, null, null);
Once we have the CrmServiceClient
, we can check the IsReady
parameter to make sure we connected successfully. If it's true
then we're connected to CRM!
Testing
All that's left to do now is test the Function! To do this, we can open up Postman and execute an HTTP GET request to the Function URL (since it's an HTTP Triggered function).
So there you have it. An Azure Function that connects to Dynamics 365 using certificate-based authentication with minimal configuration and code! In the next blog, I'll show how, if you're using an App Service, you can use an Azure Managed Identity (both system-assigned and user-assigned) to make connecting to Dynamics 365 even easier.
References
Comments
-
I figured out getting the certificate from keyVault now I have an issue with CrmServiceClient. It seams to be for .NET 4.8 and I am using 7 :-) Is the a core version for Microsoft.Xrm.Tooling.Connector?
-
-
My x is ""@Microsoft.KeyVault(SecretUri="">af2crmkey.vault.azure.net/.../e7f85f90866b....)"" but I get an error:"System.FormatException: 'The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.'" on the line " var certificateBytes = Convert.FromBase64String(certificateString);" I assume InstanceUrl should be something like "https://{my org}.crm.dynamics.com" Thank you
-
-
The key vault certificate only download CSR files but the app registration allows only CER files. Can you update this to explain what to do now? Thank you.
-
Hello, thank you for your blog ! * i have made like you string ConnectionStr = $@"AuthType=Certificate; SkipDiscovery=true; url={InstanceUri}; thumbprint={CertThumbPrintId}; ClientId={AppID}; RequireNewInstance=true"; i have create certificate with azure vault key, i have downloaded certificate, next i imported the certificate to my app registration but i get error:/ Microsoft.Powerplatform.Cds.Client.Utils.CdsConnectionException: Failed to connect to Common Data Service ---> System.Exception: Failed to locate or read certificate from passed thumbprint. ---> System.Exception: Failed to find certificate with thumbprint: 8B06E01C39B7AFF37AD82C36B903997222F67799. i apperciate any help Thank you Cordially
*This post is locked for comments