User guide
How to operate a running lab. If you do not have one yet, start at the quick start. To seed users and groups from YAML, see Scenario YAML.
Sign-in
Static bearer tokens are an explicit lab mode.
- Browser — paste the token on
/login. You get an HttpOnly session cookie. The CSRF secret stays in page memory, never in localStorage. - REST / HTTP MCP —
Authorization: Bearer - stdio MCP —
--token-fileorLABLDAP_MCP_TOKEN. Never--token. - Direct LDAP — simple bind as a directory user. The control-plane token is not an LDAP password.
Scenario YAML
Users and groups are declared in the LabScenario file. Bootstrap writes them into 389 DS. Passwords are file references. Groups cannot be empty. Soft reset restores that file.
spec:
users:
- id: alice
uid: alice
passwordFile: /run/secrets/user-alice
enabled: true
groups:
- id: staff
members:
- user: alice
Full mapping and ACL example: Scenario YAML.
Browser UI
Open https://127.0.0.1:8443/. Trust the lab CA or accept the warning.
/dashboard — scenario, engine, baseline, transports, recent audit/userscreate, edit, enable/disable, set password, delete (type the id)/groupscreate with an initial member; add / remove / replace membership/searchexplicit-submit LDAP search;userPasswordcannot be requested/auth-testbind diagnostic; password field clears after/schemaread-only Root DSE and schema/auditin-memory ring, request-id copy/exportLDIF without passwords/resetsoft reset to the compiled baseline
Updates carry a revision. A 412 means refresh and retry. Groups cannot be empty. Soft reset needs the exact scenario name. Hard reset is make compose-reset only.
REST
Base URL https://127.0.0.1:8443/api/v1. Contract: api/openapi.yaml.
TOKEN=$(tr -d '\n' < secrets/token-admin)
curl -sk -H "Authorization: Bearer $TOKEN" \
https://127.0.0.1:8443/api/v1/users
GET /health never talks to LDAP. GET /health/ready does. GET /metrics is Prometheus text on loopback.
Direct LDAP
Yes — you can authenticate against the lab as an LDAP server. The listener is 389 Directory Server, not the Go control plane. Point clients at 127.0.0.1:3389 (StartTLS) or 127.0.0.1:3636 (LDAPS). Do not point an LDAP client at :8443; that port is HTTPS.
Anonymous bind is off. Cleartext bind is off. Trust secrets/tls/instance-ca.crt (ephemeral) or secrets/tls/ca.crt (persistent). Wrong CA or SAN fails closed.
MCP
Two transports, one catalog, same scopes as REST.
- HTTP:
POST /mcpwith a bearer.GET /mcpis 405. - Local:
labldap mcp-stdio— protocol on stdout, logs on stderr.
On by default: ldap_search_entries, ldap_get_capabilities, ldap_get_baseline, ldap_get_entry.
Off until register*: create/update/delete user and group, membership, passwords, reset, export.
Resources include labldap://capabilities, labldap://baseline, labldap://schema, and labldap://entry{?dn}.
What not to do
- Do not put Directory Manager in the control container.
- Do not mount the Docker socket.
- Do not treat ephemeral tmpfs as a wipe.
- Do not expect Active Directory semantics.
- Do not log tokens, passwords, or session ids.
Full version: docs/guides/user-guide.md. MCP table: docs/mcp/catalog.md.