My original post on using NPS with Azure AD / Entra-joined devices is consistently the most-read item on this blog; nothing else even comes close. Clearly there is widespread awareness of the need for on-prem network authentication for cloud-managed devices but despite remarkably longstanding requests for attention Microsoft seems to be no closer to providing a solution.
The great little workaround for modernising NPS I presented previously is soon to be rendered inoperable, though Microsoft have postponed their deadline multiple times and it now sits at Feb 2025, a full two years later than originally advertised. In this post I share an update that makes it compliant with these changes and outline my current efforts to find a better way forward.
Bailing out a sinking ship 🪣
When I started this saga a few years ago, I wanted to find a way to keep NPS afloat because it’s essentially free if you’ve already got on-prem servers (and nobody loves free more than education folk!). I realise now that the amount of effort involved in retrofitting compatibility to this relic of the pre-cloud era and the increasing complexity of the workarounds needed to make it just-about-work skews its value proposition way into the negative. While my team and I have made it work and we are continuing to use it in production, this is as far as I’m going with my efforts to bail it out.
The device dilemma
The only way to keep NPS in play after Microsoft’s cut-off is to have strong mappings in place on certificates proffered by supplicants. This is straightforward for user certs since user account objects exist in AD and the SID of the object is synced to Azure AD. SCEPman can read this when issuing certs from its cloud CA to ensure they have matching SID extensions and will thus pass muster with NPS. While this is fantastic, we can’t authenticate a user until we’ve first authenticated their device (otherwise they can’t log in to get their certificate in the first place) and that brings us back to Azure AD / Entra-joined devices not existing in on-prem AD and thus not being addressable by NPS.
In the original process we created a ‘ghost’ computer account object in AD and a mapping was achieved via matching it with the name of an issued certificate. This was advantageous as all issued certificates would match for the lifetime of a device since they would always be issued to its name.
Sadly this mapping fails under the new requirements, which need associations to be unique, i.e. some detail from a specific issued certificate needs to be stored in the computer account object in AD such that only it will match. Where this cannot be done automatically, Microsoft says:
we recommend that you create a manual mapping by… adding the appropriate mapping string to a users altSecurityIdentities attribute in Active Directory.
So to comply, we need to fetch certificates issued from our CA, match these to our ghost devices in AD and then copy the serial number into the altSecurityIdentities attribute – and when a device renews its cert, we need to repeat this within a short enough window that authentication doesn’t fail.
NPS AADJ sync v2
The result of our extensive tinkering is this updated script which does exactly this, as well as providing a mechanism for alerting when a sanity check fails (e.g. a device is missing) or a short-life certificate is detected.
There’s two APIs that we can use for fetching cert details; managedAllDeviceCertificateState and deviceConfigurationsAllDeviceCertificates. The latter has no documentation and the former is beta and bears the caveat of “production use is not supported”. They both work currently and we’re using the former in the script but that might need to change in future. They also both include the attributes we need for mapping –
certificateSerialNumber – as well as two we need for filters,
certificateRevokeStatus (limit to current certs) and
certificateIssuerName (limit to SCEPman certs). Combined, these allow a basis for comparison with AD records.
The end result is this amendment to the former process:
The ghost object automation process run by the script not only creates the computer account object in AD but with each subsequent routine execution compares its stored certificate serial with the serial of the most recent unrevoked SCEPman certificate issued in Intune and updates it accordingly.
Herein lies the rub, since it’s difficult to predict exactly when devices will renew their certificates (they start trying with 10 percent duration remaining) and the window between renewal (when the device starts using its new cert) and update (when AD knows about it) can result in network unavailability for a device, but with the script’s alerting of soon-to-be expired certs, it’s at least possible to be prepared for this. We have now been running this for over 6 months in a production environment and it has managed renewals without issues in most cases.
As I have already said, NPS may be free (or at least a sunk cost) but licensing is far from the only expense involved in maintaining an authentication service and while this script works currently, it relies on beta endpoints and introduces a great deal of complexity to fulfil Microsoft’s requirements of strong mappings. I do not see this as sustainable in the long term in a production environment so have been investigating two promising alternatives.
This is an open-source RADIUS server and would be easy to set up via Docker on multiple servers for redundancy. It would need a configuration supporting mixed CAs since SCEPman community edition cannot be used to sign the RADIUS server cert. In the same way as NPS uses its own CA, FreeRADIUS would need to use a self-signed certificate but also accept SCEPman’s CA for clients. It would simply authorise any certificates for users or devices signed by the trusted CA. I am not pursuing this currently but would be very interested in a writeup from anyone else that has managed it.
Mist Access Assurance
This is a subscription-based cloud NAC which is exactly what I set out to avoid, however it is priced at such a reasonable point for education and is so comprehensive, simple and straightforward to integrate with SCEPman in a mixed CA mode that it is my leading contender currently. I’ll do a further post about it in detail at a later stage.