Active Directory Domain Join Delegation

The trigger to write this article was a troubleshooting session with a client that had built an automation process to deploy Windows Server and RedHat Enterprise Linux virtual machines on Azure. One of the steps of the provisioning process was to join the machine to the IaaS Active Directory Domain that was deployed on Azure and for this, an Active Directory account was required.

Following the least previlege principle, the account used in the automation processes to join machines to the domain was a plain account that could indeed perform this operation. After some successfull joins however, the process started encountering errors when trying to join machines to the domain.

As it turns out, the architects and security engineers had missed the fact that plain Active Directory accounts have the ability to only join a specific number of machines to the domain. When the automation reached that number, the process started to fail.

To further troubleshoot the issue, we tried to join the machine manually to the domain and got the error:

that clearly states that we've reached the Machine Account Quota, but I'll explain it in a second.

Let's first talk about the permissions related to joining computers to the domain. First there's the Add Workstation to the Domain setting in the Default Domain Controllers Policy:

By default, this setting is configured with the Authenticated Users group that means that all the user accounts that have been successfully authenticated have the ability to join computers to the domain.

The objects that have been granted the above permission are however limited by the Machine Account Quota value. Although the users have the ability to join computers to the domain, each user can create up to a certain number of computer accounts in Active Directory. This number is stored in the ms-DS-MachineAccountQuota atribute which has a default value of  10.

To get the value currently set on your environment, run the following command in a PowerShell window:

Get-ADDomain | Get-ADObject -Properties 'ms-DS-MachineAccountQuota' 

The output will be something like:

PS C:\> Get-ADDomain | Get-ADObject -Properties 'ms-DS-MachineAccountQuota'

DistinguishedName         : DC=LAB,DC=local
ms-DS-MachineAccountQuota : 10
Name                      : LAB
ObjectClass               : domainDNS
ObjectGUID                : e2b9879e-a356-45ba-8acc-1dd0e3ccfb9b

PS C:\>

To keep track of the computer accounts that have been created by each user, the attribute mS-DS-CreatorSID is populated with the SID of the account used to join the machine to the domain.

The easiest way to get the account that joined a machine to the domain is to get the SID of the user and then query for the machines that have that value in the CreatorSID attribute:

$server = Get-ADComputer "WebServer01" -Properties "mS-DS-CreatorSID"

Get-ADUser $server.'mS-DS-CreatorSID'

You should expect a user object as output:

DistinguishedName : CN=Domain Join,OU=Users,OU=LAB,DC=LAB,DC=local
Enabled           : True
GivenName         : Domain
Name              : Domain Join
ObjectClass       : user
ObjectGUID        : f345a3a2-6e4f-4159-bda6-cc7267b640c1
SamAccountName    : domainjoin
SID               : S-1-5-21-2384431003-3405447889-4141679475-3651
Surname           : Join
UserPrincipalName : domainjoin@LAB.local

The mS-DS-CreatorSID attribute can also be used to get all the computer accounts that have been created by a specific user, like:

$user = Get-ADUser domainjoin

Get-ADComputer -LDAPFilter "(mS-DS-CreatorSID=$($user.SID))" |
    Format-Table -Property Name,ObjectGUID

That will output an array of computer objects:

Name        ObjectGUID                          
----        ----------                          
WEBSERVER01 519b2c10-a3cd-40e5-9ca1-dbeb1bb9c67f
WEBSERVER02 c892c775-f076-46f8-98ee-91e1d4ae6b3c
WEBSERVER03 598c1b96-cecc-4fcc-9f1f-c1fb30655efb
WEBSERVER04 b0687534-005f-467d-9210-d5801728ed29
WEBSERVER05 f91751ca-fbfd-4ce6-8e05-05755ee640b9
WEBSERVER06 1b62f2cb-8bc6-4f61-b1ec-d99dd6fbd820
WEBSERVER07 8b2e6272-f4d6-45ca-8800-3dd2df9d9cb7
WEBSERVER08 5fa862a4-6ab1-4453-be55-6b812f161ee8
WEBSERVER09 5ec3b4a0-f6d5-4c4a-9cd2-5e087d27c5de
WEBSERVER10 c69917d5-adde-4422-9aee-31b4d4e086bb

There's a caveat here, not all computer accounts have a populated mS-DS-CreatorSID attribute. This attribute has a value only when no permissions have been assigned to the account that was used join the computer to the domain!

So, what do we do to properly configure the automation and avoid this situation? You could increase the value of the ms-DS-MachineAccountQuota attribute, but this would increase the limit for all users in the domain!

The second thing that comes in mind is to add the user account used to join the machines to the domain to the Domain Admins group. This way, our account would not hit the limit and will be able to join as many machines as needed. This is not a recommended approach since we'll be granting almost full access to the entire domain to an account that may fall into the wrong hands easily!

The proper way to work around this limit is to grant the Create Computer Objects permission to the account used for joining the machines on the Computers container. This will again remove the limitation imposed by the ms-DS-MachineAccountQuota and allow you to join as many machines as you want. In case you were wondering why the Domain Admins group can bypass the quota and group policy, this is becuase this group has enherited permissions to create computer object (amongst others) to the entire directory!

Please note here that the mS-DS-CreatorSID will not be populated on the computer account, since our user has been delegated the permission!

It would probably be a good idea - since we're on the subject - to rectrict the accounts the have the permissions to add computers to the domain from the Authenitcated Users to a special security group!

So, to sum it up, you can restrict the permission to join machines to the domain using the Add workstations to domain group policy setting and the number of machines will be limited by the machine account quota value. If you delegate the permission or manually add it using the security tab, both of the above will be bypassed.

My PowerShell module for Active Directory includes the Get-ActiveDirectoryComputerAccountCreator function that will query Active Directory and return the object that created the specific computer account, starting from version 1.7.0.

Popular posts from this blog

Domain Controller Machine Password Reset

Configuring a Certificate on Exchange Receive Connector

Verbose Parameter Passing to cmdlet inside Function