Pages

Monday, February 7, 2022

Attempting to use Get-AzureADServiceAppRoleAssignment to retrieve the Users and Groups of a Enterprise Application with a Service Principal instead returns API permissions of the associated App registration

A colleague of mine recently reached out to me to ask why my script from this post:

PowerShell script to assign users in an on-premise AD group to an Azure Enterprise Application's Users and Groups

http://terenceluk.blogspot.com/2022/02/powershell-script-to-assign-users-in-on.html

… did not work not work when a service principal was used as the Get-AzureADServiceAppRoleAssignment did not return the Users and Groups of the Enterprise Application that is passed to the cmdlet as the ObjectId. This brought me back to the time when I first worked with this cmdlet and spent hours over the weekend to figure out why this was the case so in hopes of saving others some grief, this post will explain the issue and resolution.

Let me begin by starting with the environment I’ll use for demonstrating this.

Environment

An Application registration named Enterprise-Apps-Permissions-PS is created in this tenant and an Enterprise Application (Service Principal) with the same name has been created from it.

Note that the Object ID of the Enterprise Application is: f984b219-756b-4454-bbf6-4290968836e4

image

If we wanted to retrieve the Enterprise Application’s Users and Groups via PowerShell, we can simply use the following cmdlets:

# Log into Azure AD PowerShell With Admin Account

Connect-AzureAD

# Retrieve Users and groups assignment

Get-AzureADServiceAppRoleAssignment -all $true -ObjectId "f984b219-756b-4454-bbf6-4290968836e4"

image

image

However, if you log in with a service principal using certificate thumbprint to authenticate, executing the same command gives you something different:

# Set variables to connect with service principal

$tenant = "84f4470b-3f1e-4xxxx-9f95-xxxxxxx24f"

$thumb = "D4F02xxxxxx60422BxxxxxxxE60Fxxxxxxxx"

$appId = "14b57135-6bf6-451f-aabb-faa3822dd5e8"

# Connect to Azure AD with service principal

Connect-AzureAD -TenantId $tenant -ApplicationId $AppId -CertificateThumbprint $thumb

# Obtain users and groups

Get-AzureADServiceAppRoleAssignment -all $true -ObjectId "f984b219-756b-4454-bbf6-4290968836e4"

image

Explanation

The reason why the output is different is because the Get-AzureADServiceAppRoleAssignment looks up and returns different configuration for a user and a service principal.

When logged in as a user and execute Get-AzureADServiceAppRoleAssignment: the Enterprise Application’s Users and Groups will be returned

When logged in as a service principal and execute Get-AzureADServiceAppRoleAssignment: the App registration’s API permissions is returned

Let’s review the output with some side-by-side screenshots.

In this environment the App registration named Enterprise-Apps-Permissions-PS has 3 Microsoft Graph permissions assigned to it, which is what Get-AzureADServiceAppRoleAssignment returns when executed under a service principal login. The screenshot has the top window showing the 3 Microsoft Graph permissions assigned to the App registration (Azure Active Directory > App registration > API permissions):

  • AccessReview.Read.All
  • AccessReview.ReadWrite.All
  • AccessReview.ReadWrite.Membership

… while the bottom window shows 1 user account assigned to the Enterprise Application linked to the App registration (Azure Active Directory > Enterprise Application > Users and Groups):

  • Terence Luk
image

If you use a regular user account to connect to Azure AD via Connect-AzureAD, then proceed use the cmdlet Get-AzureADServiceAppRoleAssignment (https://docs.microsoft.com/en-us/powershell/module/azuread/get-azureadserviceapproleassignment?view=azureadps-2.0) and execute the following:

Get-AzureADServiceAppRoleAssignment -all $true -ObjectId "f984b219-756b-4454-bbf6-4290968836e4"

You’ll receive the user and groups assigned to the Enterprise Application as shown in the following PowerShell output and screenshot:

image

image

However, if you connect into Azure AD with a Service Principal using certificate authentication as such:

$tenant = "84f4470b-3f1e-4xxxx-9f95-xxxxxxx24f"

$thumb = "D4F02xxxxxx60422BxxxxxxxE60Fxxxxxxxx"

$appId = "14b57135-6bf6-451f-aabb-faa3822dd5e8"

Connect-AzureAD -TenantId $tenant -ApplicationId $AppId -CertificateThumbprint $thumb

Then execute the same cmdlet:

Get-AzureADServiceAppRoleAssignment -all $true -ObjectId "f984b219-756b-4454-bbf6-4290968836e4"

You’ll receive the API Permissions assigned to the App registration as shown in the following PowerShell output and screenshot:

image

Solution

The Microsoft documentation isn’t very clear (or maybe I’m not reading them properly) but all the examples show Get-AzureADServiceAppRoleAssignment as the cmdlet to use to list the Enterprise Application’s Users and Groups. However, if you’re using a service principal because you’re trying to automate the execution of a script, you actually need to use this cmdlet:

Get-AzureADServiceAppRoleAssignedTo
https://docs.microsoft.com/en-us/powershell/module/azuread/get-azureadserviceapproleassignedto?view=azureadps-2.0

Note the follow output when executing as a service principal:

image

Hope this helps anyone who might run into this issue as it took quite a big chunk of my weekend when I was troubleshooting this.

Also note that the cmdlet New-AzureADUserAppRoleAssignment to assign a user or group to the Enterprise Application does not change when using a service principal.

Friday, February 4, 2022

Attempting to change an Azure App Service Plan from Premium to Standard tier fails with: "Failed to change to App Service plan: Cannot use the SKU Standard with File Change Audit for site..."

I don’t usually provide Azure operational support because of my current role but I still have a few clients who reaches out to me when they have issues in case I am able to provide a quick answer and I absolutely welcome it as it continues to give me exposure to day-to-day operational problems. A recent question I received a couple days ago was one that I’ve come across in the past and felt it is worth writing a quite blog post about it to help anyone who may come across this.

Problem

You’re attempting to change an App Service Plan from, say, the Premium Tier to Standard Tier but the process fails with the message:

Failed to change to App Service plan: 'Cannot use the SKU Standard with File Change Audit for site <AppServicePlan>. See https://aka.ms/supported-log-types for more information.’

image

A quick search on the internet will return the following blog post: https://nexxai.dev/cannot-use-the-sku-basic-with-file-change-audit-for-site/, which outlines a series of steps with PowerShell cmdlets to remediate the issue. I’ve used this procedure in the past and it has worked for me but the post was written back in January 2021 and I suggest the solution below which uses the portal.azure.com GUI should be attempted before using PowerShell.

Solution

1. Login into portal.azure.com and navigate to the App Service.

2. Click on Diagnostic settings and look for a rule set that refers to App Service Audit Logs, then click on the Edit setting link:

image

3. With the settings of the rule displayed, scroll down the list and look for AppServiceAuditLogs, deselect it, save the configuration and confirm that you want to delete the setting:

image

Once the configuration has been updated, proceed and try changing the App Service Plan.

Hope this helps anyone looking for the solution to this issue.

Wednesday, February 2, 2022

PowerShell script to assign users in an on-premise AD group to an Azure Enterprise Application's Users and Groups

Azure Active Directory administrators who have configured Enterprise Applications for Azure AD SSO would most likely have encountered the limitations of not being able to assign groups when granting access permissions due to not having Azure AD Premium P1 licenses. The cost of Azure AD Premium P1 licenses aren’t very expensive per user but the cost can quickly run up when there are thousands of users in an organization. One of the clients I worked with faced this issue when they decided to move their SaaS applications currently using their ADFS portal for SAML authentication to Azure AD. Their tenant was relatively new but they were keen to get a taste of what Azure AD could provide but quickly realized they would have to fork out additional money for Azure AD Premium P1 to assign groups to a newly created Enterprise Application. Their headcount was in the thousands and the only had Office 365 licenses rather than M365 licenses that included Azure AD Premium P1.

What I recommended as a stop gap (poor man’s solution) was to proceed and assign the users individually to the Enterprise Application as a stop gap until they can get approval to procure the licenses. I would be embarrassed to ask them to manually assign the permissions so I set out to find a script that can automate the process. A bit of lead me to Ruud’s script here: https://lazyadmin.nl/powershell/add-users-to-azure-ad-application-with-powershell/ which was very close to what I wanted, requiring a slight tweak as the client wanted to assign permissions to an on-premise AD group currently synchronized to Azure AD with AD Connect.

The following is what the modified script does:

  1. Connects to Azure AD
  2. Interactively prompts for the Enterprise Application name
  3. Interactively prompts for the on-premise AD group name
  4. Stores the Enterprise Application in a variable
  5. Obtains all the users currently assigned to the Enterprise Application
  6. Obtains all the users in the on-premise AD group
  7. Compares the list of users currently assigned to the Enterprise Application with the on-premise AD group and stores the difference in a variable
  8. If there are no users to be added, exit PowerShell script immediately
  9. Use a loop to assign the users to the Enterprise Application

I’ve included the following screenshots of the Enterprise Application:

image

Note the User and groups configuration to be populated:

image

Note that groups are not available for this tenant because Azure AD Premium P1 licenses are not available:

Groups are not available for assignment due to your Active Directory plan level. You can assign individual users to the application.

image

The script is pasted below and also available at my following GitHub repo: https://github.com/terenceluk/Azure/blob/main/PowerShell/EnterpriseApps-Permissions.ps1

If automation is required, this script can be used in a Runbook or Azure Function to automate the process.

image  

<#

Refer to the following documents for the source of where this script is derived from and the PowerShell cmdlets used:

Assign Users to Azure AD Application with PowerShell

https://lazyadmin.nl/powershell/add-users-to-azure-ad-application-with-powershell/

New-AzureADUserAppRoleAssignment

https://docs.microsoft.com/en-us/powershell/module/azuread/new-azureaduserapproleassignment?view=azureadps-2.0

Get-AzureADUser

https://docs.microsoft.com/en-us/powershell/module/azuread/get-azureaduser?view=azureadps-2.0

Get-AzureADGroupMember

https://docs.microsoft.com/en-us/powershell/module/azuread/get-azureadgroupmember?view=azureadps-2.0

#>

# Import AzureAD module with -UseWindowsPowerShell switch for PowerShell 7

# Import-Module AzureAD -UseWindowsPowerShell

# Connect to Azure AD

Connect-AzureAD

#Hardcode Enterprise Application name and on-premise AD group name

# $enterpriseAppName = "MetaCompliance User Provisioning"

# $onPremiseADgroup = "All_Staff"

# Prompt input for Enterprise Application name and on-premise AD group name

$enterpriseAppName = Read-Host "Please type the Enterprise Application Name"

$onPremiseADgroup = Read-Host "Please type the On-Premise AD Group Name"

# Get the service principal for the Enterprise Application you want to assign the user to

$servicePrincipal = Get-AzureADServicePrincipal -Filter "Displayname eq '$enterpriseAppName'"

## Use this cmdlet to list the roles available for this Enterprise App: Get-AzureadApplication -SearchString $enterpriseAppName | select Approles | Fl

## Use this cmdlet to list the specific role $servicePrincipal.Approles[0].id

# Get all users that are already assigned to the application

$existingUsers = Get-AzureADServiceAppRoleAssignment -all $true -ObjectId $servicePrincipal.Objectid | Select-Object -ExpandProperty PrincipalId

# Get all users from on-prem AD group

$allUsers = Get-AzureADGroup -Filter "DisplayName eq '$onPremiseADgroup'" -All $true | Get-AzureADGroupMember -All $true | Select-Object displayname,objectid

# Compare list of users from the on-premise AD group and list of users already assigned default permissions to the Enterprise Application

$newUsers = $allUsers | Where-Object { $_.ObjectId -notin $existingUsers }

# Check to see if there are any new users to add and if there isn't, terminate the script now rather than attempting the loop

if ($newUsers.count -eq 0) {

Exit

}

ForEach ($user in $newUsers) {

Try {

## Note that the Id parameter specifies app because this application has two defined roles

# If multiple roles does not exist then use: -Id ([Guid]::Empty) instead of -Id $servicePrincipal.Approles[0].id

# Use this cmdlet to display the available roles: Get-AzureadApplication -SearchString $enterpriseAppName | select Approles | Fl

New-AzureADUserAppRoleAssignment -ObjectId $user.ObjectId -PrincipalId $user.ObjectId -ResourceId $servicePrincipal.ObjectId -Id $servicePrincipal.Approles[0].id -ErrorAction Stop

[PSCustomObject]@{

UserPrincipalName = $user.displayname

AppliciationAssigned = $true

}

}

catch {

[PSCustomObject]@{

UserPrincipalName = $user.displayname

AppliciationAssigned = $false

}

}

}

Connect-AzureAd fails in PowerShell version 7 with: "Could not load type 'System.Security.Cryptography.SHA256Cng'..."

Problem

You attempt to use the cmdlet Connect-AzureAd (after Import-Module AzureAd) to connect to Azure:

Connect-AzureAds

image

… but quickly notice that it fails with the following error:

PS C:\Git\Azure\Azure> Connect-AzureAD

Connect-AzureAD: One or more errors occurred. (Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.): Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

Connect-AzureAD: One or more errors occurred. (Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.)

Connect-AzureAD: Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

Connect-AzureAD: One or more errors occurred. (Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.): Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

image

This happens in a PowerShell version 7 terminal as well as Visual Studio Code’s PowerShell 7 terminal:

Version: 1.63.2 (user setup)

Commit: 899d46d82c4c95423fb7e10e68eba52050e30ba3

Date: 2021-12-15T09:40:02.816Z

Electron: 13.5.2

Chromium: 91.0.4472.164

Node.js: 14.16.0

V8: 9.1.269.39-electron.0

OS: Windows_NT x64 10.0.19043

image

The PowerShell 7 version is displayed below:

PS C:\Git\Azure\Azure> $PSVersionTable

Name Value

---- -----

PSVersion 7.2.1

PSEdition Core

GitCommitId 7.2.1

OS Microsoft Windows 10.0.19043

Platform Win32NT

PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}

PSRemotingProtocolVersion 2.3

SerializationVersion 1.1.0.1

WSManStackVersion 3.0

image

This is not a problem in PowerShell version 5:

PS C:\> $PSVersionTable

Name Value

---- -----

PSVersion 5.1.19041.1320

PSEdition Desktop

PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}

BuildVersion 10.0.19041.1320

CLRVersion 4.0.30319.42000

WSManStackVersion 3.0

PSRemotingProtocolVersion 2.3

SerializationVersion 1.1.0.1

image

Solution

To get around this issue, use the -UseWindowsPowerShell switch when importing the AzureAD module as such:

PS C:\Git\Azure\Azure> Import-Module AzureAD -UseWindowsPowerShell

WARNING: Module AzureAD is loaded in Windows PowerShell using WinPSCompatSession remoting session; please note that all input and output of commands from this module will be deserialized objects. If you want to load this module into PowerShell please use 'Import-Module -SkipEditionCheck' syntax.

image

Connect-AzureAD should now complete:

image

Securing Azure AD with Duo 2FA

Duo has been one of the most common MFA solutions I’ve worked with over the past 5 years and most clients who have this as their MFA solution for on-premise services such as ADFS, tend to ask whether they can also use it for Azure AD. The short answer is yes but there the requirement of having Conditional Access (available with Azure AD Premium P1) within Azure means an additional cost would be required to replace Azure MFA with the solution (https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/concept-fundamentals-mfa-get-started). Another consideration is that certain risk detection features of Azure Identity Protection (https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/concept-identity-protection-risks) will not be available. With that said, the purpose of this post is to provide a quick walkthrough of the setup process for using Duo as the MFA for Azure AD portal.azure.com and Office 365 authentication. The official Duo documentation can be found here: https://duo.com/docs/azure-ca

Begin by logging into the Duo administration portal: https://admin.duosecurity.com/, navigate to Applications and click on Protect and Application to register Azure as an application:

image

Search for Azure, select Microsoft Azure Active Directory and click on the Protect button:

image

Click on the Authorize button to have Duo provide the Azure tenant sign-in prompt:

image

Sign into the Azure tenant with an account with global administrator permissions:

image

Authorize the permissions request:

image

Decide on whether to activate the Universal Prompt for Microsoft Azure AD:

image

Copy the custom control code snippet into notepad as we’ll require it to configure Azure AD:

image

Scroll down and review the settings of the Azure AD application:

image

Locate the Username normalization setting and change the radio button from None to Simple. The reason why this setting is important is because failure to configuring this will cause Duo to create multiple accounts for the same user depending on the username used. For example, it may create two accounts for the logins:

  1. tluk
  2. tluk@contoso.com
  3. contoso\tluk

image

image

Proceed to save the configuration and you should now see the application created:

image

Login into https://portal.azure.com, navigate to Azure Active Directory and click on Security:

image

Select Conditional Access:

image

Click on Custom controls (Preview) and then New custom control:

image

Delete the existing content in the customized controls box:

image

Paste the JSON snippet from Duo and click on Create:

image

Note the new custom control named RequireDuoMFA listed:

image

Navigate to Policies and click on New policy:

Note that if the New custom control button is greyed out then that means you do not have Azure AD Premium P1 licenses and therefore unable to use Conditional Access.

image

Select Create new policy:

image

Provide a name for the policy:

image

Click on Specified users include under Users or workload identities and configure the users or groups that you want the policy to be applied to:

image

Click on No cloud apps, actions, or authentication contexts selected under Cloud apps or actions, select Select apps and configure the applications you want this policy to apply to. For this example, we’ll include Office 365 and Microsoft Azure Management:

image

Note that Azure reminds you to not lock yourself out as Microsoft Azure Management affects portal.azure.com. Microsoft provides guidance on having and managing emergency accounts in the following document: https://docs.microsoft.com/en-us/azure/active-directory/roles/security-emergency-access

image

Select 0 controls selected under Access controls, select Grant access, enable RequireDuoMfa, and enable Require all the selected controls:

Note that if you do not see RequireDuoMfa then that means you skipped the custom control creation.

image

With the settings configured, you can choose to have Enable policy set as Report-only, which will only report expected behavior in the logs:

image

Or configured as On, which would put the policy in effect:

image

For this example, we will have the policy configured as On:

image

Proceed to test login and you should now see the following behavior:

image

image

image

Hope this provides an idea of what the process of configuring and using Duo as MFA looks like.