This tutorial explains how to automatically enforce Azure Multi-Factor Authentication on users with System administrator role assigned in Dynamics 365 for Finance and Operations. For this purpose we consume the OData services of Dynamics 365 for Finance and Operations and use Azure Logic Apps together with Azure Automation to glue everything together.

Introduction

Let’s first kickoff by answering the most obvious question: why?

From my experience as IT consultant, I often see the aspect ‘security’ is missing from the agenda during designing and maintaining corporate applications. Especially when dealing with business-critical systems such as an ERP application (like D365FO) it is vitally important to mitigate any risk of a data breach. Furthermore, D365FO is exposed to the Internet because of its Cloud-native architecture, which brings us to the next question:

” Is a username-password authentication method still sufficient these days? “

My personal opinion?

No! I don’t think that’s sufficient anymore!

In other words, applying MFA for D365FO is a good idea. The most convenient solution is to implement Azure AD Conditional Access with which you can lock down the entire D365FO application to users which have MFA in-place.
However, implementing MFA can be a real challenge depending on the nature and size of the organization and IT infrastructure, especially when it comes to user adoption.

TLDR: You can already start strengthen the security borders around D365FO by first applying (or enforcing) MFA to the most powerful users: users owning System Administrator privileges. This tutorial will show you how you can automate this process to ensure all D365FO admins are using MFA at all times.

One little note of caution: this solution will enforce MFA on the specific set of users for any kind of Azure AD-based authentication, and is therefore not limited to D365FO.

Enough talking. Time to get your hands dirty 😀 .

The solution

Let’s first take a look at the overall design of the solution:

Technical automation design
Technical automation design

  1. The Logic App gets triggered by the recurring time schedule and connects to the OData services of the D365FO application, by authenticating (oAuth2) using the provided AAD service account.

  2. The Logic App pulls a list of every user (selecting UserID) association related to the role System administrator. This process consumes the data entity SecurityUserRoleAssociations.

  3. The Logic App retrieves the user details (such as Email) for each UserID which was retrieved in the previous step. This process consumes data entity SystemUsers.

  4. Within the same ‘for each UserID’ loop, the Logic App triggers an Azure Automation Runbook and passes the Email attribute to the triggered PowerShell script.

  5. The Azure Automation Runbook runs a PowerShell script which processes the input parameter (Email) and checks if the user exists within the given Azure AD directory (tenant). If it exists, it will enforce MFA. If it doesn’t exist, it will first assume it’s an external (guest) user which requires a format change (user#ext#@tenant). If it still can’t be found within the directory, it now assumes it’s a non-existing user and aborts the PowerShell script.

Requirements

You’ll need:

  • A running D365FO cloud environment (duh). You can create one here.
    Note: This tutorial won’t work for VHD-editions (on-prem hosted).

  • System Administrator privileges to the D365FO environment.

  • Global Administrator privileges on your Azure AD tenant.

  • Owner or Contributor privileges on a valid Azure subscription of any kind, as long as it’s able to deploy Azure Logic Apps and Automation resources.

  • Appropriate Azure AD licenses to enable MFA on the specific set of users


Step #1 – Create service account

In able to consume the OData services in D365FO we need to create a dedicated service account.

Example:
svc_d365fo_automation@mycompany.com

Depending on the configuration of your identity management, you might want to create the service account locally (in AD) to be synced to Azure AD. You can also create a cloud-only account by creating it from the Azure AD or Microsoft 365 admin portal. In both cases, remember to configure the password to not expire to prevent sudden connection failures. Also, I recommend to use a strong password and maintain the corporate identity management solution (if any).

Note: D365FO also supports authenticating using service principals in stead of user accounts. I will investigate how to configure Logic App to use this type of authentication since it’s more secure and improves management.


Step #2 – Add the service account to D365FO

Before we can let Azure Logic App talk to your D365FO instance we need to configure it’s access by adding and configuring the service account.

Start the D365FO client and go to the configuration of security roles by searching for security configuration in the top search bar. Find the default role Security administrator and click Duplicate to create a duplicate. We are going to modify this copy to our needs. Give it a descriptive name, for example: Security reader.

Note: If you’re deploying this solution to production, please respect the ‘least privileges’ principle which will require to investigate if a lower level security role is appropriate. For the convenience of this tutorial we’re just duplicating the default security administrator role and changing it to read-only.

Create a duplicate security role
Create a duplicate security role

Select your created role and perform the following actions:

  • Click Tables and make sure to configure each table permission to Read: Grant. All other actions (update, create, delete) must be set to Deny.
  • After changing all of the table permissions, switch to the Unpublished objects tab above, and publish your custom role.
Customize D365FO role
Customize D365FO role

You can now import the D365FO service account to the list of users, and assign your custom role. Example below:

Add service account to D365FO
Add service account to D365FO

Step #3 – Create Automation Runbook

Go to the Azure Portal and create an Automation Account. You can also leverage an existing Automation Account (resource) as long as it’s capable of running PowerShell scripts against your Azure AD tenant.
At first, validate the ‘Run as’ account settings to check if the Automation Account is working.

Then, make sure to have the module MSOnline added to the Automation Account. Go to Modules and find out if it’s listed. If it’s not, use the + Add a module button to add the MSOnline module.

Add the MSOnline module
Add the MSOnline module


Then, navigate to Runbooks and create a new runbook. Give it a descriptive name, for example: D365FO-Enforce-MFA-for-Admins. Make sure to select the runbook of type PowerShell.

Now, grab a copy of my script on GitHub (d365fo-enforce-mfa-admins.ps1) and paste it into the runbook editor. Example below:

Example script in Azure Automation
Example script in Azure Automation

You can modify the script to your needs. For example, edit line 8 to select a valid credential asset within your Automation Account. This credential could be configured with an Azure AD account with global admin privileges, since it needs to be able to configure MFA on users. However, confirm the specific account is not MFA-enforced since it will break any attempt to run this automation job. You can learn how to create a credential asset here.

Don’t forget to click Publish to enable your runbook. I highly recommend to test your runbook using the Test pane button. You can manually provide a value to the UPN parameter and verify script execution.

Note: If you’re deploying this solution to production, please respect the ‘least privileges’ principle which will require to investigate if a lower level of Azure AD role is sufficient for this specific automation job. For the convenience of this tutorial we’re just using a global admin account.



Step #4 – Create Logic App

Go to the Azure Portal and create a Logic App. Make sure to select the appropriate subscription and resource group. You can select the common trigger named Recurrence, or start with a blank Logic App. Set the recurrence frequency a value depending on your needs.
For example: once per hour.

Right below the trigger, you can add two steps to initialize the needed variables UserID and Email. Example below. As you can see you can also rename the caption of each step to keep it all tidy and clear.

Azure Logic App - Trigger and variables
Azure Logic App – Trigger and variables

Now add a step in which you select a connector for Dynamics 365 for Fin & Ops. Make sure to select the action named Lists items present in a table. Example below:

Azure Logic Apps - Create D365FO action
Azure Logic App – Create D365FO action

And configure the step as displayed below.

Instance:
select the D365FO instance after authenticating with the service account you’ve created in previous step.

Entity name:
SecurityUserRoleAssociations

Filter query:
SecurityRoleName eq ‘System administrator’ and UserId ne ‘axrunner’ and UserId ne ‘AdminPSUS’

Azure Logic App - Retrieve D365FO role assignments
Azure Logic App – Retrieve and query D365FO role assignments

Now add a for each control, and let it loop through the value (List of Items) field of the previous step.

Azure Logic App - Create loop
Azure Logic App – Create loop

Within the loop, add a step which again connects to Dynamics 365 Fin & Ops. This time you select the action Get a record.

Entity name:
SystemUsers

Object Id:
UserId (Dynamic content from the first D365FO connector)

Then, also within the loop, set the value for both initialized variables (UserID and UserEmail). You can use dynamic content ID and Email from the second D365FO connector.

Finally, still within the loop, add a step which creates a job for the Azure Automation Runbook you’ve created in the previous tutorial-step. (Step #3).
Example below:

Azure Logic App - Loop through role assignments
Azure Logic App – Loop through role assignments



Complete Logic App overview:

Testing

Depending on your Logic App trigger frequency things should start working now. The most convenient way to find out if your automation flow is working as expected is by checking the Azure Automation runbook logs. If you have enabled verbose logging, you should see some messages appear regarding to the UPN lookup and configuration processes of the MSOnline module.

Final thoughts

This end-2-end tutorial demonstrates the ease of use regarding to the integration of D365FO and (Azure) cloud automation tools.
I hope you’ve had fun reading and building my solution, and please let me know if you encountered any issues or challenges.

Code sources

Please feel free to use my code sources in able to build (and maybe customize) this solution yourself.

Github link:
https://github.com/CloudTotal/d365fo-automation