Certificate mapping for AAD Devices with AD accounts
Device certificate authentication to NPS (e.g. an 802.1x wireless network) requires the device to have a computer object in the on-premises Active Directory. This can be done using a script to get all Autopilot registered devices, and create an account in the local AD (see SysManSquad - Working around NPS limitations for AADJ Windows Devices) however the thumbprint of the device certificate needs to be added to the computer object's altSecurityIdentities attribute. While this can be ran as an hourly task, there is the risk of a device being unable to connect for up to an hour. Luckily through configuring auditing and a scheduled task triggered by an event being raised, we can perform this mapping immediately after certificate issue.
Pre-requisites for this post are:
- Intune Certificate Connector is configured
- Device PKCS certificate profile in Intune
- Script to create local AD computer objects for Autopilot devices
More information about these is available in my previous post, Intune: 802.1x Wi-Fi, NPS and user PKCS certificates.
Configure Auditing
In order to log the event when a certificate is issued, we need to enable auditing of success on object access. This can be done in the local security policy however I'd recommend using Group Policy, especially if you already have an audit policy in place. Make sure you do not have both basic and advanced auditing rules configured as they may conflict.
Run auditpol /get /category:* to confirm that auditing is enabled. You should see that Object Access - Certification Services has the value Success.
In the Certification Authority console, configure Auditing (in the CA Properties) and turn on Issue and Manage Certificate Requests.
Script
Download the Trigger-DeviceCertUpdate.ps1 script from my GitHub repository and save in a suitable location. This script will be called by the task scheduler every time event 4887 is logged. It takes several parameters:
- RequestID - from the event data
- Requester - the username of the account which requested the certificate, from the event data
- Subject - the subject that the certificate was issued to, e.g. CN=b9b7bab8-7edc-405d-ba05-9d59d97c823d, from the event data
- LogPath - the path to save logs, e.g. C:\Scripts\Logs
- CertAuthorityName - the name of the CA to target, e.g. lab-LAB-SRV-DC03-CA
- IntuneCertUsername - the username that your Intune requested certificates are requested by. You would have entered this when configuring the Intune Certificate Connector.
It then gets the certificate from the CA based on the Request ID, and extracts the thumbnail. Finally it adds this to the computer object's altSecurityIdentities attribute, which is required for device certificate authentication to work.
Scheduled Task
Create a new scheduled task on the server(s) which will be issuing certificates. Configure the following settings:
- General Tab
- Run as: SYSTEM (or a user account with sufficient rights to query the CA and update computer objects in AD)
- Run whether user is logged on or not
- Triggers tab
- Begin the task: On an event
- Log: Security
- Event ID: 4887
- Actions tab
- Start a program: powershell.exe
- Arguments: -file C:\Scripts\Trigger-DeviceCertUpdate.ps1 -RequestID "$(RequestId)" -Requester "$(Requester)" -Subject "$(Subject)" -LogPath "C:\Scripts\Logs" -CertAuthorityName "lab-LAB-SRV-DC03-CA" -IntuneCertUsername "LAB\intunecert"
- Settings tab
- If the task is already running: Run a new instance in parallel
- If the task is already running: Run a new instance in parallel
This will not work currently - as we need to pass the RequestId, Requester and Subject from the event data into the task. This cannot be done in the GUI however it is possible by editing the task XML.
Export the task, and edit the XML file in a text editor.
Underneath the Subscription node, add the following:
<ValueQueries>
<Value name="RequestId">Event/EventData/Data[@Name="RequestId"]</Value>
<Value name="Requester">Event/EventData/Data[@Name="Requester"]</Value>
<Value name="Subject">Event/EventData/Data[@Name="Subject"]</Value>
</ValueQueries>
Your XML should look something like this:
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2024-08-30T22:28:00.8434586</Date>
<Author>LAB\kn</Author>
<Description>When an Intune cert is issued to a device, this task calls the script to add the certificate thumbprint to the device object's altSecurityIdentifier attribute. Needs object access auditing turned on in security policy, and certificate issue auditing turned on in the CA.</Description>
<URI>\Intune Cert Issued</URI>
</RegistrationInfo>
<Triggers>
<EventTrigger>
<Enabled>true</Enabled>
<Subscription><QueryList><Query Id="0" Path="Security"><Select Path="Security">*[System[EventID=4887]]</Select></Query></QueryList></Subscription>
<ValueQueries>
<Value name="RequestId">Event/EventData/Data[@Name="RequestId"]</Value>
<Value name="Requester">Event/EventData/Data[@Name="Requester"]</Value>
<Value name="Subject">Event/EventData/Data[@Name="Subject"]</Value>
</ValueQueries>
</EventTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>S-1-5-18</UserId>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>Parallel</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Command>
<Arguments>-file C:\Scripts\Trigger-DeviceCertUpdate.ps1 -RequestID "$(RequestId)" -Requester "$(Requester)" -Subject "$(Subject)" -LogPath "C:\Scripts\Logs" -CertAuthorityName "lab-LAB-SRV-DC03-CA" -IntuneCertUsername "LAB\intunecert"</Arguments>
</Exec>
</Actions>
</Task>
Delete your original scheduled task, and import your XML file.
Testing
To test everything is working, filter the Security event log for ID 4887 and watch for new events. Once a new event appears, check the log file generated by the script (these are in a format that can be opened with CMTrace). If certificates are being issued but the event is not being logged, make sure that your audit settings are not being overwritten (e.g. group policy overwriting local security policy, or having both advanced auditing and basic auditing configured with conflicting settings). Finally, check the properties of the computer object in AD to verify the certificate thumbprint has been added.