Using the Azure Run As Account in Azure Automation to Connect to Azure AD with a Service Principal

If you are using Azure Automation and working with Runbooks for automating against your Azure subscription, you can create an Azure Run As Account for authenticating and logging in to your subscription. The Azure Run As Account is configured in your Automation Account, and will do the following:

  • Creates an Azure AD application with a self-signed certificate, creates a service principal account for the application in Azure AD, and assigns the Contributor role for the account in your current subscription.
  • Creates an Automation certificate asset named AzureRunAsCertificate in the specified Automation account. The certificate asset holds the certificate private key that’s used by the Azure AD application.
  • Creates an Automation connection asset named AzureRunAsConnection in the specified Automation account. The connection asset holds the applicationId, tenantId, subscriptionId, and certificate thumbprint.

You can read more about setting up Azure Run As Accounts here, including how to do a more customized setup with PowerShell: https://docs.microsoft.com/en-us/azure/automation/automation-create-runas-account.

Something worth noting is that this Azure Run As Account will by default have the Contributor role to your entire subscription, so it would make sense to look into changing RBAC settings for the subcription or resource groups if you want to limit that. Also, all users that have access to the Automation Account will also have the opprotunity to use this Azure Run As Account.

Having said that, the Azure Run As Account is a great way to authenticate securely with certificates and a service principal name without needing to store a username and password in a credential object.

So I thought, wouldn’t it be great if we could use this same Azure Run As Account to log in to your Azure AD tenant for the possibility to run Azure AD PowerShell commands? The reason I thought of this is because of this article showing how to authenticate with Azure AD v2 PowerShell and Service Principal: https://docs.microsoft.com/en-us/powershell/azure/active-directory/signing-in-service-principal?view=azureadps-2.0. In this short blog post will show you how to do this.

Getting the Azure Run As Account details

First, look into your Automation Account and Account Settings to find any Run as accounts:

image

Click on the Azure Run As Account to see the details (or to create one if you haven’t before). Take a note of the Service Principal Object Id, we will use that later:

image

Creating a Runbook that Authenticates with Service Principal to Azure AD

Now, let’s create a PowerShell runbook using the Azure Run As Account for connecting to Azure AD.

First, I set the connection name  “AzureRunAsConnection”, and then save that as a variable for holding my service principal details using the Get-AutomationConnection cmdlet.

Then, logging in to Azure AD is done with specifiying TenantId, ApplicationId and CertificateThumbprint parameters, as shown below:

image

This will log in my service principal to Azure AD and I’m ready to run some commands, for example getting some organization details for the tenant, or counting different types of user objects:

image

Running this runbook will for example show me this output for my tenant. This shows that I successfully authenticated with the Azure Run As Account service principal:

image

Here is a link to a Gist where I have included the above PowerShell runbook script:


<#
.SYNOPSIS
This Azure Automation runbook connects to Azure AD with a Service Principal and Connect-AzureAD.
.DESCRIPTION
This Azure Automation runbook connects to Azure AD with a Service Principal and Connect-AzureAD.
It uses an Azure Run As Account connection that must be created before.
You have to import the AzureAD module from the Automation module gallery, if it's not already there.
AUTHOR: Jan Vidar Elven [MVP]
LASTEDIT: July 11th, 2018
#>
# Get Azure Run As Connection Name
$connectionName = "AzureRunAsConnection"
# Get the Service Principal connection details for the Connection name
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
# Logging in to Azure AD with Service Principal
"Logging in to Azure AD…"
Connect-AzureAD -TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
"List Tenant Org Details:"
Get-AzureADTenantDetail | Select DisplayName, Street, PostalCode, City, CountryLetterCode
"Member Account Synced Count:"
(Get-AzureADUser -All $true -Filter "userType eq 'Member' and accountEnabled eq true" | Where-Object {$_.DirSyncEnabled -eq $true}).Count
"Disabled Users Count:"
(Get-AzureADUser -All $true -Filter 'accountEnabled eq false').Count
"Guest User Count:"
(Get-AzureADUser -All $true -Filter "userType eq 'Guest'").Count
"Cloud Only Account Count:"
(Get-AzureADUser -All $true -Filter "userType eq 'Member'" | Where-Object {$_.userPrincipalName -like "*onmicrosoft.com"}).Count

Role Permissions for the Service Principal

Depending on what kind of automation you want to do against Azure AD, especially if you want to write data, you will have to add the Service Principal to an Azure AD Role. Here is a couple of examples, using the object id for the service principal I told you to note earlier from the Azure Run As Account:

# Get the associated Service Principal for the Azure Run As Account
$runAsServicePrincipal = Get-AzureADServicePrincipal -ObjectId ""

# Add the Service Principal to the Directory Readers Role
Add-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | where-object {$_.DisplayName -eq "Directory Readers"}).Objectid -RefObjectId $runAsServicePrincipal.ObjectId

# Add the Service Principal to the User Administrator Role
Add-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | where-object {$_.DisplayName -eq "User Account Administrator"}).Objectid -RefObjectId $aaAadUser.ObjectId

# Add the Service Principal to the Global Administrator Role
Add-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | where-object {$_.DisplayName -eq "Company Administrator"}).Objectid -RefObjectId $runAsServicePrincipal.ObjectId

That concludes this short blog post, hope it has been helpful! Thanks for reading and remember to share if it was useful Smile

Azure MFA Report Dashboard in Azure Portal–The Good, The Bad and The Ugly

If you are working with EMS and implementing Azure AD, Intune, MDM, MAM, Information Protection and more, you can build yourself some great dashboards in the Azure Portal using tiles and pin blades to your customized dashboard. This is an example from my own workplace:

image

Often when I work with projects implementing Identity & Access, Conditional Access and Azure MFA, I wish I could have a dashboard to report on MFA registration, and be able to pin that to my EMS dashboard as shown above.

It might be in the future that Azure MFA registrations and methods will be native in the portal, but for now this information have to be retreived in another way. In this blog post I will show you how you can set up a solution for showing this information. I will use the Markdown Tile from the gallery for displaying this information, and in the end it will look like this:

I referred in the title of this blog post to the good, the bad and the ugly, and by that I mean the process of setting this up, because it starts easy enough in the beginning but it will get more “ugly” in the end 😉

The Good – Setting up the Markdown Tile

I will use the Markdown Tile for the content in my customized dashboard in my Azure Portal. The first part is easy to set up, just click Edit and find the Markdown tile from the gallery, as shown below:

image

Drag the tile to a place you want it on your dashboard, and the Edit the title, subtitle and content as prompted:

image

There is a sample content provided, other than that you can write your own markdown. I will not get into details on markdown format here, there is a lot of good guides for learning the format, for example this: https://guides.github.com/features/mastering-markdown/. I will however provide you with a sample for reporting MFA registrations and default methods. This is how I set up my markdown tile:

image

And here is a link to my github repository where you can get the complete MFAReport.md file sample:

https://github.com/skillriver/AzureMFADashboard/blob/master/MFAReport.md

Now we need to fill that markdown tile with some real Azure AD MFA report data to report on.

The Bad – PowerShell Script for getting MFA registration and methods to Markdown

So the “bad” news is that we are reliant on running some Azure AD PowerShell commands for getting user details for MFA registration and methods. For now we are also reliant on the Azure AD v1 PowerShell (MSOnline) Module, as the new v2 AzureAD Module does not yet have any methods to get MFA authentication data. We cannot use the Microsoft Graph API either to get MFA user data, but I expect that to change in the future.

So lets look at the script I use, and after authenticating and connecting to Azure AD in my tenant with Connect-MSOLService, I will run the following commands to get details from each user where there has been configured one or more StrongAuthenticationMethods, and Group on those methods and save the results to a hash table. The results are stored in the $authMethodsRegistered object variable. Similarly I run the command once more, filtering on only showing the methods that are set to default for each user, and save to the $authMethodsDefault variable.

# Connect to MSOnline PowerShell (Azure AD v1)
Connect-MsolService

# Get MFA Methods Registered as Hash Table
$authMethodsRegistered = Get-MsolUser -All | Where-Object {$_.StrongAuthenticationMethods -ne $null} | Select-Object -Property UserPrincipalName -ExpandProperty StrongAuthenticationMethods `
| Group-Object MethodType -AsHashTable -AsString

# Get Default MFA Methods as Hash Table
$authMethodsDefault = Get-MsolUser -All | Where-Object {$_.StrongAuthenticationMethods -ne $null} | Select-Object -Property UserPrincipalName -ExpandProperty StrongAuthenticationMethods `
| Where-Object {$_.IsDefault -eq $true} | Group-Object MethodType -AsHashTable -AsString

# Create a Custom Object for MFA Data
$authMethodsData = New-Object PSObject
$authMethodsData | Add-Member -MemberType NoteProperty -Name AuthPhoneRegistered -Value $authMethodsRegistered.TwoWayVoiceMobile.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name AuthPhoneAppRegistered -Value $authMethodsRegistered.PhoneAppOTP.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name OfficePhoneRegistered -Value $authMethodsRegistered.TwoWayVoiceOffice.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name AlternatePhoneRegistered -Value $authMethodsRegistered.TwoWayVoiceAlternateMobile.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name OneWaySMSDefault –Value $authMethodsDefault.OneWaySMS.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name PhoneAppNotificationDefault –Value $authMethodsDefault.PhoneAppNotification.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name PhoneAppOTPDefault –Value $authMethodsDefault.PhoneAppOTP.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name TwoWayVoiceMobileDefault –Value $authMethodsDefault.TwoWayVoiceMobile.Count
$authMethodsData | Add-Member -MemberType NoteProperty -Name TwoWayVoiceOfficeDefault –Value $authMethodsDefault.TwoWayVoiceOffice.Count

# Write to Markdown file
"## MFA Authentication Methods`n" | Set-Content .\MFAReport.md -Force -Encoding UTF8
"### Registered`n" | Add-Content .\MFAReport.md -Encoding UTF8
"The following methods has been registered by users:`n" | Add-Content .\MFAReport.md -Encoding UTF8
"| Method | Count |" | Add-Content .\MFAReport.md -Encoding UTF8
"|:-----------|:-----------|" | Add-Content .\MFAReport.md -Encoding UTF8
"| Authentication Phone | " + [string]$authMethodsData.AuthPhoneRegistered + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"| Phone App | " + [string]$authMethodsData.AuthPhoneAppRegistered + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"| Alternate Phone | " + [string]$authMethodsData.AlternatePhoneRegistered + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"| Office Phone | " + [string]$authMethodsData.OfficePhoneRegistered + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"" | Add-Content .\MFAReport.md -Encoding UTF8
"### Default Method" | Add-Content .\MFAReport.md -Encoding UTF8
"The following methods has been configured as default by users:" | Add-Content .\MFAReport.md -Encoding UTF8
"" | Add-Content .\MFAReport.md -Encoding UTF8
"| Method | Count |" | Add-Content .\MFAReport.md -Encoding UTF8
"|:-----------|:-----------|" | Add-Content .\MFAReport.md -Encoding UTF8
"| OneWay SMS | " + [string]$authMethodsData.OneWaySMSDefault + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"| Phone App Notification | " + [string]$authMethodsData.PhoneAppNotificationDefault + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"| Phone App OTP | " + [string]$authMethodsData.PhoneAppOTPDefault + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"| TwoWay Voice Mobile | " + [string]$authMethodsData.TwoWayVoiceMobileDefault + " |" | Add-Content .\MFAReport.md -Encoding UTF8
"| TwoWay Voice Office Phone | " + [string]$authMethodsData.TwoWayVoiceOfficeDefault + " |`n" | Add-Content .\MFAReport.md -Encoding UTF8
"Last reported " + [string](Get-Date) | Add-Content .\MFAReport.md -Encoding UTF8

"" | Add-Content .\MFAReport.md

The complete PowerShell script can be found at my GitHub repository here:

https://github.com/skillriver/AzureMFADashboard/blob/master/MFAStrongAuthenticationUserReport.ps1

So now we have a script where we can get MFA authentication details for each user and create a markdown file that we can use in the tile in the Azure Portal custom dashboard. But it is all a manual process now, and it works fine for an ad hoc update. If we want to automate however, we have to get into the “ugly” stuff 😉

The Ugly – Automating Markdown creation and update Dashboard

This part requires multiple steps. First we need to schedule and run the PowerShell commands from above. Then we need to find a way to update the customized dashboard tile with the updated markdown file. To summary, this is what we need now:

  • Schedule the PowerShell script to run automatically. We can use Azure Automation for that.
  • Programmatically change the markdown tile in the customized dashboard. We can use Azure Resource Manager Rest API for that.

Lets get into the Azure Automation solution first. To run a PowerShell script I will need to create a Runbook, and in that Runbook I need to authenticate to Azure AD. I can define a Credential Asset with a username and password for a global admin user, but I like to use the least privilege possible, and besides that all my global admins are either protected by Azure AD PIM and/or MFA, so that won’t work. I prefer to use a service principal whereever possible, but after testing extensively with Connect-MSOLService that is not supported either.

So I tested with a dedicated Azure AD credential account, first by only adding the user to the Directory Readers role. I was able to list all users with Get-MSOLUser, but not any StrongAuthentication info. Neither did it work with Security Readers. In the end I added the user account to User Administrator role in Azure AD, and I was successful getting StrongAuthentication methods.

So, in my automation accont I will add or reuse my credentials:

image

Next, I will create a new PowerShell script based Runbook, basically I will use the PowerShell script from earlier in the blog, but with a couple of added parameter and getting the credential using the Get-PSAutomationCredential method. This is how it looks, you will get link to the complete script later:

image

And after testing, I can see that I successfully will get the MFAReport.md content (added a Get-Content .\MFAReport.md at the end to display the output):

image

Now that we have a solution for running the PowerShell script and generating the markdown file, the next part is how to update that data in the custom dashboard. And for that we need to look into programatically changing Azure Portal dashboards. There is a good resource and starting point for that in this article: https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-dashboards-create-programmatically.

First you need to share the custom dashboard, remember to include the markdown tile we set up in the first part of this blog post. At the top in the portal dashboard, select the Share button:

image

By sharing the dashboard will published as an Azure resource. Specify a name, select the subscription and either use the default dashboard resource group or select an existing one:

image

Go to Resource Explorer in the Portal:

image

Navigate to Subscriptions, Resource Groups, and find the resource group and resource containing the custom dashboard. From there you will be able to see the JSON definition of the dashboard and specifically the markdown tile containing the content we want to update:

image

So for next process now we need to copy this complete JSON definition containing all your tiles including the markdown tile. Locally on your computer, create a .json file in your favorite JSON editor, I use Visual Studio Code for this, and paste in the content. I have named my file DeploymentTemplateMFAReport.json.

Now we need to change this template to be ready for deployment, and for that we need to add or change a couple of things. First, in the start of the JSON file, add schema and versioning, and parameters, variables and resources section like I have shown below in line 1-17:

image

I have chosen to use 3 parameters, the markdown content itself, and name of the dashboard and the title of the dashboard.

Next, find the tile for the markdown content, and change the content value to the value of the parameter, like I have done at line 113 here:

image

And last, at the end of the json template, add and change the following settings, I have used my parameters for the dashboard name and the dashboard title here in the lines 401-411:

image

My deployment template for the customized dashboard is now completely general and can be used in every environment. In fact you are welcome to borrow and use my template from above her, I have included it in my github repository:

https://github.com/skillriver/AzureMFADashboard/blob/master/DeploymentTemplateMFAReport.json

Working locally in my Visual Studio Code editor, I can now test the deployment using Azure PowerShell, as shown below and described with these simple steps:

  1. Connect to Azure Resource Manager and select the Subscription
  2. Specify a variable for the Resource Group you want to deploy to
  3. The MFAreport.md file (which we created earlier) need some converting to JSON format, I’m removing all espace characters and any uneeded special characters
  4. Specify variable names your environment for name and title for the dashboard
  5. Deploy the custom dashboard to the resource group

image

However, now that we can test the deployment, I want to schedule a deployment using Azure Automation, and I will continue on my previous runbook from before. But first we need to set up some connections for authenticating to Azure and some variables.

I Azure Automation we can create an Azure Run As Account, this will also create a service principal. If you navigate to your Automation Account in the Azure Portal, and go to the section called Run as accounts, you can create an Azure Run As Account automatically, as I have done here:

image

If I look more closely at this generated Run As Account, I can see details for Azure AD App Registration, Service Principal, Certificate and more. This account will also automatically be assigned Contributor role for my Azure Subscription. If you want more control over Azure Run As Accounts, you can create your own as described in the following article: https://docs.microsoft.com/en-us/azure/automation/automation-create-runas-account

image

I will use this Azure Run As account in my environment to deploy the dashboard resource, I’ll just need to make sure the account has contributor access to the resource group. Next I will set ut a few variables under the Variables section for my Automation Account, I will use these variables when I deploy the resource:

image

Now we are ready to finally put together the complete Runbook and test it. You will have the complete link later in the blog post, but I will share some screenshots first:

After I’ve connected with Connect-MSOLService I’m creating a variable for the markdown content, so I’ve changed from earlier when I saved a .md file temporarily, now I just adding lines using the newline special character (`n):

image

The next part is for logging in to Azure (using the Azure Run As Account mentioned above), and then getting my variables ready for deployment:

image

Then I convert the markdown content to Json format, and removing any escape characters that I don’t need:

image

And then deploy the dashboard resource with parameters for markdown content and dashboard name & title. Note that I’m using my deployment template as a source from my github repository via the TemplateUri property:

image

You can use any TemplateUri you want, for example from a more private source like a storage account blob etc.

Testing the Runbook gives the following output, which shows it was successful:

image

When I now go and refresh the dasboard in the portal, I can see that the markdown tile has been updated:

image

That leaves me with just publishing and scheduling the runbook:

image

When creating a new schedule specify a name and recurrence:

image

Link the schedule to the runbook and any needed parameters, I have to specify my credential that are allowed to Connect-MSOLService:

image

That concludes this lengthy blog post. The script will now run regularly and update my custom markdown tile with MFA report data.

Here is the link to the PowerShell script used in my Azure Automation runbook, enjoy your MFA Reporting!

https://github.com/skillriver/AzureMFADashboard/blob/master/MFAStrongAuthenticationUserReportAutomation.ps1

 

Getting started with Azure AD PIM PowerShell Module

This is a short blog post showing how you can get started and some examples of using the PIM PowerShell Module for Azure AD Privileged Identity Management.

You can read more about Azure AD Privileged Identity Management here: https://docs.microsoft.com/en-us/azure/active-directory/active-directory-privileged-identity-management-configure, or by just using the following short URL: https://aka.ms/AzureADPIM!

Installing the Azure AD PIM PowerShell Module

Since there are no PIM related commands in the AzureAD or AzureADPreview PowerShell Modules, we will have to install a separate module for PIM. You can find this module at the PowerShell Gallery here: https://www.powershellgallery.com/packages/Microsoft.Azure.ActiveDirectory.PIM.PSModule

To install the module just run the following command in an elevated PowerShell session:

Install-Module Microsoft.Azure.ActiveDirectory.PIM.PSModule
image

After installing you can list the available commands in the PIM module:

Get-Command -Module Microsoft.Azure.ActiveDirectory.PIM.PSModule
image

Here is a short explanation of the available commands:

  • Connect-PimService. Prompts you to log on with an Azure AD Account that might have any PIM roles assigned. You can optionally specify a username, tenantname or credential object as parameters. Especially tenantname would be useful if you are a guest user with roles assigned in another tenant.
  • Show-PimServiceConnection. This will show the active PimService session details you have, after connecting with Connect-PimService.
  • Get-PrivilegedRoleAssignment. This would list any permanent or eligible role assignments the user you connected with using Connect-PimService has.
  • Enable-PrivilegedRoleAssignment. This command will enable a specified role assignments. It is required to specify which role either by RoleId or by a RoleAssignment variable. It is also required to specify a Duration for activation. Optional parameters includes Reason, TicketNumber, TicketSystem and StartTimeUtc.
  • Disable-PrivilegedRoleAssignment. If you previously have activated one or more roles with Enable-PrivilegedRoleAssignement, you can preemptively deactivate these roles again before the duration expires. You must specify a RoleId or RoleAssignment variable.
  • Disconnect-PimService. Disconnects any previous sessions to PimService.

Examples of Azure AD PIM Commands

In the following I will show some examples of using the Azure AD PIM Module.

Connect-PimService

In the following I’m connecting with a specified username, if it is required to use Azure MFA for this user I will be prompted for that as well:

Connect-PimService –UserName <username>
image
image

After authenticating, PIM service connection details are returned, here slightly masked:

image

The above returned is exactly the same as would be returned by running the command:

Show-PimServiceConnection

Get-PrivilegedRoleAssignment

This command will list any role assignments, permanent or eligible your user might have. Here is a couple of examples for outputs for two different admin users. The first user is eligible for Security Administrator and Privileged Role Administrator, and permanent for Global Administrator:

image

The second admin user is eligible for Exchange Administrator and Global Administrator:

image

If I want to assign a variable to a role assignment, I can do it like the following command:

$roleAssignment = Get-PrivilegedRoleAssignment | Where {$_.RoleName -eq "Privileged Role Administrator"}

I now have a role assignment variable I can use in the following commands.

Enable-PrivilegedRoleAssignment

To enable one of my roles, I need to specify a duration (PS! keep inside the allowed role settings for max duration!), and specify which role either by RoleId or RoleAssignment variable. Optional parameters like Reason etc can also be specified.

Here is a working example:

Enable-PrivilegedRoleAssignment –Duration 1 –RoleAssignment $roleAssignment –Reason “Add crmadmin to CRM Administrators”

After running the command, if successful it will return as a submitted request for activating role membership.

image

By running Get-PrivilegedRoleAssignment again, we can now see that the role of “Privileged Role Administrator” is indeed activated (elevated), and with a ExpirationTime (UTC time):

image

PS! If you have required MFA on activation for the role, one of two things will happen:

  1. If the user already has verified the identity with Azure MFA when authenticating with Connect-PimService, the user will not be asked again. This is the same experience as by using the Azure Portal for activating roles.
  2. If the user hasn’t verified with Azure MFA, the user will be prompted when activating the role, similar to this example:
    image

Disable-PrivilegedRoleAssignment

Any roles you have activated will automatically deactivate after the duration specified has passed. However, if you are finished doing administrative tasks with your role, you can deactivate the role manually.

To deactivate an active assignment, run the following command specifying a RoleId or RoleAssignment variable:

Disable-PrivilegedRoleAssignment –RoleAssignment $roleAssignment
image

Disconnect-PimService

To end your connection to Azure AD PIM Service, run the following command:

Disconnect-PimService

After running that command you can also see that there are no role assignments to list anymore.

image

Hope these commands and examples have been helpful, enjoy working with Azure AD PIM!

How to configure Conditional Access for Azure AD PIM

Azure AD Privileged Identity Management is a really great security feature for controlling those Azure AD and Azure Subscription administrator roles. By implementing Azure AD PIM you can let users with admin roles elevate themselves when they need to, using just in time (JIT) and eligible roles instead of permanent admin roles. You can even implement approval workflows and audit trails, so if you haven’t looked into it you should really take a look!

With Azure AD PIM you can require Azure MFA when activating admin roles, but outside that you cannot set conditions and access control scenarios like you can do with Azure AD Conditional Access.

But now recently there is a new option in public preview for assignments to users and groups for Conditional Access policies, you can assign the CA policy to directory roles!

image

So I was wondering how this would work together with Azure AD Privileged Identity Management, for example in the following scenario:

I have an Exchange Administrator that from time to time performs Exchange Online admin tasks, and have configured this admin user with Azure AD PIM and eligible for Exchange Administrator Role among others:

image

Lets say that I only want this user to perfom Exchange Administrator tasks from a Compliant Device. Even though the Azure AD PIM role is protected by MFA at activation, making the user secure and trusted, I really want the device he is using to be secure and compliant with any management profiles I have defined using Intune MDM. Especially when he is doing admin stuff in our Exchange Online tenant or even running some Exchange Online PowerShell commands.

Lets set up this scenario.

Creating Azure AD Conditional Access Policy for Directory Role

The first thing I set up is the CA policy for my specific Directory Role in this scenario. I specify a name and then select the Directory role of Exchange administrator as shown below:

image

Next for Cloud apps I select Exchange Online:

image

For Access controls I select to require the device to marked as compliant:

image

After that I enable the policy and save. We are now ready to test the user experience.

Testing Azure AD PIM Role Activation and Conditional Access

So now we can test the scenario. Remember that the idea is that the CA policy only will kick in when the user has activated his Azure AD PIM role assignment as Exchange Administrator.

PS! If this user also has a Exchange Online license and mailbox, the same CA policy will apply and require the device to be compliant as long as the Exchange Administrator role is active. That could pose some not intended side effects, requiring the devices that access Exchange Online for normal mailbox access to be compliant as well, but as long as the Exchange Online Admin isn’t available as a Cloud app in Conditional Access we have to do it this way.

With my admin user, I first go to http://aka.ms/myroles, which will redirect me to my roles defined in Azure AD PIM. Lets sign in first:

image

And here is my eligible roles:

image

I select the action link to activate my Exchange Administrator role, and then to verify my identity with Azure MFA:

image

After verifying I can specify a reason or adjust the activation duration:

image

After that I’m activated and has an access valid for the set period of time:

image

Now, let’s go to to the Exchange Online Admin portal: https://outlook.office365.com/ecp. After signing in, if I’m not already signed in, I will get this message:

image

The details will tell me that the access rules require a compliant device:

image

We could also check using Exchange Online PowerShell module, and I get the same message:

image

Note that this message only works with the Connect-EXOPSSession that use Modern Authentication. The “old” way of using remote PowerShell and credential object to Exchange Online use basic (legacy) authentication so we cannot control that information flow, but the admin user will be denied there as well:

ExoPS

To conclude this blog post, I have shown that by combining the new preview feature of Directory Roles assningments for Azure AD Conditional Access, and Azure AD Privileged Identity Management, we can implement more complex scenarios for conditions and access rules for using those directory roles. In my example I used compliant device, but you could also use any other of the conditions and access controls available.

Configure Azure AD Authentication for Project Honolulu version 1803

Just a few days ago a new version of Project Honolulu, technical preview 1830, was released for Windows Server Insiders, https://blogs.windows.com/windowsexperience/2018/03/13/announcing-project-honolulu-technical-preview-1803-and-rsat-insider-preview-for-windows-10/.

One of the major updates to that version was the support for changing access control from local group/Active Directory to Azure AD Authentication. Configuring Azure AD Authentication will provide the ability to pre-authenticate users with their Azure AD credentials, as well as restrict access to selected users or even integrate with Azure AD Conditional Access.

In this blog post I will provide some steps, examples and screenshots for how I did that configuration in my own environment.

This scenario builds on the previous installation I have made with Windows Server 1709 (Server Core) and Project Honolulu, see blog article for how my setup is: https://gotoguy.blog/2018/02/13/installing-windows-server-version-1709-on-intel-nuc-skull-canyon-and-configure-hyper-v-for-remote-management/

Update existing version of Project Honolulu to version 1803

Since I had an existing installation of Project Honolulu on this server ELVEN-NUC-HV1.nuc.group, I downloaded the 1803 installation file, connected to the server and ran the following command to silently install and update the existing installation:

msiexec /i HonoluluTechnicalPreview1803.msi /qn /L*v log1803.txt SME_PORT=443 SSL_CERTIFICATE_OPTION=generate

After that I navigated to the https://elven-nuc-hv1.nuc.group url from my client machine, and verified that I could sign in and see that the Project Honolulu website was updated.

image

I also note the certificate warning I receive because my client doesn’t trust the self generated certificate the gateway server installation provided. This will be a problem when using Azure AD Authentication, so in the next step I will make sure the client trusts that.

Export and trust self signed certificate

First, start a PowerShell session on the Honolulu Gateway Server, and then run the command:

Get-ChildItem –Path cert:\LocalMachine\My | FL

This will return any certificates in the machine store. As I have previously installed and generated a self signed certificate for Project Honolulu gateway server, I see 2 certificates now, and can note the thumbprint for the most recent one:

image

Next I will run the following commands for getting the certificate and exporting it to a .cer file:

$cert = (Get-ChildItem –Path cert:\LocalMachine\my\<THUMBPRINT>)
Export-Certificate –Cert $cert –FilePath <path>\<filename>.cer.

In my enviroment I ran the following:

imageAfter that, transfer the .cer file to the client computer(s) you want to be able to connect to the Project Honolulu website, and run the following commands to get and import the .cer certificate into trusted root store:

$cert = (Get-ChildItem –Path <path>\<filename>.cer)
$cert | Import-Certificate –CertStoreLocation cert:\LocalMachine\Root

In my enviroment this looked like this (from an elevated PowerShell window):

image

I took the extra step of verifying that the self signed certificate indeed was imported into trusted root store:

image

Change Access Control to Azure AD

Now I am ready to change access control in Project Honolulu. Click on the Settings cogwheel, and under Settings click Access.

My current settings are set to Active Directory or Local groups, so I click on Change access control:

image

I then change to Azure Active Directory (AAD), and see the prerequisites for connecting the gateway to Azure:

image

I downloaded the New-AadApp.ps1 script, note that this script requires the modules AzureRM.Resources and AzureAD to be installed at the machine where you run the script. If you don’t have them installed, you can install these using Install-Module, as shown in this example:

image

I chose to run this script on my client computer (not on my server core gateway computer), and with the following command:

.\New-AadApp1803.1.ps1 –GatewayEndpoint https://elven-nuc-hv1.nuc.group

(PS! I didn’t have the AzureAD module installed, but the AzureADPreview module instead. A simple change in the Requires section of the script fixed that;)

Running the script prompted me to specify a Global Administrator account for the tenant I wanted to register the Azure AD App in, and after sucessfully authenticating I got confirmation. Note the AAD Application name and other Id’s:

image

Back at the Access Control settings, refresh the browser, note the changed instructions show in the dialog below, and then Save. This will restart the gateway service.

image

After refreshing the browser again, you will be prompted by the following consent for permissions (provided that you already had an active logged on session, or else you will prompted to log in to the tenant you registered the app in):

image

After successfully authenticating and accepting, I’m logged into the Project Honolulu website. Under Settings and Azure, I can verify that I’m logged in and sign out again if needed.

image

Logging on with other users from the tenant

Remember by default all members of the Azure AD tenant will have user access to the Honolulu gateway service. That includes any B2B Guest Users!

Each user logging in need to first time consent to permissions, in the following screenshots I have logged on with a normal user account and then a B2B guest account:

imageimage

Only local administrators on the gateway machine will have administrator access to the Honolulu gateway.

Under Access Settings you can click on a link to go directly to the Azure AD App that got registered when you ran the script earlier:

image

Clicking on that link and logging in with a Global Administrator, you will get to your SME-<name> app. From there you can go to users and groups, and all users that have logged in until now will be listed. By default they will not have any role assigned, but you can change role between Gateway Administrator or Gateway User as I have done below:

image

If you want to restrict which users or groups that are allowed to log into the Project Honolulu site with their Azure AD Credentials, you can go to Properties and then enable the setting for require user assignment:

image

After enabling this setting users that aren’t added to the list of users or groups either directly or via group membership will not be allowed to log on to Project Honolulu.

Summary and next steps

In this blog post I have shown a first look for enabling Azure AD Authentication for Project Honolulu version 1803 technical preview.

The next step is to look into configuring Azure AD Conditional Access for this application, that will come in a later update to this blog article, stay tuned!

A couple of issues is also on my list:

  • I’m prompted to log on with local admin credentials in addition to the Azure AD credentials
  • When I follow the link from Access Control settings I’m able to find the Azure AD App, but I cannot see it by just browsing the Enterprise Applications list. Based on the documentation I this should have work. This means for now I cannot add that App to any Conditional Access policies as it is not browseable.
  • The .\New-AadApp1803.1.ps1 script cannot be run on the Windows Server 1709 core version, as there is no GUI and I get iframe errors, it could be that this is related to the issue above, as I ran the script on my client instead.

I will also look into these issues in an update to this blog post. Please comment below if you are seeing similar issues or have any other experiences. Thanks for reading 🙂

Install & Register Azure AD Application Proxy Connector on Windows Server 1709

I recently installed the new release of Windows Server, version 1709 on my Intel NUC, you can read about that here.

I have installed Project Honolulu for remote server management on that server, but as this Intel NUC is usually located on my home lab network, I want to be able to publish and access the Honolulu website using Azure AD Application Proxy.

As the Windows Server 1709 is Server Core, I need to install and configure the Azure AD Application Proxy Connector silently, and these are the steps I did to do that.

First, you need to download the Application Proxy connector install file, and transfer it to the server. You can access the connector download from Application Proxy section in your Azure AD portal:

image

After that, run the following command to do a quiet install of the connector, skipping registration interactively:

AADApplicationProxyConnectorInstaller.exe REGISTERCONNECTOR=”false” /q

image

Next we need to register the Application Proxy connector to Azure AD, and for that we need to run some PowerShell commands. There are two ways this can be done, with a Credential Object, or using an Offline Token. Using Credential is simplest, but has the drawback that you cannot use that method if your Global Administrator account is protected with Azure MFA. Lets look at both methods below.

Using Credential Object:

On the Server you want to register the Azure AD App Proxy Connector, start a PowerShell session and run the following commands for setting the Global Administrator user name and password, and then create a Credential Object.

image

After that, run the following commands to run the RegisterConnector.ps1 script for register the connector using Credential object as authentication:

image

You can copy the PowerShell commands used above using the Gist linked at the end of this blog post.

Using Offline Token:

If you can’t or don’t want to use a credential object, you have to use a offline token. The following commands will get an access token for the authorization context needed for Application Proxy Connector Registration.

Getting the Token can be run from any client, and then transferred to the server, but you will need to have the Azure Active Directory Authentication Library (ADAL) installed at the machine you are running the PowerShell commands. The easiest way to get the needed libraries installed is to Install the AzureAD PowerShell Module.

The following commands locates the AzureAD (or AzureADPreview) Module, and then finds the ADAL Helper Library: Microsoft.IdentityModel.Clients.ActiveDirectory.dll, and adds that as a Type to the PowerShell session:

image

Next, run these commands to define some constants, these values are the same for all tenants:

image

Now we can run these commands for setting the authentication context and then prompt user for AuthN:

image

Running the above commands will result in an authentication prompt, this is where you would specify your Global Administrator account, and if MFA enabled this will also work:

image

After authenticating we can check the result and save the token and tenantId in variables as shown below:

image

Next, copy the contents of the $token and $tenantId to the Windows Server 1709, and run the following command to create a secure string from the token:

image

And then run the RegisterConnector.ps1 script with AuthenticationMode as Token and using the secure token and tenant id as parameter values as shown below:

image

PS! According to the official documentation, there are no description or examples for the mandatory parameter “Feature”, but I found that it accepts the value “ApplicationProxy” as used above.

You can copy the above PowerShell commands from the Gist linked at the end of this blog post.


# Register Azure AD App Proxy Connector
# PS! Using Credential Object cannot be used with MFA enabled administrator accounts, use offline token
$User = "<username of global administrator>"
$PlainPassword = '<password>'
$SecurePassword = $PlainPassword | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $User, $SecurePassword
Set-Location "C:\Program Files\Microsoft AAD App Proxy Connector"
.\RegisterConnector.ps1 -modulePath "C:\Program Files\Microsoft AAD App Proxy Connector\Modules\" `
-moduleName "AppProxyPSModule" -Authenticationmode Credentials -Usercredentials $cred


# Get Offline Token for Azure AD App Proxy Register Connector
# Then Register Connector with that Token
# Locate AzureAD/AzureADPreview PowerShell Module
# Change Name of Module to AzureAD or AzureADPreview after what you have installed
$AADPoshPath = (Get-InstalledModule -Name AzureADPreview).InstalledLocation
# Set Location for ADAL Helper Library
$ADALPath = $(Get-ChildItem -Path $($AADPoshPath) -Filter Microsoft.IdentityModel.Clients.ActiveDirectory.dll -Recurse ).FullName | `
Select-Object -Last 1
# Add ADAL Helper Library
Add-Type -Path $ADALPath
#region constants
# The AAD authentication endpoint uri
[uri]$AadAuthenticationEndpoint = "https://login.microsoftonline.com/common/oauth2/token?api-version=1.0/&quot;
# The application ID of the connector in AAD
[string]$ConnectorAppId = "55747057-9b5d-4bd4-b387-abf52a8bd489"
# The reply address of the connector application in AAD
[uri]$ConnectorRedirectAddress = "urn:ietf:wg:oauth:2.0:oob"
# The AppIdUri of the registration service in AAD
[uri]$RegistrationServiceAppIdUri = "https://proxy.cloudwebappproxy.net/registerapp&quot;
#endregion
#region GetAuthenticationToken
# Set AuthN context
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" `
-ArgumentList $AadAuthenticationEndpoint
# Build platform parameters
$promptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always
$platformParam = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList $promptBehavior
# Do AuthN and get token
$authResult = $authContext.AcquireTokenAsync($RegistrationServiceAppIdUri.AbsoluteUri, `
$ConnectorAppId, `
$ConnectorRedirectAddress, `
$platformParam).Result
# Check AuthN result
If (($authResult) -and ($authResult.AccessToken) -and ($authResult.TenantId) ) {
$token = $authResult.AccessToken
$tenantId = $authResult.TenantId
}
Else {
Write-Output "Authentication result, token or tenant id returned are null"
}
#endregion
# Create a secure string from token
$secureToken = $token | ConvertTo-SecureString -AsPlainText -Force
# Register connector with secure token and tenant guid
Set-Location "C:\Program Files\Microsoft AAD App Proxy Connector"
.\RegisterConnector.ps1 -modulePath "C:\Program Files\Microsoft AAD App Proxy Connector\Modules\" `
-moduleName "AppProxyPSModule" -Authenticationmode Token -Token $SecureToken -TenantId $tenantId `
-Feature ApplicationProxy

So to recap, after installing the Application Proxy Connector silently on the Windows Server 1709, and then registering the connector, I can now verify in the Azure AD Portal that the connector is available for use. I can see it has a status of Active, from my home IP address, and I have already placed it in a Connector Group.

image

I’m now ready to publish Azure AD Proxy Apps using this connector, and in my next blogpost I will publish the Project Honolulu management website using this!

Here is the Gist source for the above linked PowerShell commands:


# Register Azure AD App Proxy Connector
# PS! Using Credential Object cannot be used with MFA enabled administrator accounts, use offline token
$User = "<username of global administrator>"
$PlainPassword = '<password>'
$SecurePassword = $PlainPassword | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $User, $SecurePassword
Set-Location "C:\Program Files\Microsoft AAD App Proxy Connector"
.\RegisterConnector.ps1 -modulePath "C:\Program Files\Microsoft AAD App Proxy Connector\Modules\" `
-moduleName "AppProxyPSModule" -Authenticationmode Credentials -Usercredentials $cred


# Get Offline Token for Azure AD App Proxy Register Connector
# Then Register Connector with that Token
# Locate AzureAD/AzureADPreview PowerShell Module
# Change Name of Module to AzureAD or AzureADPreview after what you have installed
$AADPoshPath = (Get-InstalledModule -Name AzureADPreview).InstalledLocation
# Set Location for ADAL Helper Library
$ADALPath = $(Get-ChildItem -Path $($AADPoshPath) -Filter Microsoft.IdentityModel.Clients.ActiveDirectory.dll -Recurse ).FullName | `
Select-Object -Last 1
# Add ADAL Helper Library
Add-Type -Path $ADALPath
#region constants
# The AAD authentication endpoint uri
[uri]$AadAuthenticationEndpoint = "https://login.microsoftonline.com/common/oauth2/token?api-version=1.0/&quot;
# The application ID of the connector in AAD
[string]$ConnectorAppId = "55747057-9b5d-4bd4-b387-abf52a8bd489"
# The reply address of the connector application in AAD
[uri]$ConnectorRedirectAddress = "urn:ietf:wg:oauth:2.0:oob"
# The AppIdUri of the registration service in AAD
[uri]$RegistrationServiceAppIdUri = "https://proxy.cloudwebappproxy.net/registerapp&quot;
#endregion
#region GetAuthenticationToken
# Set AuthN context
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" `
-ArgumentList $AadAuthenticationEndpoint
# Build platform parameters
$promptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always
$platformParam = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList $promptBehavior
# Do AuthN and get token
$authResult = $authContext.AcquireTokenAsync($RegistrationServiceAppIdUri.AbsoluteUri, `
$ConnectorAppId, `
$ConnectorRedirectAddress, `
$platformParam).Result
# Check AuthN result
If (($authResult) -and ($authResult.AccessToken) -and ($authResult.TenantId) ) {
$token = $authResult.AccessToken
$tenantId = $authResult.TenantId
}
Else {
Write-Output "Authentication result, token or tenant id returned are null"
}
#endregion
# Create a secure string from token
$secureToken = $token | ConvertTo-SecureString -AsPlainText -Force
# Register connector with secure token and tenant guid
Set-Location "C:\Program Files\Microsoft AAD App Proxy Connector"
.\RegisterConnector.ps1 -modulePath "C:\Program Files\Microsoft AAD App Proxy Connector\Modules\" `
-moduleName "AppProxyPSModule" -Authenticationmode Token -Token $SecureToken -TenantId $tenantId `
-Feature ApplicationProxy

Installing Windows Server, version 1709, on Intel NUC Skull Canyon and Configure Hyper-V for Remote Management

A while back I wrote a blog post on Installing Hyper-V Server 2016 on my Intel NUC Skull Canyon: https://gotoguy.blog/2016/10/17/installing-microsoft-hyper-v-server-2016-on-intel-nuc-skull-canyon/

You can read more on the hardware setup on that referred blog post, but in this blog post I will revisit the steps on how to repeat this setup on the new Semi-Annual Channel release of Windows Server, version 1709. You can read more on this new server version here: https://docs.microsoft.com/en-us/windows-server/get-started/get-started-with-1709

Setup Windows Server, version 1709

I needed to add a bootable volume for which I could install Windows Server, version 1709, and prepared an USB stick for which I would boot up the installation media for Windows Server 1709. The following steps should help you set up a bootable USB stick for Windows Server, version 1709:

  1. Download the .iso image for the Windows Server, version 1709, and mount it to a drive letter (in my example this will be f:)
  2. Make sure the USB stick is inserted and note the drive letter (in my case this is E:)
  3. Launch an elevated Command Prompt or PowerShell window (Run as Administrator)
  4. Run command: Diskpart (this will start DiskPart tool in interactive mode)
  5. Run command: list disk (from the list, note the disk number of the USB drive)
  6. Run command: select disk 1 (use the number from above, double check before next step which is to clean)
  7. Run command: clean (careful, this will wipe out the usb drive completely, so make sure you have selected the correct disk number)
  8. Run command: create partition primary
  9. Run command: select partition 1
  10. Run command: active (this will mark the selected partition as active)
  11. Run command: format fs=ntfs quick label=”1709″ (wait after for formatting to complete)
  12. Run command: exit
  13. You have now exited diskpart, change to the mounted iso drive (f:), and the run command: cd boot
  14. Run command (change drive letters if different in your environment): F:\boot>bootsect /nt60 e:
  15. You will now have updated NTFS filesystem bootcode on the USB drive, and the last step is to copy all Windows Server, version 1709 files:
    xcopy f:\* e: /H /F /E
  16. This could take a while, especially copying the large install.wim file. After copying is finished, you are ready to boot the USB stick on the Intel NUC Skull Canyon.
  17. At the Intel NUC boot screen, hit F10 to enter boot menu, and select the boot option for UEFI USB drive. After this the Windows Server, 1709 server install should begin.

Install the Windows Server, 1709 following the installation process, and since 1709 is only available in Server Core, you will have to use Command Prompt and “SConfig” tool for initially configuring the server as shown in the next section.

Configuring the Windows Server, 1709 version for Remote Management and Hyper-V Server

After installation and changing the Administrator account password before first time logon, the Server Core configuration was ready for to start configure the server.

I first did these changes:

  • Renamed the Computer Name, in this case I renamed the Computer to ELVEN-NUC-HV1
  • Renamed the Workgroup name to NUCGROUP (optional)
  • Enabled Remote Desktop (All clients, less secure). This setting can be reversed after I have configured all the Remote Management scenarios I need to.
  • Under Configure Remote Management, I also Enabled the Server to Response to Ping, that could be useful when setting up the Server.
  • I also downloaded and installed any pending updates.

2018-02-13_00-29-31

My next step was to add the Hyper-V Server Role and configure for Remote Management via Hyper-V Manager.

Add and Configure the Hyper-V Host for Remote Management

In the Command Prompt of the server, type powershell.exe to start a PowerShell session.

Then run the following command to install the Hyper-V Role:

Add-WindowsFeature -Name Hyper-V,RSAT-Hyper-V-Tools

2018-02-13_22-36-56

After a reboot we are ready to configure the server for remote management

I want to use my Windows 10 machine and Hyper-V Manager to remote manage this Hyper-V Host, as described in this link: https://msdn.microsoft.com/en-us/virtualization/hyperv_on_windows/user_guide/remote_host_management.

As this will be my home/portable lab, the Hyper-V Server will not be in a domain, so I need to use the instructions at the end of the above article for Manage a Hyper-V host outside your domain (or with no domain).

This is the steps I went through to set that up:

Configure FQDN for the Hyper-V Host

I want to set the FQDN for the Hyper-V Host so that:

Computername = ELVEN-NUC-HV1
Desired Primary DNS Suffix = nuc.group

In PowerShell, I first add the FQDN of the computer with the Netdom command:

netdom computername $env:computername /Add:ELVEN-NUC-HV1.nuc.group

Second, I add the FQDN of the computer to primary:

netdom computername $env:computername /MakePrimary:ELVEN-NUC-HV1.nuc.group

Restart the server before the next step.

Add the FQDN and IP address to the Hosts file

To be able to access the Hyper-V Server from my Windows 10 client, I add the IP address (I have created a DHCP reservation for it on my Router) and the FQDN in my Hosts file in C:\Windows\System32\Drivers\Etc directory.

image

Configure Remoting on the Hyper-V Server

On the Hyper-V host to be managed, start PowerShell.exe, and run the following as an administrator:

Enable-PSRemoting

Enable-PSRemoting will create the necessary firewall rules for private network zones.

To make sure that the connection are in the private network zone, I check with the command:

Get-NetConnectionProfile

In my case, as this server is in a workgroup, I must specifically change the network zone from public to private:

Set-NetConnectionProfile -InterfaceIndex 4 -NetworkCategory Private

When checking after that, the connection is now Private:

2018-02-13_23-04-11

After that I run the following command:

Enable-WSManCredSSP -Role server

Configure the Client

On my Windows 10 client machine, I run the following commands in a PowerShell (Run As Administrator) session:

# Start the WinRM Service
Start-Service WinRm

# Add the Hyper-V Server as Trusted Host
Set-Item WSMan:\localhost\Client\TrustedHosts -Value “elven-nuc-hv1.nuc.group”

# Add the Hyper-V Server to the list of servers to delegate credentials to
Enable-WSManCredSSP -Role client -DelegateComputer “elven-nuc-hv1.nuc.group”

If you later when adding the Server to Hyper-V Manager, get this error message, you need to follow these instructions on the client via GPedit.msc:

Configure the following group policy: * Computer Configuration | Administrative Templates | System | Credentials Delegation | Allow delegating fresh credentials with NTLM-only server authentication *

Click Enable and add wsman/elven-nuc-hv1.nuc.group

image

 

Add the Server to Hyper-V Manager

Finally, we should be ready to add the Server to Hyper-V Manager:

  1. Select Connect to Server, specify name and Connect as your Admin user:image
  2. And now I can successfully configure the Hyper-V Server:
    2018-02-13_23-09-11

I can now configure Hyper-V Settings and add VMs to the Server via Hyper-V Manager from my Windows 10 client to the Windows Server, version 1709!

Manage the Windows Server 1709 with Project Honolulu

Another way to remote manage the Windows Server, version 1709 is to use the browser based server management tool “Project Honolulu”, https://docs.microsoft.com/en-us/windows-server/manage/honolulu/Honolulu.

Project Honololu is supported in Gateway Mode on the 1709 server version, and to install you first have to download the Honolulu installer, and then run a command like this:

msiexec /i <HonoluluInstallerName>.msi /qn /L*v log.txt SME_PORT=<port> SSL_CERTIFICATE_OPTION=generate

In my example I ran the command like this:

msiexec /i HonoluluTechnicalPreview1712-05002.msi /qn /L*v log.txt SME_PORT=443 SSL_CERTIFICATE_OPTION=generate

After installing Project Honolulu I can now also remote manage via browser from my client:

2018-02-13_23-26-59

Shutdown and Deallocate an Azure VM using Managed Service Identity and Instance Metadata Service

The purpose of this blog post is to show how you can run a PowerShell script on an Azure VM that will shutdown and deallocate the actual VM the script is run on.

First, kudos to Marcel Meurer (Azure MVP), that originated the idea of how to run a PowerShell script that will shut down and deallocate the VM from inside itself, this is a good read: https://www.sepago.de/blog/2018/01/16/deallocate-an-azure-vm-from-itself.

Marcels blog learnt me of something I havent used before, Azure Instance Metadata Service, where I can get information on my current VM instance. I wanted to combine this with using Managed Service Identity (MSI), and actually let the VM authenticate to itself for running the shut down command. The shut down command will be using the Azure REST API.

First, let us set up the requirements and permissions to get this to work.

Configure Managed Service Identity

Managed Service Identity is feature that as of January 2018 is in Public Preview, and by using MSI for Azure Virtual Machines I can authenticate to Azure Resource Manager API without handling credentials in the code. You can read more on the specifics here: https://docs.microsoft.com/en-us/azure/active-directory/msi-tutorial-windows-vm-access-arm.

First, we need to set up the Managed Service Identiy the VMs in question. This is done under the VM configuration, by enabling Managed service identity as shown below:

image

After saving the configuration, wait for the Managed service identity to be successfully created. This will create a service principal in Azure AD, and for VMs this will have the same name as the virtual machine name.

Now we need to give that service principal access to its own VM. Under the VMs Access Control (IAM) node, select to add a permission for the service principal as shown under. I have given the role of Virtual Machine Contributor, which means that the MSI will be able to write to and perform operations on the VM like shutdown, restart and more:

image

So for each VM we want to use this PowerShell script, we will need to do the same 2 operations, enable MSI and add service principal permission to the VM:

image

PowerShell script for Shutdown and Deallocate using MSI

The following script will when run on the Azure VM do the following steps: (full script follows below as the images are small)

  1. Read instance metadata and save subscription, resource group and vm name info:image
  2. Authorize itself to Managed Service Identity:image
  3. Send an Azure Resource Manager REST API POST command for shutdown and deallocate:imageThe REST API call for shutting down a VM uses method POST and the following URI format: https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines/{vm}/deallocate?api-version={apiVersion}(https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-stop-deallocate)

When this script is run on a VM the following output will display that the REST operation was successful, and shortly after the server goes down and deallocates as excpected.

image

To summarize, this blog post showed how we can use Managed Service Identity together with Azure Instance Metadata Service, to let the VM manage itself. This example showed how to shut down and deallocate, but you can use the REST API for other operations like restart, get info, update the VM and so on. Best of all with using MSI, is that we don’t have to take care of application id’s, secret keys and more, and having those exposed in the script which can be a security issue.

The complete PowerShell script is shown below:


# This script will shutdown the Azure VM it's running on
# Requirements: Azure Managed Service Identity (MSI) configured on the VMs in question.
# Permissions: The MSI service principal for the VM needs to be added as Virtual Machine Contributor for it's own VM
# Kudos: This script is inspired from Marcel Meurer's script for shutting down VM from itself: https://www.sepago.de/blog/2018/01/16/deallocate-an-azure-vm-from-itself
# Read VM details from Azure VM Instance Metadata
$md = Invoke-RestMethod -Headers @{"Metadata"="true"} -URI http://169.254.169.254/metadata/instance?api-version=2017-08-01
# Save variables from metadata
$subscriptionId = $md.compute.subscriptionId
$resourceGroupName = $md.compute.resourceGroupName
$vmName = $md.compute.name
# Next, using the MSI we will get an access token for the service principal
$response = Invoke-WebRequest -Uri http://localhost:50342/oauth2/token -Method GET -Body @{resource="https://management.azure.com/&quot;} `
-Headers @{Metadata="true"}
# Save the response and access token
$content = $response.Content | ConvertFrom-Json
$ArmToken = $content.access_token
# Using Azure REST API to shutdown and deallocate VM, authenticating with access token from MSI
Invoke-WebRequest -Uri `
https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Compute/virtualMachines/$vmName/deallocate?api-version=2016-04-30-preview `
-Method POST -ContentType "application/json" `
-Headers @{ Authorization ="Bearer $ArmToken"}

Access Microsoft Graph API using Custom Connector in PowerApps and Flows

Microsoft PowerApps and Flows are great and simple to get started and use solutions for creating Apps and for how to “Code with No Code”. And the Microsoft Graph API is a great source of information for your Organizational data, including Users, Devices, Apps and Data. The Microsoft Graph has one common endpoint for which you can access and use all the information you want.

The purpose of this blog post is to show how to set up the requirements for accessing Microsoft Graph from PowerApps and Microsoft Flow.

image

I will show how you create an App Registration in your Azure AD tenant with the required settings and permissions for Microsoft Graph, and how you set up a custom connector in PowerApps and how to connect to that using PowerApps and Flows. We will create a simple App and see how you can share that App in your Organization. Let’s get started!

App Registration

If you want to access the Microsoft Graph you will need an App Registration, for which you can authenticate against the Graph API. There are two options available, depending on whether you want to authenticate only with Azure AD Work or School accounts, or if you also want to authenticate with Microsoft Accounts. The first option is to use the Azure AD portal (https://aad.portal.azure.com), the second option is to use the Application Registration Portal (https://apps.dev.microsoft.com). I will use the Azure AD Portal.

First, login as a Global Administrator to your Azure AD Portal, or have your IT admin perform the following steps for you. Under Azure Active Directory, create a new App Registration:

image

Provide a name like below, select Web app / API type, and then type any URL you want. It doesn’t have to be an accessible URL, as long as it is a valid format:

image

After the App Registration is created, you can open it and note the application id, which we will require later:

image

Next, under Settings, click Required Permissions. Here we will add the permissions we need for accessing the Microsoft Graph.

image

Click Add and then select Microsoft Graph from the list over available APIs:

image

Next, you will need to specify the permissions this App will have to access the Microsoft Graph. Note that there are two types of permissions:

  • Application Permissions. These permissions are for Apps that run without a user logged in, like a service or deamon.
  • Delegated Permissions. These permissions are for running apps in the context of the logged on user. The users effective permission will be a least privilege of these permissions you give the App, and the users actual permission in your organization.

image

In my scenario with using PowerApps and Flows, I will only use Delegated Permissions. Lets start with the most basic permission, and add that to the Microsoft Graph API:

image

Note that there is a column for Require Admin which either contains a Yes or No. If you select a permission that require Admin grant, the Global Administrator must click on the Grant Permissions. In our example now I don’t have to do this, but remember that any time you update the permissions for your app registration that require Admin, you must click on this Grant Permissions button.

image

Next, under Settings for the App Registration, go to Keys. We will now create a secret key to be used together with the application id when authenticating. Type in a description and select a period of expiry, and then click save. Your key will be displayed only once, so make sure you copy it and note it down for later use:

image

We are now ready to head over to PowerApps and create our Custom Connector that will use this App Registration.

Create a Custom Connector in PowerApps

Go to https://web.powerapps.com and log on as your normal user account, you don’t have to be an admin to do this.

Under Custom connectors, select Create Custom Connector, specify a name and continue:

image

On the General page, type a description and optionally change the icon or background color:

image

Under scheme select HTTPS, and under host, specify graph.microsoft.com. The base URL is “/”.

image

Click Continue. Under Security select OAuth 2.0 as authentication type, and then for Identity Provider select Azure Active Directory. For Client id, copy the Application id from the Application Registration we did in the previous section in the Azure AD portal:

image

Scroll down and for Client secret, paste in the secret key you generated from the app registration. Let login URL and tenant ID be as suggested and the type https://graph.microsoft.com as Resource URL:

image

Scroll further down. Scope is optional, and take a note of that Redirect URL will be generated after we save the connector.

image

Click continue to the Definition section. We will get back to this later, so for now just click Create connector:

image

The custom connector will be created, and we can go back and get the redirect URL:

image

Now you need to get back to the application registration in Azure AD and add that Redirect URL to the list of Reply URLs like this:

image

Save that and we are ready for the next step. To summarize, we have now created an App Registration in Azure AD with these 4 steps, as well as prepared a Custom Connector i PowerApps.

image

Now we need to prepare some queries we are going to run in Microsoft Graph.

Prepare queries in Graph Explorer

When working with Microsoft Graph, Graph Explorer is your best friend and resource. You can access the Graph Explorer via the https://graph.microsoft.com website, or even with this simple url:

http://aka.ms/ge

At the Graph Explorer page you can run from a  great collection of samples, and you can either run with a sample account, or log in using your own Work/School or Microsoft account.

image

I will log in as my normal user, and if this is the first time you log in to Graph Explorer you are prompted to consent to permissions needed by the Graph Explorer. From the picture below I have just Run Query for getting my profile:

image

With Microsoft Graph, you can also select just the attributes you want to see, so if I run the following query: https://graph.microsoft.com/v1.0/me/?$select=displayName,givenName,surname,userPrincipalName,aboutMe

I will get this response for my user:

image

From the response I see that my “aboutMe” attribute is empty. Let’s try to put a value into that. This is where the Microsoft Graph documentation is useful. If I look at the API reference for update user, https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_update, I see that I will have to use a PATCH method and specify a Request Body which contains the attributes and values I want to update. So for example I will specify my request like this, and then Run Query:

image

I see that the status is success with a status code of 204, and if I check my profile again with the GET query from earlier, I will se that the aboutMe value now has been set: (It’s true by the way, I love working with Microsoft Graph!)

image

Now that we have seen how we can run queries for reading and writing to Microsoft Graph, lets try to implement that in a PowerApp, but first we need to create some Operations for our Custom Connector.

Create Custom Connector Operations

Back in PowerApps and under Custom connectors, I select edit for my connector:

image

I then go to Definition, and since there are no Actions created previously, I will add that now by clicking New Action. This will present me with the following form. I will specify a name, description and an operation id:

image

Scroll down to Request, this is where we will provide the details for our query. The best way to do this is to select to Import from sample. I specify the Method to be GET, and then the query like this, which is the same query I ran in the Graph Explorer earlier:

image

I don’t need to specify any Header or Body for this query, so I just press Import. Now my action looks like this:

image

Scroll down to the Response section, and then click on the default response. Click on Import from sample, and this time you paste in the response body from the previous Graph Explorer query:

image

This response will help the custom connector operation so that we can get the right output values mapped in our PowerApp later. Select Import.

The response now looks like this:

image

We can also validate that the response looks ok:

image

Click on Update connector to save this operation.

Next I want to create another action for updating the aboutMe attribute in my profile. I’ll create a new Action:

image

Under Request I will select Import from sample again, this time specifying PATCH as operation verb, the request URL is https://graph.microsoft.com/v1.0/me, and also add the Headers and Body as shown below. These samples are exactly the same as what I tested in Graph Explorer:

image

As this operation does not return a specific response object, I will let the default response be as it is, and will save my settings by Updating the connector.

Testing the custom connector

In my custom connector I can now move to the Test section:

image

The first thing I need to do is to create a New connection:

image

By logging in with my user I will be presented to consent to the permissions of the App, these are the delegated permissions we configured when registering the App in Azure AD (the reason for the double consent is that in addition to the Microsoft Graph delegated permission, there was also an Active Directory Graph permission for sign in and read profile) :

image

After creating the connection, go back to the custom connector and to the test section again. This time we have a valid connection to choose, and can test the action we want. I will test the GetMyProfile action first:

image

By using the $select parameter I can specify any attribute I want to get, and when clicking Test operation I get a successful response like this:

image

Now, let’s test the second action:

image

I specify the Content-Type to be application/json, and then an updated value for the aboutMe in the profile, and then Test operation:

image

The response is also successful.

Now that the operations are tested and verified, we know that the Custom connector can successfully access the Microsoft Graph, and we are finally ready for creating a PowerApp and testing it all out!

Set up the PowerApp and use the Connector

I will create a PowerApp that will get my profile details, and also be able to update the about me attribute. I will not get into great detail on the general instructions to set up the PowerApp, but the high level steps are:

  • Create a new PowerApp using the blank template and phone layout
  • Add some custom colors and an image (optional)
  • Add some labels and text boxes for getting some chosen profile attributes
  • One of the text boxes is for the “about me” value
  • Create a couple of buttons for getting profile data and to update the “about me” value

So after playing around a little bit I have this PowerApp ready:

image

So lets bring some action into the PowerApp. First, go to the View menu, and then Data Sources. From the list of data sources you should be able to see a connection with your username and the PowerApps Microsoft Graph connector (as I am using PowerApps for other data sources as well, I have a few more):

image

After I add the connection I now have a data source for this Connector:

image

Now I can refer to this data source in my PowerApp, for example in my buttons. I will for the first button add an action for getting my profile data, and for the second button add an action for writing back to “about me” in my profile.

For reading data from my profile, I will add the following action to the OnSelect event:

image

First a little explanation of this action:

  • UpdateContext is a function that would hold data into a variable i specify.
  • Calling the PowerAppsMicrosoftGraph.GetMyProfile operation would return a response I want to save to that variable.
  • Using arguments for $select I can specify which attributes I want to return as a response.
  • So by using UpdateContext and specifying that I save the response back to the MyProfile variable I can use that variable in other controls.

The complete operation is: UpdateContext({MyProfile: PowerAppsMicrosoftGraph.GetMyProfile({‘$select’:”DisplayName,givenName,surname,aboutMe”})})

Then for each textbox control I can get the value from the MyProfile variable, like this:

image

And l would do the same for the other text boxes, using MyProfile.givenName, MyProfile.surname and MyProfile.aboutMe.

Next, for updating the attribute “about me”, I will add the following action to the OnSelect event:

image

In this case I call the PowerAppsMicrosoftGraph.UpdateAboutMeProfile operation, specifying the arguments for content-type and using the text specified in the txtAboutMe.Text property:

PowerAppsMicrosoftGraph.UpdateAbouteMeProfile({‘Content-Type’:”application/json”,aboutMe:txtAboutMe.Text})

Now you can Save, give the PowerApp a Name and a chosen Icon, and then Publish the PowerApp. You are now ready to run the PowerApp!

Running the PowerApp

The PowerApp can be started in different ways, via the mobile app, desktop app or via the https://web.powerapps.com website. When I run this PowerApp I see this after starting up:

image

When I click Read Profile, it will call the Custom connector and get my profile information from Microsoft Graph:

image

Lets update some text in the About me textbox:

image

And then click on the butting Update About me, this will run the PATCH query against Microsoft Graph and update the “about me” attribute.

PS! The operation will run successfully, but it will return the following error when the custom connector to Graph API does not return a response object:

image

This is a flaw in PowerApps using Custom API connector, as it expext a JSON response object, but some operations against API’s are designed to return a 204 No Content response. We will fix that later by using a Flow.

To verify my profile has been updated, I can check in Dvelve and the about me section:

image

At this point we have seen that we can access the Microsoft Graph using a Custom connector from a PowerApp. There are a couple of more scenarios I will show before I wrap up this blog post, using Flows and Sharing the PowerApp with other users in my organization.

Using Microsoft Flow

Using Microsoft Flow with your PowerApps will make it possible to add workflows with actions and condtions to your apps. When creating a custom connector like we did to Microsoft Graph earlier, the same connector is available for your Flows.

I will go to the Flows section and create a new Flow. The first step for getting input from PowerApps is already there, so add a new step and select Action. From there you can search a lot of actions available, and you will find our PowerApps Microsoft Graph connector as well, with it’s 2 defined operations. Select the Update About Me Profile:

image

Next, the operation require 2 inputs, the first one I specify “application/json” which Microsoft Graph expects, and for the next aboutMe input, I select “Ask in PowerApps”:

image

This will create an input I later can use from PowerApps. This is all I need to do now, but I could have added more actions for example for sending an e-mail after updating the profile etc.

Now I specify a Flow name and Create or Update the Flow:

image

Back in my PowerApp, select the Update About me button, and then in the Action menu, select Flows:

image

Then find the Flow I created and add that:

image

You will see that the Run action for the Flow will prompt me for the Input I created with the “Ask in PowerApps” when I edited the Flow. This is where I would supply the the content from the txtAboutMe.Text control:

image

The OnSelect action for this button now looks like this, which will run the Flow:

image

Let’s Save and Publish the PowerApp again, and then launch it. First i Read the profile, and then I update some text in the About me:

image

When running Update About me now, the action successfully completes, with no error warning, and if I go to the Flow I can see the run history shows that it successfully completed. In the details I see that the Flow has triggered with the input I specified in the PowerApp:

image

Note that the Flow handles 204 No Content well, so now we have solved our problem in the PowerApps from earlier 🙂

Using a Flow will not only handle some types of inputs and outputs better for custom connectors than directly from PowerApps, but also make it possible to create more logic to your apps using workflows with actions, conditions and a lot of other data sources.

Sharing the PowerApp with other users

In the last part of this blog post I will show how you can share the PowerApp with other users. When you create a PowerApp it is only you that can access it:

image

Sharing an app that uses a custom connector, like we use for the Microsoft Graph, it will be automatically shared, but users must create their own connections to it.

And when sharing an app that includes a Flow, users who run the app will be prompted to confirm or update any connections on which the flow relies. In addition, only the person who created the flow can customize its parameters.

You can share the PowerApp to specific individuals, to groups or to the whole organization.

image

When sharing to the organization the users can find the PowerApp in the Dynamics 365 app store, under in-house apps:

image

Now, let’s test with another user, in this case I have a test user called [email protected]. When he launches the PowerApp for the first time he will need to create a connection to the custom connector:

image

After signing in he would need to  consent to the App permissions:

image

And after consenting click to Allow:

image

Now he can use the PowerApp, and when clicking Read Profile his details are filled in as expected. This is a test user I have based on the Seinfeild Show, so I will add to the “About me” with some text:

image

When I click Update About me, this users profile is updated. My test user does not have access to see the details of the Flow, but back with my original user that owns the Flow I can see that it indeed ran with the input from this user:

image

Summary

In this blog post we have seen how we can access the Microsoft Graph via a Custom connector in PowerApps and Flows. The sample shown in this post is simple with working with the profile of the logged on user, but with the power of the Microsoft Graph this opens up a lot of possibilities!

In later blog posts I will show some more exciting scenarios for using the Microsoft Graph, and I will link back to this blog post as a reference for how to get it all set up!

Thanks for reading, let me know in the omments if you have any questions or maybe some ideas for usage scenarios!

Azure AD B2B Users and Access to Azure AD Application Proxy Apps

The purpose of this blog post is to show a practical approach and some guidelines for publishing Azure AD App Proxy applications to guest users using Azure AD B2B.

To keep this blog post short and to the point, I will make the following assumptions:

Demo scenario

I will first give a quick overview over the demo scenario for this blog post:

  • I will use my tenant elven.onmicrosoft.com, where I have configured a custom domain elven.no.
  • I have invited an external user: [email protected] to the elven.onmicrosoft.com tenant. This user has accepted the invitation and can access resources that will be shared.
  • I have published some App Proxy applications, and in this scenario I will use Cireson Portal, which is a Self Service Portal for SCSM.

In this blog post I will use both single sign-on disabled with forms based authentication, and single sign-on with windows integrated authentication for this guest user, but lets first verify that the guest user can log on to my application panel.

Using Azure AD Access Panel as Guest User

When I log on to the Azure AD Access Panel at https://myapps.microsoft.com as external account I will se all my published applications at my company Skill AS, and since I have been added as a Azure AD B2B guest to the Elven Azure AD tenant, I can switch to that tenant like this:

image

I will then be redirected to the Elven Azure AD tenant and all my published applications will show (but for now this is none):

image

So lets start by adding this external guest to a published application without single sign-on and Windows Integrated Authentication enabled.

Without Single Sign-On

First, this is the guest user I will add to the application:

image

Then I go to the App Proxy Application, and in the properties I have required that any user must be assigned to access the application:

image

Under Application Proxy I will require pre authentication with Azure AD, so that users can not access the URL without being logged on to the tenant (in this case as a guest):

image

In this first scenario single sign-on with Azure AD and Windows Integrated Authentication is disabled:

image

Then I add my guest user as an assigned user to the application:

image

In the meantime I have configured the Cireson Portal to use Forms Based Authentication, and now we can test the guest user:

In the Access Panel my guest user can now see and launch the Cireson Portal published application:

image

And my guest user can successfully get to the web application which now presents a user login form, which will require a on-premises AD user with access rights to the Cireson Portal.

image

In my on-premises AD I have created just that, a user with the account name jan.vidar.guest:

image

And I can successfully log on with the guest user:

image

So far we have seen that an Azure AD B2B user can successfully launch an Azure AD App Proxy application, and in the next step log on with a local AD user with access to the application.

I the next section we will see how we can provide single sign-on with Azure AD and Windows Integrated Authentication.

PS! I will also change the Cireson Portal to use Windows Authentication before this next step!

Azure AD Single Sign-On and Windows Integrated Authentication

First I will need to change the settings for the Azure AD App Proxy application.

Under Single sign-on I will change to Integrated Windows Authentication, specify a SPN for Kerberos Constrained Delegation, and specify to use User principal name for delegated login identity:

image

By now you might have realized that for single sign-on to work with windows integrated authentication in a Azure AD B2B guest user scenario, you will need to have a “shadow” AD user for this external scenario. In my first test above, I had created a “jan.vidar.guest” user. Remember that I chose to use User principal name as a delegated login identity. So I will need a UPN that will be a link between my Azure AD guest user account ([email protected]) and the local AD user. If that link is missing, you will see the following in the Application Proxy Connector Log:

image

So this error message tells us exactly what user principal name is expected from the guest user. The error message below provide more details from this error:

Web Application Proxy encountered an unexpected error while processing the request.
Error: The user name or password is incorrect.
(0x8007052e)

Details:
Transaction ID: {00000000-0000-0000-0000-000000000000}
Session ID: {00000000-0000-0000-0000-000000000000}
Published Application Name:
Published Application ID:
Published Application External URL:
https://selfservice-elven.msappproxy.net/
Published Backend URL:
http://azscsmms3/
User: jan.vidar.elven_skill.no#EXT#@elven.onmicrosoft.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299
Device ID: <Not Applicable>
Token State: NotFound
Cookie State: NotFound
Client Request URL:
https://selfservice-elven.msappproxy.net/Home/NavigationNodes
Backend Request URL: <Not Applicable>
Preauthentication Flow: PassThrough
Backend Server Authentication Mode: WIA
State Machine State: OuOfOrderFEHeadersWriting
Response Code to Client: 500
Response Message to Client: Internal Server Error
Client Certificate Issuer: <Not Found>
Response Code from Backend: <Not Applicable>
Frontend Response Location Header: <Not Applicable>
Backend Response Location Header: <Not Applicable>
Backend Request Http Verb: <Not Applicable>
Client Request Http Verb: POST

So, lets change the UPN of my local shadow user to that. You can either add the UPN suffix to your Active Directory Forest, or change the user principal name with AD PowerShell like:

Set-ADUser jan.vidar.guest -UserPrincipalName jan.vidar.elven_skill.no#EXT#@elven.onmicrosoft.com

image

Generally you will need to add Azure AD B2B users with user principal name in the form of:

<emailalias>_guestdomain#EXT#tenantdomain

So, lets try to launch the Cireson Portal again now, this time with Azure AD Single Sign-On and Windows Integrated Authentication:

image

And now the user will be logged directly into the Cireson Portal with SSO:

image

So now we have seen that we can successfully use Azure AD B2B Guests in an Azure AD Application Proxy published application scenario, with or without Single Sign-On, and that we require a link with the delegated identiy with a “shadow” user in the on-premises AD.

NB! Before you think that you should create that user as a disabled account, this is what happens:

image

This means, you have to enable the AD user account, but the password can be anything and don’t have to be shared with the external user.

Update: Require MFA from Guest Users

I have had some questions on how requiring MFA would affect guest users when accessing published applications, and decided to update the blog post on this.

First of all you would need to create an Azure AD Conditional Access Policy where you:

  • Target the policy to your guest users, for example by creating a group (assigned or dynamic) with all guest users in your tenant.
  • Target the policy to your selected published Azure AD App Proxy Apps.
  • Setting the policy to require MFA.

Your guest users will have to set up their security verification methods in your tenant before they can authenticate with MFA as guests to your published application. They will be prompted to do that if they haven’t done it before at first time, but they can also do that by accessing their profile in your tenants myapps.microsoft.com. See below picture where my guest user can set up preferred methods for MFA in the elven tenant:

MFAGuest4

In this example I have set up Microsoft Authenticator on my mobile phone, and note the #EXT# identity which is the guest user for Elven tenant:

MFAGuest2

I can the select to launch the application as a guest user, and will be prompted authenticate with my selected method for MFA:

MFAGuest3

In my mobile phone I can approve, again I can see that I authenticate with my #EXT# guest account (most text in Norwegian, but you get the idea;)

MFAGuest1

See notes under for license requirements for MFA and guest users.

Notes and tips

Although Azure AD B2B is a free feature, creating local users in Active Directory and accessing resources like web servers, database servers and any third party applications you publish are not free and you will have to check your licensing requirements.

You shouldn’t synchronize your shadow guest users to Azure AD with Azure AD Connect.

Using Azure AD Conditional Access for require MFA is an Azure AD Premium feature, so you need EMS E3 or Azure AD Premium P1 licenses. You can then use up to 5 Azure AD B2B guests per EMS E3/AADP1 license you own, in a 1:5 ratio. So for example if you internally have 100 EMS licenses, you can require MFA for up to 500 Azure AD B2B guests.

And finally, Microsoft has noted that there will be guidance and documentation coming for best practice and governance for these Azure AD and on-premises AD guest users, as there can be a lot more complex enviroments than my example here, see this link: https://techcommunity.microsoft.com/t5/Azure-Active-Directory-B2B/AAD-Application-Proxy-and-B2B-Users/td-p/85249