Stronghold connects to Active Directory (AD) over LDAP: it verifies domain user passwords, resolves their groups, including nested ones, and assigns policies by group. The LDAP secrets engine with the ad schema changes passwords of domain service accounts.
Goal
After the setup:
- AD users log in to Stronghold with their domain accounts through the
ldapmethod over LDAPS. - Stronghold permissions are assigned by AD group membership, including nested groups.
- Stronghold rotates AD service account passwords and hands them out to applications.
Prerequisites
Before you start, prepare the following:
- An AD domain, for example
corp.example.comwith domain controllersdc01.corp.example.comanddc02.corp.example.com. - LDAPS (port 636) enabled on the domain controllers with a certificate issued by the corporate CA.
- The root CA certificate in PEM (Base-64) format, for example
corp-ca.pem. - Network access from Stronghold nodes to the domain controllers on port 636.
- A Stronghold token with permissions to configure auth methods, secrets engines, policies, and Identity.
The examples assume users are in OU=Users,DC=corp,DC=example,DC=com, groups in OU=Groups,DC=corp,DC=example,DC=com, and service accounts in OU=Service Accounts,DC=corp,DC=example,DC=com. Replace the DNs with your own.
Step 1. Prepare AD accounts
Create the accounts that Stronghold uses in AD and check the directory search.
Create a
svc-stronghold-bindaccount for searching users and groups. Regular domain user permissions to read the directory are enough. Set a non-expiring password.If you plan to rotate passwords, create a
svc-stronghold-rotatoraccount and delegate the Reset password permission on the service account OU to it. Do not grant it domain administrator rights.Check search over LDAPS:
LDAPTLS_CACERT=./corp-ca.pem ldapsearch -x -H ldaps://dc01.corp.example.com -D "svc-stronghold-bind@corp.example.com" -W -b "OU=Users,DC=corp,DC=example,DC=com" "(sAMAccountName=jsmith)" sAMAccountName userPrincipalName memberOf
Step 2. Configure the LDAP method
Enable the ldap method, connect it to the domain controllers and check login.
Enable the auth method:
d8 stronghold auth enable ldapConfigure the connection. Users log in with
sAMAccountName; groups are resolved including nesting through theLDAP_MATCHING_RULE_IN_CHAINrule (OID1.2.840.113556.1.4.1941):d8 stronghold write auth/ldap/config url="ldaps://dc01.corp.example.com:636,ldaps://dc02.corp.example.com:636" certificate=@corp-ca.pem insecure_tls=false starttls=false binddn="CN=svc-stronghold-bind,OU=Service Accounts,DC=corp,DC=example,DC=com" bindpass='<BIND_PASSWORD>' d8 stronghold write auth/ldap/config userdn="OU=Users,DC=corp,DC=example,DC=com" userattr="sAMAccountName" groupdn="OU=Groups,DC=corp,DC=example,DC=com" groupfilter="(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))" groupattr="cn" username_as_alias=true<BIND_PASSWORD>is the password of thesvc-stronghold-bindaccount. The first command configures the connection, the second one configures the user and group search.Key parameters:
Parameter Value for AD urlComma-separated list of domain controllers, port 636. certificateCertificate of the root CA that issued the controller certificates. insecure_tls,starttlsfalseforldaps://. When connecting vialdap://on port 389, setstarttls=true.userattrsAMAccountName: the short login name, for examplejsmith.groupfilterFinds all groups the user belongs to directly or through nested groups. groupattrcn: the group name in Stronghold.Instead of
groupfilter, you can setuse_token_groups=true: Stronghold reads the user’s computedtokenGroupsattribute, which contains all security groups, including nested ones.To find users by UPN (
jsmith@corp.example.com), add theupndomainparameter to the configuration. Keepuserattr=sAMAccountName:d8 stronghold write auth/ldap/config upndomain="corp.example.com"The user still enters the name without the domain, for example
jsmith. Stronghold searchesuserdnasbinddnfor the object withuserPrincipalName=jsmith@corp.example.com, binds with the DN of the found object and uses this DN in the group search.A write to
auth/ldap/configchanges only the parameters passed in the command. The other parameters keep their current values.Check login:
d8 stronghold login -method=ldap username=jsmith
Step 3. Map AD groups to policies
For a single login method, LDAP method groups are enough. The group name must match the group’s cn in AD:
d8 stronghold write auth/ldap/groups/SG-Stronghold-Admins policies=admin
d8 stronghold write auth/ldap/groups/SG-Developers policies=dev-readIf AD groups are also used by other login methods, or you need to apply MFA to them, create external Identity groups:
GROUP_ID=$(d8 stronghold write -field=id identity/group name="ad-stronghold-admins" type="external" policies="admin")
LDAP_ACCESSOR=$(d8 stronghold auth list -format=json | jq -r '."ldap/".accessor')
d8 stronghold write identity/group-alias name="SG-Stronghold-Admins" mount_accessor="$LDAP_ACCESSOR" canonical_id="$GROUP_ID"For details on external groups, see Identity.
Step 4. Rotate service account passwords
The LDAP secrets engine with the ad schema changes passwords of AD service accounts and hands them out to applications.
AD allows changing a password (the unicodePwd attribute) only over a secure connection. Use ldaps:// or starttls=true.
Enable the secrets engine and configure it with the
adschema:d8 stronghold secrets enable ldap d8 stronghold write ldap/config url="ldaps://dc01.corp.example.com:636" certificate=@corp-ca.pem insecure_tls=false binddn="CN=svc-stronghold-rotator,OU=Service Accounts,DC=corp,DC=example,DC=com" bindpass='<ROTATOR_PASSWORD>' userdn="OU=Service Accounts,DC=corp,DC=example,DC=com" schema=ad<ROTATOR_PASSWORD>is the current password of thesvc-stronghold-rotatoraccount.Rotate the
svc-stronghold-rotatorpassword so that only Stronghold knows it:d8 stronghold write -f ldap/rotate-rootCreate a static role for the application service account:
d8 stronghold write ldap/static-role/svc-jenkins dn="CN=svc-jenkins,OU=Service Accounts,DC=corp,DC=example,DC=com" username="svc-jenkins" rotation_period="24h"The application reads the current password:
d8 stronghold read ldap/static-cred/svc-jenkins
For shared accounts lent to people for a limited time, use a library:
d8 stronghold write ldap/library/helpdesk service_account_names="svc-helpdesk1@corp.example.com,svc-helpdesk2@corp.example.com" ttl=2h max_ttl=8h
d8 stronghold write -f ldap/library/helpdesk/check-out
d8 stronghold write ldap/library/helpdesk/check-in service_account_names="svc-helpdesk1@corp.example.com"The service_account_names values are matched against the attribute set in the userattr parameter; for the ad schema it defaults to userPrincipalName, so use the full name such as svc-helpdesk1@corp.example.com.
Access policies for static-cred and library are similar to those in Integration with ALD Pro.
Verification
Check the result:
Log in as a user from a group nested in
SG-Stronghold-Adminsand check that the token got theadminpolicy:d8 stronghold login -method=ldap username=jsmith d8 stronghold token lookupRead the static role password and check the bind:
LDAPTLS_CACERT=./corp-ca.pem ldapsearch -x -H ldaps://dc01.corp.example.com -D "svc-jenkins@corp.example.com" -w '<STATIC_CRED_PASSWORD>' -b "DC=corp,DC=example,DC=com" -s base<STATIC_CRED_PASSWORD>is thepasswordvalue from theldap/static-cred/svc-jenkinsresponse.
Troubleshooting
On a bind error, AD returns code 49 and a subcode in the data field of the error message. The subcode indicates the cause.
| Symptom | Likely cause | What to do |
|---|---|---|
Invalid Credentials, data 52e | Wrong user password or bindpass | Check the password. After rotate-root, only Stronghold knows the binddn password. |
data 525 | User not found | Check userdn, userattr, or upndomain. |
data 775 | The account is locked in AD | Unlock it in AD. Also check the Stronghold lockout (lockout_threshold) described in LDAP auth method. |
data 533, data 532, data 701 | The account is disabled, or the password or account has expired | Enable the account or change the password in AD. |
x509: certificate signed by unknown authority | The CA certificate is missing or wrong | Pass the corporate root CA certificate in certificate. |
| Login succeeds but group policies are missing | groupfilter finds no groups, or group names do not match | Run ldapsearch with the (member:1.2.840.113556.1.4.1941:=<USER_DN>) filter. Group names in Stronghold must match cn. |
rotate-role returns Unwilling To Perform or Insufficient Access Rights | No secure connection, binddn lacks the Reset password permission, or the password does not meet the domain password policy | Use LDAPS, check the delegation, and configure a Stronghold password policy with the password_policy parameter. |
Cleanup
Disable the auth method and the secrets engine:
d8 stronghold auth disable ldap
d8 stronghold secrets disable ldapDisabling the secrets engine does not change passwords. Change the service account passwords with AD tools.