I like solutions that are both secure and user-friendly at the same. (Who doesn't?) I also know that it can be real hard to build such solutions on your own so I'm happy when the Azure AD teams provide the bits I need for implementing the authentication parts in a good way :)
When I noticed a post about Certificate-Based Authentication (CBA) on mobile with YubiKeys I wanted to take things for a spin:
The blog post itself is just a teaser, but it provides links to the configuration docs so I thought I would follow those. Unfortunately I felt the instructions were missing a few details for doing a quick proof-of-concept in my lab. Which is why I'm writing this post.
To be clear - the instructions here are not intended for production use. When the docs define the following as out of scope "Customers need to configure their own Public Key Infrastructure (PKI) and provision certificates to their users and devices." I consider that to be true. What you do in a lab for learning is something else entirely.
CBA on YubiKey requires a hardware key from yubico, and they have plenty to choose from. I'll let you figure out which form factor and interface you like but I went with the YubiKey 5C NFC. The important bit is that you need one with support for PIV. The blue "Security Key" and the "Bio Series" do not support this and cannot be used.
YubiKey 5C NFC
The guide specifically calls out YubiKey and I have not tested other keys so I don't know if this is just a soft limitation or if you can make it work with other hardware keys.
As this key has a USB-C connector it can be used for newer Android devices and iPads. (I tested with a Pixel 7 and iPad Pro 2021.) The NFC chip can be used with iPhones. (iPad does not support NFC.) So depending on your combination of devices it could be that you just need the one key to support them all.
While usage in Windows is also a good scenario it is out of scope for this article. (It requires smart card support to be configured so it's not entirely plug and play.)
As mentioned in the docs assume stock browser support (Chrome on Android, Safari on iOS).
It should also work with apps you develop yourself when using the MSAL libraries. More on that later.
What about FIDO2?
FIDO2 is great. When it works. The combination of Azure AD + FIDO2 + mobile is not quite there. (On Windows and MacOS you should be good.)
There's nothing preventing you from using both. In my lab I went with PIV/CBA for mobile and FIDO2 on my Surface where both configs were linked to the same account in Azure AD.
Another important point is that for an enterprise CBA and FIDO2 covers different use cases. As a user I can receive a FIDO key straight from the shop and self-enroll it into Azure AD without much fuss. With certificates I have to perform an enrollment procedure to load the cert onto my key outside of Azure AD. Exactly how this is implemented is up to each company. With FIDO support is baked into the OS, but tied to the device the key is plugged into. With CBA you need extra drivers, but you can re-use credentials for an RDP session. Short version - which one is right for you depends on what you want to do :)
Setting up a Certificate Authority
As already alluded to the first part of configuring Azure AD CBA is "Configure at least one certification authority (CA) and any intermediate CAs in Azure AD."
Setting this up properly is a project of its own. Setting this up quick and dirty in a Windows Server lab could be done by enabling Active Directory Certificate Services in your on-prem AD. The even quicker way is just firing up Windows Subsystem for Linux (WSL) and use OpenSSL.
I drew inspiration from this post, but made a few tweaks since I'm not looking to implement https for a web site right now:
The tricky part is making sure the certificate contains the correct properties to work with AAD CBA and for this we need an extension file for OpenSSL. Create a text file (like contoso.ext) with the following contents:
I hardcoded the SAN to a specific email address which obviously doesn't scale, but the whole point is that we're not building for production now :) Should be easy to script this if you're lining up a stack of certificate requests.
Configure Azure AD
Since you have your CA/PKI created you can now perform the steps in the configuration guide:
The public part of the certificate you generated is in the myCA.pem file. The Azure Portal expects a .cer extension. Copying/renaming to a new file called contoso.cer, or whatever you prefer, should work. You can leave the CRL and Delta CRL fields blank, and you should choose "Yes" that this is a root CA cert.
In Step 3 Configure authentication binding policy I found things to be not entirely clear as I thought I could just go with the issuer and ignore the policy part. You need both rules to be in place for things to work. (Based on the extension file used above the Policy OID equals 18.104.22.168 as in the guide.)
Creating the leaf certificate
You should now have the server part of things configured and in place. The next part is bootstrapping your key with a certificate. For small scale testing like here the easiest thing to do is install the YubiKey Manager application on Windows or MacOS and use that.
In YubiKey Manager go to Applications=>PIV=>Configure Certificates. Click "Generate" and select "Certificate Signing Request". Use the default algorithm, and for Subject type your UPN (like firstname.lastname@example.org). The file you get as an output should be put into the certificate directory on your OpenSSL creation box.
I have tested them, and got it working, but there are mistakes one can easily make. For instance on iOS - you must enter the PIN and press OK before tapping the NFC chip to the device. Tapping the chip first will fail. Similarly you can "trick" your Android device into an incorrect sequence of things as well. You will probably be able to figure out things, but don't be surprised if you get it wrong once or twice.
Needing something mobile friendly I found opening https://myapps.microsoft.com to be a good test site if you don't want to install apps. (Outlook Mobile seems to work fine if you want to check that out.)
I had to put in the Azure AD details like an app registration, tenantId, etc. as well as configuring redirects in the Azure Portal accordingly. But this is not specific to CBA - the YubiKey/certificate part just worked with no extra config. (The default caching seems to be very user-friendly with hardly ever requiring reinserting the key.)
If you create something like a Blazor app where you enable Azure AD as the identity provider it also works without any secret sauce needed. At least on my iPhone, where I can use NFC, I feel this provides a much better experience than typing in long and complex passwords followed by MFA prompts in the Authenticator app. (Note that there is a "double prompt" known issue which is a slight snag in the experience currently, but it's a preview for a reason.)
Forcing usage of CBA
If you go through the work setting this up it could be that you want to not have it just as an option for users, but actually enforce it. I tested applying a Conditional Access policy (based on the appId of my MAUI app) and this also works. Mind you, you can't choose CBA specifically - you need to choose "Phishing-resistant MFA". FIDO2 also qualifies as resistant so your YubiKey can satisfy the requirement two different ways.
As already stated this is a preview feature so things might change. If you find errors in my guide please shout out in the comments below.