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
119 lines
5.2 KiB
Markdown
119 lines
5.2 KiB
Markdown
# 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_USERNAME` and its password in `LDAP_PASSWORD`.
|
|
|
|
Test the bind:
|
|
|
|
```sh
|
|
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 set `LDAP_TLS_VERIFY=true`.
|
|
|
|
Quick check from the app host:
|
|
|
|
```sh
|
|
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:
|
|
|
|
```powershell
|
|
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
|
|
|
|
1. Sign in as a member of `AD_LOGIN_GROUP`.
|
|
2. Open **Users** — the list and OU tree populate.
|
|
3. 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".
|
|
4. Repeat for the other features you delegated.
|
|
|
|
See [troubleshooting.md](troubleshooting.md) for specific errors.
|