First public release. - docs: document the audit log, user offboarding, CSV export and the "require a reason for destructive actions" setting across README, docs/ and CLAUDE/AGENTS.md; note retention for panel_audit - docs: fill the publishing placeholders (repo URL, security contact, issue-template links) and add a semantic-versioning policy - move agent/contributor context into CLAUDE/ (AGENTS.md + a README); root CLAUDE.md is now a thin @-import pointer - add a favicon (shield-lock, matching the login screen) to the login page and the app layout - CHANGELOG: promote [Unreleased] to [1.0.0]; keep the earlier internal build as [0.1.0] Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UfuvfwexztdS7LDpGuKsuK
5.2 KiB
Active Directory setup
ADconsole needs three things from your directory: a service account to bind with, an encrypted channel (LDAPS/STARTTLS), and a login group whose members may use the panel. What the panel can actually change is governed entirely by AD delegation on that service account — grant only what you need.
1. Service account
Create a dedicated account, e.g. svc-adconsole:
- Password never expires, cannot change password, not a member of any privileged group by default.
- Deny interactive/RDP logon (it only needs "Access this computer from the network" to the DCs, i.e. LDAP bind).
- Put its DN in
LDAP_USERNAMEand its password inLDAP_PASSWORD.
Test the bind:
php artisan tinker
>>> \LdapRecord\Container::getConnection('default')->connect(); // no exception = OK
2. Encrypted transport (LDAPS / STARTTLS)
AD refuses password writes (unicodePwd) and other sensitive changes over an
unencrypted connection, so this is mandatory for anything beyond read-only use.
- LDAPS (recommended): ensure the DCs have a certificate with Server
Authentication EKU (AD CS "Domain Controller" / "Kerberos Authentication"
template auto-enrols this). Set
LDAP_SSL=true,LDAP_PORT=636. - STARTTLS:
LDAP_TLS=true,LDAP_PORT=389. - If the app host does not trust the issuing CA, set
LDAP_TLS_VERIFY=false(skips chain validation — acceptable on a trusted network, not ideal). To verify instead, install the internal root CA in the app host's trust store (/etc/ssl/certs,update-ca-certificates) and setLDAP_TLS_VERIFY=true.
Quick check from the app host:
openssl s_client -connect dc01.corp.example.com:636 -showcerts </dev/null
3. Base DN and OU layout
LDAP_BASE_DN is used by every module. If your users, computers and groups
live in sibling OUs, the base DN must be an ancestor of all three — normally the
domain root:
LDAP_BASE_DN="DC=corp,DC=example,DC=com"
LDAP_DEFAULT_USER_OU="OU=Staff,DC=corp,DC=example,DC=com"
LDAP_DEFAULT_COMPUTER_OU="OU=Workstations,DC=corp,DC=example,DC=com"
LDAP_DEFAULT_GROUPS_OU="OU=Security Groups,DC=corp,DC=example,DC=com"
A too-narrow base DN is the #1 cause of "the computers / groups list is empty".
4. Login group
AD_LOGIN_GROUP = the group whose members may sign in. Use the full DN:
AD_LOGIN_GROUP="CN=ADconsole Admins,OU=Security Groups,DC=corp,DC=example,DC=com"
Nested membership and the primary group are honoured
(App\Ldap\Rules\MemberOfLoginGroup). Empty value = nobody can log in. This is
an application gate only — it grants no directory rights.
5. Delegation — grant per feature
Delegate on the OUs you want ADconsole to manage (Delegation of Control
Wizard, or dsacls). Map the features you'll use to the rights below and skip
the rest.
| Feature | Rights on the target OU(s) |
|---|---|
| Read lists, search, view profiles | Read all properties on user/computer/group objects (Authenticated Users usually have this already) |
| Reset password | Reset Password extended right on user objects |
| Force "change at next logon" | Write pwdLastSet |
| Unlock account | Write lockoutTime |
| Enable / disable account | Write userAccountControl |
| Password-expiry toggle (never expires) | Write userAccountControl |
| Account expiry date | Write accountExpires |
| Create user | Create/Delete User objects; Write the attributes your panel writes (name, sAMAccountName, userPrincipalName, mail, …) |
| Delete user / computer / group | Delete on that object class |
| Move between OUs | Write + Delete Subtree on source, Create child on destination |
| Group membership add/remove | Write member on the group objects |
| Edit group description / mail | Write description, mail |
| Create group | Create Group objects + write its attributes |
| Reset computer trust account | Reset Password extended right on computer objects |
| Photo upload | Write thumbnailPhoto |
| LAPS password (read) | Read ms-Mcs-AdmPwd / msLAPS-Password (+ …-EncryptedPassword). These are not readable by default — grant explicitly, e.g. Set-AdmPwdReadPasswordPermission / Windows LAPS ACL. |
| BitLocker recovery keys (read) | Read msFVE-RecoveryInformation child objects (msFVE-RecoveryPassword) |
| GPO module | Read on CN=Policies,CN=System,<baseDN> and read gPLink on OUs (default for Authenticated Users). No write is ever attempted. |
Example — password reset + unlock + enable/disable on one OU:
dsacls "OU=Staff,DC=corp,DC=example,DC=com" /I:S `
/G "CORP\svc-adconsole:CA;Reset Password;user" `
"CORP\svc-adconsole:WP;lockoutTime;user" `
"CORP\svc-adconsole:WP;userAccountControl;user" `
"CORP\svc-adconsole:WP;pwdLastSet;user"
6. Verify
- Sign in as a member of
AD_LOGIN_GROUP. - Open Users — the list and OU tree populate.
- Open a test account → Reset password → set a value → confirm on a real logon. A failure here almost always means "no encrypted channel" or "Reset Password right not delegated".
- Repeat for the other features you delegated.
See troubleshooting.md for specific errors.