Secure Azure AD connect

Let’s talk about Azure AD Connect. This is an application that connects your local Active Directory with the Azure Active Directory or rather synchronizes the objects. This is an application that connects your local Active Directory to the Azure Active Directory, or rather, synchronizes the objects. Sounds like a pretty important part of the whole cloud journey, doesn’t it? Of course, because it brings the possibility of SSO or not having to maintain users separately, just to name a few benefits.

Today we will not talk about the features but about how to install it safely. To do this, we will look at which user this should run as and what permissions that user must have. Of course, you can easily install this with a domain admin and synchronize all AD objects, but I advise you not to do this! So the best place to start is with the account.

group managed service account (gMSA)

The AD Connect service should always, and I mean always, be installed with a group managed service account (gMSA). Now you might ask why, well with gMSA the OS or rather the DCs handle the password, you don’t need to know it. Besides, you can delegate the management of these accounts, so it makes sense, right? The following 3 lines of code can create such an account.

Import-module ActiveDirectory
New-ADServiceAccount -Name "aadconnect" -Enable $true -DNSHostName {SERVERNAME}
Set-ADServiceAccount -Identity "aadconnect" -PrincipalsAllowedToRetrieveManagedPassword {SERVERNAME}
Install-ADServiceAccount "aadconnect"

The created account is located in the Managed Service Accounts OU in the root directory.

When you install Azure AD Connect, you can now enter this user in the Customize Setup settings.

AD Account

During setup, you should select only those OUs that really have Azure AD-relevant objects that should be included in the synchronization. For example, you do not need to synchronize local NTFS groups or accounts which are never used in the cloud. Reduces your Attack Surface as much as possible, even here. Also, when adding the local domains, you need to specify an AD user who is responsible for reading and writing all AD objects. This account should have only the rights he needs for his activity as AAD sync user, least privilege! The following script can be used to assign permissions per OU.

import-module ActiveDirectory
$DN = "OU=aad,DC=collfuse,DC=com"
$account = "collfuse\srv-aadconnect"

Function set_writeback_perm {
    $sc = (Get-ADRootDSE).SchemaNamingContext
    $ob = "CN=ms-Exch-Schema-Version-Pt," + $sc
    $ExchangeSchemaVersion = (Get-ADObject $ob -pr rangeUpper).rangeUpper
    if ($ExchangeSchemaVersion -ge 15317)
        {
        Write-Host ("msDS-ExternalDirectoryObjectID") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msDS-ExternalDirectoryObjectID;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchArchiveStatus") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchArchiveStatus;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchBlockedSendersHash") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchBlockedSendersHash;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchSafeRecipientsHash") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchSafeRecipientsHash;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchSafeSendersHash") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchSafeSendersHash;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchUCVoiceMailSettings") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchUCVoiceMailSettings;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchUserHoldPolicies") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchUserHoldPolicies;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("proxyAddresses-user") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;proxyAddresses;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("proxyAddresses-group") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;proxyAddresses;group'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("proxyAddresses-contact") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;proxyAddresses;contact'"
        Invoke-Expression $cmd | Out-Null
        }
    else
        {
        Write-Host ("msExchArchiveStatus") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchArchiveStatus;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchBlockedSendersHash") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchBlockedSendersHash;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchSafeRecipientsHash") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchSafeRecipientsHash;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchSafeSendersHash") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchSafeSendersHash;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchUCVoiceMailSettings") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchUCVoiceMailSettings;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("msExchUserHoldPolicies") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;msExchUserHoldPolicies;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("proxyAddresses-user") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;proxyAddresses;user'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("proxyAddresses-groupe") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;proxyAddresses;group'"
        Invoke-Expression $cmd | Out-Null

        Write-Host ("proxyAddresses-contact") -ForegroundColor Yellow
        $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;proxyAddresses;contact'"
        Invoke-Expression $cmd | Out-Null
        }
}

Function set_exch_perm {
    Write-Host ("Reset Password") -ForegroundColor Yellow
    $cmd = "dsacls '$DN' /I:S /G '`"$account`":CA;`"Reset Password`";user'"
    Invoke-Expression $cmd | Out-Null

    Write-Host ("Change Password") -ForegroundColor Yellow
    $cmd = "dsacls '$DN' /I:S /G '`"$account`":CA;`"Change Password`";user'"
    Invoke-Expression $cmd | Out-Null

    Write-Host ("pwdLastSet") -ForegroundColor Yellow
    $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;pwdLastSet;user'"
    Invoke-Expression $cmd | Out-Null

    Write-Host ("lockoutTime") -ForegroundColor Yellow
    $cmd = "dsacls '$DN' /I:S /G '`"$account`":WP;lockoutTime;user'"
    Invoke-Expression $cmd | Out-Null 
}
# call functions
    set_exch_perm
    set_writeback_perm 

The variables “$DN” & “$account” must be adapted to your own environment. After running the script, the new OU can be added to the synchronization via the setup.

One small addition, if you don’t always want to/can’t wait for the default time to sync, you can use the following PowerShell command.

$syncstate= (Get-ADSyncScheduler).SyncCycleInProgress

if ($syncstate-like "false") {
    Start-ADSyncSyncCycle -PolicyType Delta
}

That’s it so far, stay tuned and see you soon!

** midjourney string “secure data connection