How to Congure Secure LDAP (LDAPS) in Active Directory
with Let’s Encrypt
AN ESSENTIAL PART OF HARDENING AN ACTIVE DIRECTORY
ENVIRONMENT IS CONFIGURING SECURE LDAP
An essential part of hardening an Active Directory environment is conguring Secure LDAP
(LDAPS). When LDAPS is enabled, LDAP trac from domain members and the domain controller
is protected from prying eyes and meddling thanks to Transport Layer Security (TLS). While the
insecure LDAP protocol can provide integrity (prevents tampering) and condentiality (prevents
snooping), it is no match for TLS, which is the industry standard for security.
Just like websites secured with HTTPS, LDAPS requires X.509 certicates signed by a trusted
root certicate authority to function properly. Chances are, you have heard about Let’s Encrypt,
which is a popular certicate authority trusted by default in all browsers. Well, here is some
good news: Let’s Encrypt is completely free, and it also works for LDAPS!
2
How to Congure Secure LDAP (LDAPS) in Active Directory with Let’s Encrypt
Private Certicate Authority
Active Directory Certicate Services (AD CS) is the most common way to create a private certicate authority
inside a Windows network, but only domain-joined machines are automatically congured for trust. Any other
device on your network (macOS, Linux, or even a smartphone!) will not validate the LDAPS certicate, unless the
private certicate authority is installed in the system’s trusted root certicates. Even then, all devices need to use
the internal DNS servers. Otherwise, it may not be possible to connect to the LDAPS server using the same name
found inside the server certicate, thus causing a validation failure.
The Importance of DNS
All certicates contain a common name that must match the expected name, in order to be considered valid.
For example, when loading “google.comin a browser, the hostname is resolved using public DNS servers, and
the certicate contains a matching name. The certicate authority that signed the certicate for google.com
(GlobalSign) had to validate ownership of the domain before doing so. This process can be manual or automated,
but it always relies on a form of challenge that the domain owner must complete to prove that it has control over
the DNS domain name. Since private DNS servers are excluded for obvious reasons, the only way to use a public
certicate authority like Let’s Encrypt for LDAPS is to ensure we can request a certicate for a public DNS domain
name that will match the name of the domain controller.
Naming Your Domain Wisely
If you have ever tried to follow a “Getting Started Guide to Promoting Windows Server to a Domain Controller,”
then this is usually the part where you might feel a bit lost. There are many names to choose from, and all of them
look very important and impossible to change afterwards if you get it wrong. Trust me: I have been there, done
that! If you do not have a domain name available, then you can simply buy one from Namecheap or your favorite
registrar. For this example, let us be creative and use a ctional company called “IT Help Ninja” using the “it-help.
ninja” internet domain:
Company Name: IT Help Ninja
DNS Domain Name: ad.it-help.ninja
NETBIOS Domain Name: IT-HELP
3
How to Congure Secure LDAP (LDAPS) in Active Directory with Let’s Encrypt
Domain Controller Name: IT-HELP-DC
Domain Controller FQDN: IT-HELP-DC.ad.it-help.ninja
Domain Administrator (UPN): [email protected]
Domain Administrator (NETBIOS): IT-HELP\Administrator
Following Active Directory naming best practices, the best approach is to use a short subdomain of an internet
domain, such as “ad,” “corp,” or “internal.” Using unassigned public domain names like “.local” or “.loc” is not
recommended, because there is no protection against future registration of the domain name. The NETBIOS
name is there for backward compatibility, and is limited to 15 characters, so keep it short. The name of the domain
controller is most often just the NETBIOS name with “-DC” as a sux.
Promoting Windows Server to Domain Controller
Note: If you already have a properly congured domain controller, then you can skip this step. If you have no prior
experience creating a domain controller, or could gladly use a refresher, then this section is for you.
The recommended environment is a Windows Server 2019 Core VM with a public IP address. The Windows
Server GUI is not required, and so installing it is a personal choice.
Start by reviewing the machine conguration:
The machine is congured with the intended nal name (IT-HELP-DC).
The machine is congured with a static IP address on the local network.
Once promoted to a domain controller, the machine name cannot be changed. Since the domain controller
becomes a DNS server, it needs to be reachable using a static IP by other machines inside the domain.
Install the Active Directory Domain Services feature, including the management tools:
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools
Create the new Active Directory forest with the Install-ADDSForest command. Do not merely copy/paste this
4
How to Congure Secure LDAP (LDAPS) in Active Directory with Let’s Encrypt
line! Change the parameter values to t your intended domain name. If you use the wrong forest name, then the
easiest way to x the problem is to create a new VM and start over from scratch.
Install-ADDSForest -DomainName «ad.it-help.ninja» -DomainNetbiosName «IT-
HELP» -InstallDNS
You will be prompted for the Directory Services Restore Mode (DSRM) password during the installation
(“SafeModeAdministratorPassword”). Use a password manager to generate a strong password, and then save it
for later. The machine will reboot to complete the installation process. If the next remote login appears stuck on
“Please wait for Group Policy Client,” just wait a little longer it is normal.
Congratulations, you now have a domain controller! If this is your rst time doing it, welcome to the club.
Requesting Certicate from Let’s Encrypt
Obtaining a certicate from Let’s Encrypt is always done using the ACME protocol. This automated process can
use two dierent ways of validating domain ownership:
DNS challenge
HTTP challenge
The DNS challenge involves setting DNS records to a special value, while the HTTP challenge requires hosting a
le with a special value at a known path. The downside of the DNS challenge is that the application needs write
access to the DNS records, and the downside of the HTTP challenge is that the application needs access to the
HTTP standard port 80. Since domain controllers generally run a restricted amount of services, we can aord the
luxury of using TCP port 80 for the ACME challenge.
Add a Windows rewall exception for inbound trac on TCP port 80:
netsh advrewall rewall add rule name=»HTTP inbound» dir=in action=
allow protocol=TCP localport=80
Do not forget to add a rewall exception in other places that require it, such as the Azure Network Security Group
(NSG), if this is an Azure VM. Verify that no other program is currently listening on TCP port 80:
5
How to Congure Secure LDAP (LDAPS) in Active Directory with Let’s Encrypt
netstat -an | ndstr :80
If another program such as Internet Information Services (IIS) is running and using the port, the ACME HTTP
challenge can still be completed using a special reverse proxy rule that is not covered in this guide.
Install the Posh-ACME PowerShell module:
Install-Module -Name Posh-ACME -Scope AllUsers
The certicate common name has to match the domain controller FQDN. Since Let’s Encrypt will need to resolve
the same FQDN, do not forget to update your external DNS conguration accordingly. This means adding a DNS A
record for “IT-HELP-DC” under “ad.it-help.ninja” that points to the domain controller public IP address. Make sure
that the domain controller FQDN can be resolved before continuing:
New-PACerticate «IT-HELP-DC.ad.it-help.ninja» -Plugin WebSelfHost -AcceptTOS
Wait a few minutes for the challenge to complete. If it succeeds, then you should be able to get the last certicate
object using the Get-PACerticate command, and nd the path on disk for the les:
$Certicate = Get-PACerticate
$CertPath = Split-Path -Path $Certicate.PfxFullChain -Parent
If you can nd the certicate les, congratulations! You now have a valid certicate usable for LDAPS.
Conguring LDAP Server Certicate
Did you think it was over already? Not so fast! We have a certicate, but the LDAP server needs to be congured
to use it. This part is, unfortunately, a bit complicated unless you have the right code snippets available to do it, so
keep a link to this blog post as a reference.
6
How to Congure Secure LDAP (LDAPS) in Active Directory with Let’s Encrypt
Let us begin by importing the server certicate into the local machine certicate store:
$CerticatePassword = $(ConvertTo-SecureString -AsPlainText ‘poshacme’ -Force)
$ImportedCerticate = Import-PfxCerticate -FilePath $Certicate.PfxFullChain `
-CertStoreLocation ‘cert:\LocalMachine\My’ -Password $CerticatePassword
$CerticateThumbprint = $ImportedCerticate.Thumbprint
The default password on certicates obtained using Posh-ACME is ‘poshacme’, but it can be changed. Certicate
stores on Windows have a physical location inside the Windows registry. PowerShell oers a nice interface over
some certicate stores, but not the one used by the LDAP server (NTDS). The trick is to import the certicate into
a temporary store, then copy it to the destination store using the Windows registry paths:
$LocalCertStore = ‘HKLM:/Software/Microsoft/SystemCerticates/My/Certicates’
$NtdsCertStore = ‘HKLM:/Software/Microsoft/Cryptography/Services/NTDS/
SystemCerticates/My/Certicates’
if (-Not (Test-Path $NtdsCertStore)) {
New-Item $NtdsCertStore -Force
}
Copy-Item -Path «$LocalCertStore/$CerticateThumbprint» -Destination $NtdsCertStore
The certicate thumbprint is the signature or hash of the certicate used as the name inside the registry store key
structure. You do not need to know the details, other than that you need to nd the right thumbprint to copy the
right certicate. Run the following commands to tell the LDAP server to renew its server certicate conguration
and apply the changes:
$dse = [adsi]’LDAP://localhost/rootDSE’
[void]$dse.Properties[‘renewServerCerticate’].Add(1)
$dse.CommitChanges()
At this point, the LDAP server should now properly respond to a TLS handshake over TCP port 636 (standard
LDAPS port). Make sure that the rewall is properly congured, then test the TLS handshake using OpenSSL:
7
How to Congure Secure LDAP (LDAPS) in Active Directory with Let’s Encrypt
openssl s_client -connect IT-HELP-DC.ad.it-help.ninja:636 -showcerts
If it works, then OpenSSL should validate the certicate automatically, and show Let’s Encrypt as the certicate
authority. The chain should contain the Let’s Encrypt intermediate CA, and the server certicate with the FQDN of
your domain controller. If validation fails, take a closer look at the errors returned by OpenSSL.
Closing Thoughts
Considering the importance of Secure LDAP for the future of Active Directory, it is surprising to nd out how
dicult it is to properly congure the LDAP server to use a certicate. A lot of online guides use ldp.exe to test
LDAP connectivity, but it has the unfortunate limitation of returning the same error when certicate validation fails
as it does when the server is unreachable.
As if that was not enough, there is no way to select which certicate will be used by the LDAP server inside the
NTDS certicate store. And so, the most foolproof way to do it is to delete all other certicates except the one that
you wish to use. Let’s Encrypt certicates are only valid for three months, and so it is recommended to create an
automated script run to handle the renewal.
Please share this blog if you found it helpful, but more importantly, we would like to know more about your
experience conguring Secure LDAP in your Active Directory environment. Please comment below!