Azure MFA – Setup Wizard

This post is part of a series, for the series contents see: Azure MFA

Once an account has been MFA enabled the next time you login you’ll be prompted to go through the setup wizard before you can continue.  In the case of my “itadmin” account I was greeted with the following:

MFA Enable Step 1

The first step is to choose what method you want to use for your 2nd factor of authentication.  The options available here are those specified in the Global MFA settings:

  • Mobile App (the Microsoft Authenticator App)
    • Either with a push notification
    • Or a code generated by the app
  • SMS
  • Voice call

MFA Enable Step 2

Personally, I really think that the app is the way to go: it’s flexible and can also be used with various other services including Facebook, Amazon, GitHub, and WordPress(!).

And with that mobile app I’m especially fond of the push notification:

MFA Enable Step 3

Configuring the app itself is as simple as getting it from Google Play, iTunes, etc. and then scanning a QR code to set it up

MFA Enable Step 4

At this point you’ll be sent a test notification to make sure everything is working as expected:

MFA Enable Step 5

Next up you get the choice of adding a phone number as a backup MFA method in case you lose access to the mobile app.  Obviously, you probably want to enter a number that’s different from the mobile where you’ve installed the app or it might end up being a pretty pointless backdoor.

MFA Enable Step 6

Then on the final screen of the wizard you’ll be given an app password to use with any legacy apps.

MFA Enable Step 7

With that all done, all that was left to do was test that it worked which I did by simply logging into :

MFA Enable Test


Azure MFA – Global Settings

This post is part of a series, for the series contents see: Azure MFA

Before showing what the enablement process is like for an end user, let’s just run through the global MFA settings you can set in Azure AD.

The steps to change these settings are:

  1. Login to the old portal (very annoying that this isn’t in the “new” portal yet):

  2.  Then go to Azure AD:MFA Global Settings AAD Choices
  3. Choose your directory (“irankon” in my case):MFA Global Settings AAD Irankon
  4. From the menu along the top of the page go to “Configure” then in the MFA section choose “Manage service settings”:MFA Global Settings AAD MFA Settings
  5. The first settings section let’s you choose whether or not you want to allow “app passwords”:MFA Global Settings AAD MFA Settings App PasswordsIn an ideal world you wouldn’t want to allow the use of app passwords but most of us don’t live in an ideal world so you’re likely to accept the default and allow them.An app password is a never expiring password that you can essentially use to bypass MFA and login to legacy non-browser apps: things like older versions of Office or some smart phone apps.

    Why wouldn’t you want to use them?

    Well, it’s a back door that isn’t tied down to a single app. It’s not a one to one relationship so you can use the same app password across multiple apps. Therefore if someone gets hold of a user’s app password then they can bypass both the need to know that user’s normal password and the protection of MFA all in one, across any application, until that app password is rescinded.

    The other scenario to imagine is the good old laptop left on a train story. If that laptop has Outlook configured with an app password then whoever has it will receive and see both old and new e-mail without prompts for MFA until the app password is rescinded which will stop new mail being pulled down.  Of course, hopefully you’ll have drive encryption enabled with something like bitlocker so that won’t be a problem!

  6. The second set of options allows you to add some trusted IPs or locations:MFA Global Settings AAD MFA Settings Trusted IPs
    What you’re doing here is whitelisting some locations. For example, you might find it counter productive for staff within your offices to have keep going through the multi-factor process every time they want to access business systems so you could add that office location’s public IP to the list above to say that you trust users coming from there and want to spare them the hassle of MFA.
    Anyone coming from a different location (i.e. outside the office) would have to authenticate with a 2nd factor.

    The other option in the screenshot above is to base that trust on whether or not they have an internal ADFS token as the way to show that they are in the office.  I guess there could be a use case for that, perhaps a shared office building where multiple companies appear behind the same public IP so that option becomes unavailable, but when I tried this out my experience was that it added a notable delay to the whole MFA login experience.

    Of course there is also always the argument that with the nature of modern attacks no location should thought of as “safe” or “trusted”.  The idea of a walled garden where your perimeter keeps you safe should be consigned to history and you should always secure the identity and data instead of purely focusing on the location.  I saw an interesting talk about that idea by Wendy Nather from Duo Security (another multi-factor vendor) where she used Google’s BeyondCorp model as an example of good practise in that regard.

    I agree with that idea and think that the “zero trust” model is the way to go, but the reality of an actual large corporate environment is that you may not win that argument as productivity will often trump security concerns.

  7. The final setting you can change is to define the authentication methods you want your users to be able to choose from:MFA Global Settings AAD MFA Settings Verification OptionsThe default settings are as above and include the recently controversial SMS method.On the security front there have been murmurs of disquiet about the security of SMS (see NIST guidelines) but there are still pros as well as cons for using SMS as illustrated in this Sophos article from last year.  As always, it comes down to a risk assessment of how likely it is for someone to have one of your user’s passwords and to go to the effort of an SMS scam.  If you reckon that you’re not that juicy of a target and the likelihood is low then you might be happy to accept SMS as a convenient method for users to be able to choose.
    Although if this Krebs on Security post is anything to go for then maybe this type of attack is more common than I thought.

Azure MFA – Enabling Users with PowerShell

This post is part of a series, for the series contents see: Azure MFA


With all the vital components in place I can now MFA enable a user but in order to do so I need an account with Global Admin rights over my Azure AD.

I think this is pretty ridiculous because, for me, enabling/disabling users for MFA should be a standard first line help desk activity and I reckon most organisations won’t be giving their first line teams full Global Admin rights.  It doesn’t really fit within a role based access model.  I raised it with Microsoft and, thankfully, was told that more granular permissions are on the way by the end of the year (2017 at the time of writing) so, hopefully soon, if not already, it’ll be possible to give MFA enablement rights to custom admin roles or those permissions will be added into the user administrator role.

In my case I decided to give my test “itadmin” account those rights so I logged into the portal and changed to my irankon directory.

MFA Enable Directory Choice

Then I went to my itadmin user and in the roles section gave them full Global Admin rights:

MFA Enable Global Admin

Enabling a User

The first step is to get connected up to Azure AD

#Get connected up to Azure AD using Global Admin Credentials
Import-Module MSOnline

$Credential = Get-Credential

Connect-MsolService -Credential $Credential

Next up, define the authentication options, including setting MFA to be enabled:

#First define auth options
$auth = New-Object `
-TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$auth.RelyingParty = "*"

#Set the option to enable MFA
$auth.State = "Enabled"

#Set MFA so that as of the current date
#devices issued to the user will also require MFA
$auth.RememberDevicesNotIssuedBefore = (Get-Date)

Then, finally, let’s bring it all together to enable our itadmin user:

#Next define our user and enable them for MFA
$UserPrincipleName = ""

Set-MsolUser `
​-UserPrincipalName $UserPrincipleName `
-StrongAuthenticationRequirements $auth

Now when “itadmin” next logs in they will be prompted to set themselves up with a second factor of authentication.

Disabling Users

This is going to be short and sweet!

To disable a user for MFA you just need to clear their “StrongAuthenticationRequirements” setting:

#Disable the user:
Set-MsolUser `
​-UserPrincipalName $UserPrincipleName `
-StrongAuthenticationRequirements @()

Licensing Users

As mentioned before there are pretty much three ways to sort out your Azure MFA licensing:

  1. Purchase MFA specific licenses and assign them to your users.  With this method you don’t need to create a cloud based MFA provider, in fact, if you do, you could end up paying twice.
  2. Purchase license bundles that include MFA such as Azure AD Premium (P1 or P2), E5, or EMS + Security E3 licenses.  Again, with this method you don’t need to create a cloud based MFA provider.
  3. Setup a cloud based MFA provider and pay on an Opex/Capacity basis, either per user using that provider or per authentication.

There’s a Microsoft article that probably explains it better than I do here.

If you’re doing either of the first two options then you’re going to want to give your users a license so here’s the PowerShell for that.

First of all, you will want to check the licenses you have available to you by running:

#Verify what licenses you have with:

Results will be returned in the format domain:licenseSKU so, for example:


You can then add that license SKU to a user with:

Set-MsolUserLicense `
-UserPrincipalName $UserPrincipleName `
-AddLicenses “irankontk:MFA_STANDALONE”

With some of the more complex license packs, such as EMS, you might want to add just one part of that pack but not the rest.  To do that you need to define some license options that identify the bits you want to exclude:

#Define the options we want, in our case MFA only
$licenseOptions = New-MsolLicenseOptions `
-AccountSkuId irankontk:EMS `

Then use those exclusions when adding a license to a user:

#Apply a license using those options
Set-MsolUserLicense `
-UserPrincipalName $UserPrincipleName `
-AddLicenses irankontk:EMS `
-LicenseOptions $licenseOptions

And that’s it.  I’ll post a tool belt style script in an upcoming entry that puts the licensing and enablement code into functions so it can be run against batches of users to setup them up.

Azure MFA – ADFS Customisation

This post is part of a series, for the series contents see: Azure MFA

I’m building up my ADFS servers to have some infrastructure to use when playing about with MFA, so they’re not directly related to MFA just a stepping stone along the way.  This post stretches that a bit further: it has nothing to do with MFA but fits best within this series given how far along the ADFS build has come.

It’s just a quick post to customise my ADFS web front end so that it’s not so bland and generic by following the instructions in this Microsoft article.

Logo Customisation

The main rules here seem to be that your logo file should be:

  • 260×35 pixels
  • 96 DPI
  • No greater than 10KB

I say “rules” but actually you can push the boundaries on the sizes, you’ll just see a performance hit with screen size scaling (i.e for mobiles) or slower load times as it tries to pull down your image.

Anyway, I simply made up a logo file to specification (in PNG format) and then enabled it by running the following on my ADFS server:

Set-AdfsWebTheme `
-TargetName default `
-Logo @{path="c:\irankon_logo.png"}

And that is all that is needed.  You can actually create whole new themes to customise the look of the ADFS page whereas the one-liner above is simply modifying the default theme.

The result turned out like this:

ADFS Logo Change

Illustration Customisation

The other part I decided to customise was what Microsoft refers to as the “illustration” – the blue area to the right of my ADFS screen that you can see a bit of above.

The rules for this one (same reasons apply) are:

  • 1420×1080 pixels
  • 96 DPI
  • No greater than 200KB

I’m no artist myself so I grabbed a good image from, a nice bit of scenery in NES style 8-bit.  Then, sticking with the old school theme, I loaded it into good old MS Paint (not Paint 3D that they’re pushing everyone to use) and resized it to 1420×1080.

The resized image didn’t scale perfectly but it was good enough, however what wasn’t good enough was that the image was 1.3 MB in size.  Even if you can push the limits of Microsoft’s recommendations, 1.3 MB is simply too big for a page to have decent load time so I pumped the image into and got it down to a more sensible 230 KB.

With that done I set it as the image to use on my customised ADFS page with another PowerShell one-liner:

Set-AdfsWebTheme `
-TargetName default `
-Illustration @{path="c:\8-bit-illustration.png"}

Again, just modifying the default theme, this time the result was:

ADFS Illustration Change


Azure MFA – ADFS Federating a Domain

This post is part of a series, for the series contents see: Azure MFA

At this point we’ve got all of our ADFS infrastructure in place but before we can make use of it we need to federate our domain.  I think of this step as essentially configuring Azure AD to know that you’ve got federation infrastructure setup and how to offload request to it: i.e. how your ADFS is presented publicly ( in my case).

Federating a Domain

Luckily it’s just a little bit of PowerShell and you’re done.  I ran the PowerShell from my ADFS server (adfs-vm) so first of all I needed to install the Azure AD PowerShell module on there, which I downloaded from:

ADFS Federate Module Download

With that installed, next up I connected to Azure AD using PowerShell and logged in.  The federation operation needs to be performed by an account with Global Admin privileges so I used the account I created earlier, to perform my DirSync operation with AAD Connect, and logged in as:


#Import the AD Module
Import-Module MSOnline

#Login to Azure AD with
#When prompted I logged in with:

Once connected, I then checked the current federation status of my domains with:

#Verify the domain status with

ADFS Federate Domain Check

Then, finally, I federated my domain with:

#Then federate the domain with
Convert-MsolDomainToFederated -DomainName

ADFS Federate Domain

The feedback from the cmdlet is pretty much instant but in reality all that has done is kick off a background process in Azure AD and it will be a another couple of hours before you can start making use of it in earnest.

Testing It Has Worked…

Testing it out is as simple as:

  1. Creating an account in the on premise AD environmentADFS Federation Test AD Account
  2. Synchronising that up to Azure AD with AAD Connect (or waiting for that process to happen automatically):ADFS Federation Test Synch Verify
  3. Giving the account some permissions in the Azure Portal (so that you can login as it)ADFS Federation Test Azure Admin
  4. Then logging in to to prove the pointADFS Federation Test Login

At this point, choosing my test account takes me to my ADFS sign-in page (i.e. my ADFS Proxy server):

ADFS Federation Test ADFS Offload

And then, finally, once the ADFS infrastructure has completed the authentication process you get logged into Azure successfully with a synchronised and federated identity:

ADFS Federation Test Success



Azure MFA – ADFS Proxy Build

This post is part of a series, for the series contents see: Azure MFA

Things are starting to near completion now:

  • I’ve got an ADFS server configured
  • Testing shows that it works internally

Next up is to build up an ADFS proxy server to expose that to the outside world where it can be used so that I can authenticate against SaaS apps using my internal domain accounts.

So what I need to do is build up a web application proxy server in my DMZ, give it a public IP address, and then setup a public facing DNS record ( pointing to that public IP address.


Just as with the ADFS server you need to make sure you install your SSL certificate on the server before configuring it as an ADFS proxy so that it’s available for you to choose during the install wizard.  In my case, I just copied over my Let’s Encrypt SSL cert for, double-clicked to install it and then chose the local computer option when asked.

ADFS Proxy VM Build

The PowerShell to create the VM is:

# Setup Windows ADFS Proxy VM #

#Specify the resource group and location
$RGName = "dmz-rg"
$Location = "North Europe"

#First setup default credentials to use in provisioning by retrieving and decrypting our Key Vault password
$Username = "adminuser"
$SecurePwd = Get-AzureKeyVaultSecret -VaultName 'lab-vault' -Name 'ProvisionPassword'
$Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePwd.SecretValue

#Define VM basics
$VMName = "adfsproxy-vm"
$VMSize = "Standard_A1"
$OSDiskName = $VMName + "OSDisk"
$StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $RGName -Name dmzvmstr
$vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name dmz-vnet

#Create a public IP
New-AzureRmPublicIpAddress -Name adfsproxy-vm-pip -ResourceGroupName $RGName `
-AllocationMethod Static -Location $Location

#Define VM network details
#Private IP
$NIC1 = New-AzureRmNetworkInterface -Name "adfsproxy-vm-eth0" -ResourceGroupName $RGName -Location $Location -SubnetId $vnet.Subnets[0].Id -PrivateIpAddress

#Public IP
$pip = Get-AzureRMPublicIPAddress -ResourceGroupName $RGName -Name adfsproxy-vm-pip
$NIC1.IPConfigurations[0].PublicIPAddress = $pip

#Confirm the details
Set-AzureRmNetworkInterface -NetworkInterface $NIC1

#Define the VM config
$VirtualMachine = New-AzureRmVMConfig -VMName $VMName -VMSize $VMSize
$VirtualMachine = Set-AzureRmVMOperatingSystem -VM $VirtualMachine -ComputerName $VMName -Windows -Credential $Credential
$VirtualMachine = Set-AzureRmVMSourceImage -VM $VirtualMachine -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Skus "2016-Datacenter" -Version "latest"
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $NIC1.Id
$OSDiskUri = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $OSDiskName + ".vhd"
$VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -Name $OSDiskName -VhdUri $OSDiskUri -CreateOption FromImage

#Create the VM
New-AzureRmVM -ResourceGroupName $RGName -Location $Location -VM $VirtualMachine

Setting Up Name Resolution

The DNS zone for my domain ( is hosted in Azure DNS so I can also use PowerShell to update my public facing DNS record.  I say “update” because, of course, I already created an record pointing to my cert-vm’s public IP so that I could get my free Let’s Encrypt SSL cert.  This will re-point that existing record to my ADFS Proxy VM’s public IP instead:

#Update my sts DNS record to now use my ADFS Proxy public IP instead of the cert-vm public IP
$RGName = "hub-rg"

$RecordSet = Get-AzureRmDnsRecordSet -Name "sts" -RecordType A -ZoneName -ResourceGroupName $RGName

$RecordSet.Records[0].Ipv4Address = $pip.IpAddress
Set-AzureRmDnsRecordSet -RecordSet $RecordSet

The next step might seem a little odd but, when you think about it, it does make sense:  I need to create a hosts file entry on the ADFS proxy VM pointing at my internal ADFS server.

It comes down to the fact that ADFS makes use of split brain DNS:

  • Public DNS pointing to the ADFS proxy server
  • Internal DNS pointing the the ADFS server

The proxy server needs to offload to the ADFS server but because it is in the DMZ it won’t be using internal DNS, it will query public DNS and end up resolving to itself and getting stuck in a loop!  So, to stop that happening, I need to setup a hosts file entry on the server pointing it internally instead:

ADFS Proxy Hosts File

ADFS Proxy Configuration

The installation itself can just be done via “Add Roles and Features” but you won’t find an “ADFS Proxy” role, what you want is “Remote Access”:

ADFS Proxy Config Step 1

Then specify “Web Application Proxy”:

ADFS Proxy Config Step 2

Next up, specify some details about the ADFS service and an account with permissions to connect to the internal ADFS server:

ADFS Proxy Config Step 3

Before finally getting to the part of the wizard where you can choose the SSL cert you installed earlier:

ADFS Proxy Config Step 4

And then you should be done and have a working, publicly available ADFS infrastructure in place.

Azure MFA – ADFS Server Build

This post is part of a series, for the series contents see: Azure MFA

With the foundations in place (i.e. DNS + SSL cert all sorted) next up is building the ADFS server itself.  Obviously in the real world you’ll want two for resilience but as this is just a lab environment I’m only building one.  It’s cheaper that way.


First up let’s build the base VM in my internal resource group  (see my Azure Lab series for details):

#Login to Azure resource manager

#Just in case you have multiple subscriptions check which one you're working in

# Setup Windows ADFS VM #

#Change to the internal resource group
$RGName = "internal-rg"

#Define VM basics
$VMName = "adfs-vm"
$VMSize = "Standard_A1"
$OSDiskName = $VMName + "OSDisk"
$StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $RGName -Name internalvmstr
$vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name internal-vnet

#Define VM network details
$NIC1 = New-AzureRmNetworkInterface -Name "adfs-vm-eth0" -ResourceGroupName $RGName -Location $Location -SubnetId $vnet.Subnets[0].Id -PrivateIpAddress
Set-AzureRmNetworkInterface -NetworkInterface $NIC1

#Define the VM config
$VirtualMachine = New-AzureRmVMConfig -VMName $VMName -VMSize $VMSize
$VirtualMachine = Set-AzureRmVMOperatingSystem -VM $VirtualMachine -ComputerName $VMName -Windows -Credential $Credential
$VirtualMachine = Set-AzureRmVMSourceImage -VM $VirtualMachine -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Skus "2016-Datacenter" -Version "latest"
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $NIC1.Id
$OSDiskUri = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $OSDiskName + ".vhd"
$VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -Name $OSDiskName -VhdUri $OSDiskUri -CreateOption FromImage

#Create the VM
New-AzureRmVM -ResourceGroupName $RGName -Location $Location -VM $VirtualMachine

This is my internal ADFS server so the next step is to login and get it joined to my AD domain:

#Login to the newly built machine and add to the domain with:
Add-Computer -DomainName "" -Restart

At this point there is one last key thing to do on the VM in preparation: install the Let’s Encrypt SSL Cert!

I simply copied over the certificate pfx file, that I’d exported from my cert-vm before, double-clicked and installed it to the local machine.

Service Account Setup

Once you install ADFS, your going to need an account to run the service as.  This can be a normal old school service account or something a bit more fancy like a group managed service account (gMSA). Every now and then fancy is good so here’s how to prepare the gMSA.

First up you need generate the Key Distribution Service (KDS) Root Key which is what the domain controller needs to begin generating gMSA passwords.  Normally you have to wait 10 hours after generating this to allow for replication but in a single DC lab environment like mine you can set the “EffectiveTime” to 10 hours in the past as a fudge to get you up and running straight away.  There’s a TechNet article about it here, and this is the PowerShell to run:

#I ran this on my ad-vm
Add-KdsRootKey –EffectiveTime (Get-Date).AddHours(-10)

The next step with a gMSA is to create an AD group whose members will be allowed to use the account.  Those members will be computer accounts.

#Create an AD group, the members of which will be able to use the gMSA
New-ADGroup –name "grp-adfs-gmsa" –groupscope Global

#Add my ADFS VM as a member of that group
Add-ADGroupMember "grp-adfs-gmsa" –members “adfs-vm$”

Then it’s time to finally create the gMSA itself:

#Now create the gMSA
#I think the DNSHostName switch is specifying the DC on which to create the account
New-ADServiceAccount `
-name adfs-gmsa `
-DNSHostName `
-PrincipalsAllowedToRetrieveManagedPassword "grp-adfs-gmsa"

You’d think that you’d be done by now but, no wait, you still need to install the newly created gMSA on the ADFS VM:

#Run on adfs-vm
Add-WindowsFeature RSAT-AD-PowerShell
Install-ADServiceAccount -Identity adfs-gmsa

ADFS Install

Right, finally, you should now be ready to install the ADFS role on the server which you can do by simply firing up “Add Roles And Features” from Server Manager:

ADFS Role Install

Similar to a lot of Windows role installs, once the main install has completed you’ll then be prompted to go through a separate configuration wizard.

For the first step I chose the first federation server in a new farm option.  I made a mental note of the O365 comment at the bottom of the page as I’m planning to lab about that in the future so I guess I’ll have to do some retro-fitting:

ADFS Config Step 1

Because this is essentially part of the AD infrastructure you next need to specify an account with admin privileges.  I used my domain/enterprise admin account:

ADFS Config Step 2

For the service properties I was able to choose my Let’s Encrypt SSL cert, thanks to installing it beforehand, and for the federation service display name I simply chose “irankon”.  All that is really specifying is what will be displayed on the ADFS web login page that is presented to users.

ADFS Config Step 3

The next step is where you get to specify your service account, or in our case the gMSA

ADFS Config Step 4

Then you choose the database type to store your ADFS configuration data.  Unless you have a particularly huge environment (more than 30 ADFS servers) then you’re going to choose the WID option here.  There’s a Microsoft article here about the requirements.

ADFS Config Step 5

Finally you get to review the options you’ve chosen

ADFS Config Step 6

Then before the wizard completes it runs some final prerequisites checks.  I got a couple of warnings here but nothing to worry about

ADFS Config Step 7

And that was that, although again I did have a couple of warnings once it was all complete:

ADFS Config Step 8

Verifying the Install

There’s no better way of verifying that ADFS is up and running than by browsing to it.

As we’re still all internal at the moment (no ADFS proxy servers setup) you’ll need to configure an internal DNS record pointing to ADFS:

Add-DnsServerResourceRecordA `
-Name "sts" `
-ZoneName "" `
-AllowUpdateAny `
-IPv4Address "" `
-TimeToLive 00:05:00

Now, here’s an interesting thing, on Windows Server 2012 R2 there was an ADFS test page you could use but in 2016 that is disabled by default.  There’s a nice TechNet article about it here where the author, Rhoderick Milne, handily also tells you how to re-enable it:

#Enable viewing the test sign-in page
Set-AdfsProperties -EnableIdPInitiatedSignonPage $true

With that in place I was then able to browse to my ADFS login page:


And login successfully:

ADFS Test Success

Azure MFA – ADFS SSL Cert with Let’s Encrypt

This post is part of a series, for the series contents see: Azure MFA

I’m a cheap guy so I don’t want to spend any money on this lab.  My Azure stuff is covered by the hours I get as part of my MSDN subscription and my test domain is free from freenom, so there’s no way that I want to fork out and pay for an SSL certificate.

Enter, Let’s Encrypt: the free, automated, and open certificate authority.

I first read about Let’s Encrypt over a year ago when a teammate at work put forward the idea that we might want to use it as a cost saving measure for securing some of our internal management interfaces which we’ve always tended to use public CA certs for as they’re relatively cheap and it saves us the hassle of managing an internal PKI infrastructure.  At the time I had a look and Let’s Encrypt wasn’t yet inherently trusted by the common browsers (it was going through the Mozilla process but there wasn’t much on the site about IE or Chrome), so I thought it wasn’t quite ready.

Fast forward to now and those problems have all gone, it seems that all the major browsers now trust the CA by default, so I thought I’d give it a go for this ADFS lab.

How It Works…

This took me a few minutes to get my head around at first because I’m very much used to the traditional method for getting an SSL certificate:

Usual SSL Cert Process

That’s all far too manual for the Let’s Encrypt model, which is designed for an automated DevOps kind of world. In fact, each Let’s Encrypt cert only lasts 90 days so, generally, if you’re not running a build and burn DevOps style deployment method then you might want to question if it’s the right solution for you.

The Let’s Encrypt method uses tooling and the “Automated Certificate Management Environment (ACME)” protocol as follows:

Automated SSL Cert Process

All pretty simple and logical when you think about it – Let’s Encrypt do a much better job of explaining the process than me here.

Putting it into Action

Most of the ACME tools out there are for Linux but I wanted to get it up an running on Windows for no better reason than it would make my life easier for exporting the cert to use on my ADFS and proxy servers.  I can never remember my OpenSSL command line switches so I always end up having to Google things…

This is how you do it, the high-level steps are:

  1. Create a new Windows Server VM being sure to give it a public IP
  2. Install IIS and create a basic site with the host header you want for your cert.  In my case:
  3. Create a DNS entry pointing to the VM’s public IP
  4. Install and run the Windows ACME agent on the VM (you can download it here)

Step 1 – Create the Windows VM with a Public IP

First up, create a certificate VM in the DMZ with a public IP.

#Login to Azure resource manager

#Just in case you have multiple subscriptions check which one you're working in

#If you need to select your test subscription use:
#Set-AzureSubscription -SubscriptionName 

# Setup Windows Cert VM for Let's Encrypt #

#This is needed to use Let's Encrypt to get a free SSL cert for ADFS usage

#Specify the resource group and location
$RGName = "dmz-rg"
$Location = "North Europe"

#First setup default credentials to use in provisioning by retrieving and decrypting our Key Vault password
$Username = "adminuser"
$SecurePwd = Get-AzureKeyVaultSecret -VaultName 'lab-vault' -Name 'ProvisionPassword'
$Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePwd.SecretValue

#Define VM basics
$VMName = "cert-vm"
$VMSize = "Standard_A1"
$OSDiskName = $VMName + "OSDisk"
$StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $RGName -Name dmzvmstr
$vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name dmz-vnet

#Create a public IP
New-AzureRmPublicIpAddress -Name cert-vm-pip -ResourceGroupName $RGName `
-AllocationMethod Static -Location $Location

#Define VM network details
#Private IP
$NIC1 = New-AzureRmNetworkInterface -Name "cert-vm-eth0" -ResourceGroupName $RGName -Location $Location -SubnetId $vnet.Subnets[0].Id -PrivateIpAddress

#Public IP
$pip = Get-AzureRMPublicIPAddress -ResourceGroupName $RGName -Name cert-vm-pip
$NIC1.IPConfigurations[0].PublicIPAddress = $pip

#Confirm the details
Set-AzureRmNetworkInterface -NetworkInterface $NIC1

#Define the VM config
$VirtualMachine = New-AzureRmVMConfig -VMName $VMName -VMSize $VMSize
$VirtualMachine = Set-AzureRmVMOperatingSystem -VM $VirtualMachine -ComputerName $VMName -Windows -Credential $Credential
$VirtualMachine = Set-AzureRmVMSourceImage -VM $VirtualMachine -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Skus "2016-Datacenter" -Version "latest"
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $NIC1.Id
$OSDiskUri = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $OSDiskName + ".vhd"
$VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -Name $OSDiskName -VhdUri $OSDiskUri -CreateOption FromImage

#Create the VM
New-AzureRmVM -ResourceGroupName $RGName -Location $Location -VM $VirtualMachine

Step 2 – Install IIS and Setup a Basic Site

There’s nothing big or clever here, just simply using Add Roles & Features to install IIS. Or you could do it with PowerShell using the following:

Install-WindowsFeature -Name Web-Server, Web-Mgmt-Tools

The whole point of this step is to have a website where the ACME tool can create a publicly available file that Let’s Encrypt can then use as verification that I do indeed own my domain.

Once IIS is installed, fire up the management console and create a site with the host header and bindings for “”

ADFS Site Creation


ADFS Site Bindings

Then in the site’s root directory add a noddy index.htm file:


I don’t think this is necessary for the whole Let’s Encrypt thing but it does give you some content to use to verify that the site is up and running (see the next step for details).

Step 3 – Setup a DNS Record

If you’ve got your zone setup and hosted in Azure DNS, like I have for, then create a record for sts.<domain>.<tld> with a quick bit of PowerShell:

#Specify the resource group and location
$RGName = "dmz-rg"
$Location = "North Europe"

#Public IP
$pip = Get-AzureRMPublicIPAddress -ResourceGroupName $RGName -Name cert-vm-pip

#Setup DNS
$RGName = "hub-rg"
New-AzureRmDnsRecordSet `
-Name "sts"`
-RecordType A `
-ZoneName "" `
-ResourceGroupName "$RGName" `
-Ttl 3600 `
-DnsRecords (New-AzureRmDnsRecordConfig -IPv4Address $pip.IpAddress)

With that all in place, you should then be able to verify that the web server is indeed working by simply browsing to it:

ADFS SSL Basic Site

Step 4 – Use the Windows ACME Tool to Get an SSL Cert

With all the prep done, all that is left to do is to use the Windows ACME tool and get an SSL cert.

After a quick Google the Windows ACME agent I settled on was “Let’s Encrypt Win Simple”.  It’s very easy to use, first up download it from the GitHub page and extract the zip file locally on your VM.  Then open up a command prompt, browse to the directory, and just run: letsencrypt.exe

ADFS SSL cmd tool

The tool will search IIS for sites and their bindings, at which point just enter the number for the site you want to create an SSL cert for (“1” in my example below).

ADFS SSL cmd tool options

At this point the tool will kick in and sort out the verification stage before installing a brand new Let’s Encrypt cert for the chosen site.

ADFS SSL Cert Installed

With that done, the final step for will be to export that cert for use on your ADFS servers later on.

ADFS SSL Cert Export

Azure MFA – ADFS Infra Overview

This post is part of a series, for the series contents see: Azure MFA

Very quick post to set the scene of the ADFS environment I’ll be building up – nothing fancy just standard ADFS.

ADFS Infra Overview

Essentially the flow will be:

  1. An external user will hit an ADFS proxy server sitting in the DMZ to provide an extra layer of security as middleman between the outside world and the ADFS server itself.
  2. The login request will then be passed through to the ADFS server itself.
  3. The ADFS server will offload username/password authentication to the local AD server (this is the 1st factor of authentication)
  4. It will then offload to the cloud based MFA Auth Provider for the 2nd factor of authentication.

Steps 1-3 have been around for years with ADFS but step 4, the ability to offload MFA to the cloud, is new to ADFS 3.0 on Windows Server 2016.

That’s the simplistic view of what we’ll be achieving but in reality things are a little more complex, due to DNS and SSL cert considerations, which makes the real picture a bit more like this:

ADFS Detailed Infra Overview

The fundamentals you need are:

  • An SSL certificate to secure traffic to the ADFS proxy and to the ADFS server itself.  Usually the same cert on each.
  • Split brain DNS so that when an external user contacts they hit the ADFS proxy whereas an internal user will hit the ADFS server directly.

The flow for an external user will be:

  1. Query external DNS for
  2. That should take them to the ADFS proxy protected by a valid SSL certificate
  3. The user will enter their credentials and the proxy will pass the details to the ADFS server.
  4. The ADFS server then offloads the request to AD to authenticate the user with their username/password.
  5. Finally the ADFS server offloads to the Azure MFA Auth Provider to prompt the user to authenticate using their 2nd factor.  Usually this will be a smartphone app notification from the Microsoft Authenticator app or an SMS message with a code.

For an internal user that flow will be:

  1. Query internal DNS for  Usually this will be a query to the AD server.
  2. That should resolve and take them straight to the ADFS server protected by a valid SSL certificate.
  3. As the user is internal will have already authenticated against AD (assuming their machine is on the domain) then the first part of the authentication process against AD will happen transparently as single sign-on.
  4. Then, just as for the external user, the ADFS server will offload to the Azure MFA Auth Provider to prompt the user to authenticate using their 2nd factor.

All nice and easy!

A couple of things to note:

  1. For the single sign-on piece:
    • You’ll probably want to setup a proxy exception
    • You’ll also want to add your ADFS URL ( to the local intranet zone in IE.  Group policy might be your friend here.
    • Single sign-on should then just work for browser based authentication but for some apps, such as PowerShell, you may also need to install the Microsoft Online Services Sign-in Assistant. Again Group Policy, or SCCM, will be your friend here.
  2. I’ve used the URL of but you can choose anything you want.  The standard ones everyone tends to use are:
    • adfs.<domain>.<TLD>
    • sts.<domain>.<TLD>   (where sts stands for: “Security Token Service”)

In the next post I’ll get the SSL cert for my lab environment, for free!

Azure MFA – ADFS Options Overview

This post is part of a series, for the series contents see: Azure MFA

I’ve got an MFA auth provider setup now, so I guess, technically, I could start using it for cloud based accounts, but what I really want to do is use it with my on-premise domain identities.  For that, the easiest thing to do is setup ADFS.

There are two methods to combine ADFS with Azure MFA, essentially an old way and a new way.  The old stems from the fact that when Microsoft released Azure MFA the didn’t quite nail their colours to the mast and ended up with this weird halfway house of essentially two products:

  1. Cloud based Azure MFA
    This is what we’ve setup so far and is used as an extra layer of protection for cloud based services.
  2. Azure MFA Server (i.e. the old way)
    This is a server based product designed to protect on-premise applications and resources, including the ability to RADIUS offload devices such as firewalls to it to apply multi-factor for things such as VPN access.

My experience with the MFA server product hasn’t been good and I don’t have a good impression of it.  Technically the product isn’t that smooth to configure, it’s obviously early on in an Agile process and has a lot to improve.  It’s very cumbersome to setup and kind of reminds me of the Bitlocker product from a few years ago which seemed far from polished (I assume it’s a lot better nowadays).

However, whereas I’m always happy to overcome technical inadequacies where the real problem lies with the server product is its fundamental mentality and design which I’ll try to sum up in a few bullet points:

  • Using the MFA server product requires you to first setup an Azure based auth provider, after which you get the option to download the product.  Then, when you install it, the server will register with the Azure based auth provider and appear in your cloud dashboard.  The reason for this is that the server product offloads the MFA process to the cloud based product which begs the question: is this a truly on-premise solution?  It doesn’t seem to have made up its mind.
  • In reality I don’t care that it uses the cloud auth provider.  In fact, from my perspective, that’s great as it’s one less on-prem component to nurture, upgrade, or worry about.  It’s this next point that I find really weird: the server product requires users to register with the MFA server and go through a setup/enrolment process.

You might ask: “So? What’s the problem with that?”

Well here’s the scenario where I think it doesn’t make sense:

As a business you’ve implemented Azure MFA to protect you Azure admin users and O365 accounts.  You’ve rolled it out across the business and everyone has gone through the enrolment process of setting up SMS, voice calls, or the Microsoft Authenticator app as their 2nd factor of authentication.  Across a large business with varying use cases, and people using all sorts of mobile devices, this can be a painful, helpdesk heavy process.

At this point, you decide that you also want to apply Azure MFA to your VPN connectivity or an on-premise app so you install the MFA server product.  In an ideal world it would be as simple as telling the business “from now on VPN and app “X” will also require you to use MFA as you do with O365″.  In reality, you’re going to have to get all of those users to go through yet another enrolment process to register with the MFA server and choose their 2nd factor of authentication again: SMS, voice call, or Microsoft Authenticator App.

It seems crazy to me that you’re going to have to go through all of that pain again, despite the fact that you know that the server product is talking the the Azure based MFA provider in the background.  It offloads the auth process there but doesn’t care whether or not the user has already enrolled for Azure MFA using that cloud service.

Cloud and server are treated as two separate things whereas I think you should have the option of taking the offload a step further so you can take advantage of any roll out work already done so far.

OK, at this point I’m very aware that whilst I started off talking about ADFS I’ve gone off at a tangent by ranting about the MFA server product so I’ll try now to join those two things back up and get this post back on track!

The crux of the issue is that in the past if you wanted to add in Azure MFA to protect sign-in to products via your ADFS farm you would have had to have installed the MFA server product.  It was marketed as the ADFS Azure MFA add-in but in reality that add-in was just a way to point ADFS authentications at you on-premise Azure MFA server.  Which, again, would mean that your users would have had to have enrolled with that on-premise server in order to use it.  That was the case with ADFS 2.0 and 3.0 on Windows Server 2012 (R2), but with ADFS 3.0 on Windows Server 2016 that is no longer the case!

It seems that Microsoft have come to the same realisation as me because ADFS on Server 2016 now gives the option of using MFA that offloads to your cloud setup rather than having to use the on-premise server option.

Over the next few posts I’m going to test that out by building up a server 2016 ADFS environment.