Skip to content
View in the app

A better way to browse. Learn more.

Learn more

Stop binding your VPN to a real person's AD account

Featured Replies

The VPN, the remote access portal, the copier that does scan-to-email, the wiki, the helpdesk system. Anything that looks people up in AD needs an account to bind with, and in a lot of environments we inherit, that account belongs to an actual person. Usually whoever set it up. It works fine until they change their password at the 90-day prompt, mistype it on their phone and lock themselves out, or leave. Then everybody's logins to that system break at once.

It's messy in quieter ways too. The logs show that person "logging in" thousands of times a day, and because those accounts are often admins, the appliance ends up holding admin credentials. What we do instead is boring on purpose. One dedicated service account per system, minimum rights, a long random password, no interactive logon, and a written rotation process.

The one we caught right before a handover

Before handing a client environment over to another provider, we audited every integration and found the remote access portal binding to AD as one of our own engineers, by name. The day that account got disabled, nobody at the client would have been able to connect remotely. We created a dedicated read-only bind account, tested it with ldapsearch, switched the portal over, confirmed staff could log in, and added it to the handover documentation. Ten minutes of work, and the new team didn't spend their first morning on a remote access outage.

To do this you'll need rights to create OUs, users and GPOs, a password manager or vault for the generated password, and access to the config of whatever system is going to bind.

Give service accounts their own OU

Keeping them out of your normal user OUs means user GPOs, password policies and cleanup scripts don't touch them by accident.

New-ADOrganizationalUnit -Name "Service Accounts" -Path "OU=Admin,DC=contoso,DC=local" -ProtectedFromAccidentalDeletion $true

Create the account

Generate the password in your password manager first. We go 32 characters or more. Name the account so whoever finds it in two years knows what it's for, and put the owner and runbook in the description.

$pw = Read-Host "Password for svc-vpn-ldap" -AsSecureString

New-ADUser -Name "svc-vpn-ldap" `
    -SamAccountName "svc-vpn-ldap" `
    -UserPrincipalName "svc-vpn-ldap@contoso.local" `
    -Path "OU=Service Accounts,OU=Admin,DC=contoso,DC=local" `
    -AccountPassword $pw `
    -Enabled $true `
    -PasswordNeverExpires $true `
    -CannotChangePassword $true `
    -Description "LDAP bind for remote access portal. Owner: IT. See runbook SVC-001."

"Password never expires" is a deliberate trade-off. An expiring password on a service account causes exactly the outage we're trying to avoid. The compensating controls are the long random password and the rotation process further down.

Keep it to Domain Users

For read-only lookups (authenticate a user, read their group memberships), plain Domain Users membership is enough, since authenticated users can read most user and group attributes by default. Please don't add it to Domain Admins or any admin group "to make it work". If an app genuinely needs to write, like a password self-service tool, delegate that specific permission on the specific OU and nothing else.

Block interactive logon

A bind account should never be able to sit at a desktop or open an RDP session. Make a group, something like GRP-Deny-Interactive-Logon, and add the account. Then in a GPO linked at the domain level (or the OUs holding your servers and workstations), go to Computer Configuration, Policies, Windows Settings, Security Settings, Local Policies, User Rights Assignment and add the group to Deny log on locally and Deny log on through Remote Desktop Services.

Don't add it to Deny access to this computer from the network on your DCs. LDAP binds are network logons, so that breaks the one thing the account exists to do.

Use TLS, and test before you touch the appliance

Set the appliance to LDAPS (636) or StartTLS if it supports it. A simple bind over plain 389 sends the password in clear text. Before I change anything on the device, I test the bind from any Linux box with the OpenLDAP client tools:

ldapsearch -H ldaps://dc01.contoso.local -D "svc-vpn-ldap@contoso.local" -W \
  -b "DC=contoso,DC=local" "(sAMAccountName=jdoe)" memberOf

If that returns the user's groups, the account works. Then update the appliance, test a real user's login, and only then remove the old credentials.

Before you disable the old shared account, watch the DC logs for its logon attempts for a few days. There's always a second device nobody remembered, and in my experience it's usually a scan-to-email printer.

How to tell it worked

  • Users can log in to the system that binds to AD
  • Get-ADUser svc-vpn-ldap -Properties LastLogonTimestamp, PasswordNeverExpires, MemberOf shows recent activity and only Domain Users
  • Trying to RDP or log on locally as the service account is refused
  • The old named account no longer shows bind activity in the DC security logs (look for its logons, events 4624 and 4625, from the appliance's IP)

Write it down so rotation isn't scary

For each service account we record what uses it and where the credential is entered (device, admin URL, config file), who owns the integration, where the password is stored, and when it was last rotated along with the steps. Rotation then is just generating a new password, updating the vault, setting it in AD, updating each consumer and testing. One account per system keeps that list short, and one rotation can't break five things.

People sometimes ask why not use a gMSA. They're great for Windows services, but the password is retrieved by Windows hosts, so a VPN appliance or printer can't use one. For appliances, a normal user account managed like this is the right tool.

Create an account or sign in to comment

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.