Active Directory and LDAP
Connect the appliance to your directory, import users from groups and OUs, and keep a local break-glass account that works when the directory does not.
- Version: 0.4
- Role: admin_user
- Type: task
Bind CID222 to your directory so users sign in with their existing domain accounts. Two panes do the work: Active Directory / LDAP holds the connection, and Directory Sync imports users from a group or an organisational unit so you can set their roles before they ever log in.
What do I need?
- Licence
- Any
- Role
admin_user
Prerequisites
- The appliance has completed the first-boot setup wizard.
- A read-only service account exists in the directory, with permission to search the user subtree.
- TCP 636 is open from the appliance to at least one domain controller — see Network prerequisites.
- The domain controller presents a certificate your appliance can validate, or you accept an unvalidated LDAPS connection.
- A local administrator account exists whose password you know. Directory sign-in fails during a directory outage; the local account is the way back in.
/assets/screenshots/settings-active-directory@0.4.pngDirectory authentication is available on every licence tier and is unaffected by an expired licence — gating it would lock out the administrator coming to renew. The only licence interaction is the seat cap, which applies when the directory tries to create a new account.
Connect to the directory
Open the directory settings
Select Settings → Active Directory / LDAP.
The page reads Let users sign in with their directory accounts. Once connected, users are created automatically on first login. A badge on the Connection card shows Disabled, Not checked yet, Reachable or Unreachable.
Choose the directory type
Set Directory type to Active Directory or OpenLDAP.
This choice is not cosmetic: it decides the attribute the appliance treats as the username —
sAMAccountName for Active Directory, uid for OpenLDAP — and the object filter it searches
with. There is no separate username-attribute field.
Enter the server address
Set Server URL to a full LDAP URL, for example ldaps://dc01.example.corp:636.
Host, port and transport all live in this one field. Only an ldaps:// URL is given TLS
options; there is no StartTLS path. Certificate validation is on by default and is turned off
only by setting LDAP_TLS_REJECT_UNAUTHORIZED to false on the appliance.
Supply the service account
Set Bind DN (service account) to the account's distinguished name — for example
CN=svc-cid,OU=Service,DC=example,DC=corp — and type its password into Bind password.
The password is encrypted with AES-256-GCM before it is stored and is never returned by the API. Once saved, the field's placeholder becomes •••••••• (leave blank to keep current).
Scope the user search
Set Base DN to the subtree holding your users, for example DC=example,DC=corp, and check
User filter.
The filter defaults to (sAMAccountName={{username}}) for Active Directory and
(uid={{username}}) for OpenLDAP. {{username}} is replaced with what the user typed at
sign-in.
Decide how group membership is read
Set Group membership mode to memberOf (Active Directory) or group-search (OpenLDAP), and optionally set Admin group DN (optional).
A user the directory places in the admin group receives the admin_user role on every login
and every sync. Left empty, no role is granted from the directory.
Test before you enable
Select Test connection.
A success reports Connected. Found N+ user object(s) under the base DN. — a count capped
at five, so 5+ means at least five. A failure shows the directory's own error text.
Enable directory sign-in and save
Set Enable directory authentication to on, decide whether Just-in-time provisioning stays on, then select Save.
A toast reports LDAP configuration saved. With just-in-time provisioning on, an unknown username that binds successfully gets an account created on the spot; with it off, only users who already have an account can sign in.
Danger
The bind password is encrypted with a key derived from JWT_SECRET. Rotating that secret makes
the stored password undecryptable, and the appliance then attempts the bind with an empty
password rather than telling you why. Re-enter Bind password after any rotation.
Warning
Testing a URL you have not saved requires the password again: the saved password is only ever sent to the saved URL. Type it into Bind password before testing a changed Server URL.
Import users from a group or an OU
A sync scope is a directory group or OU, plus the CID222 role and tenant group its members should receive.
Open directory sync
Select Settings → Directory Sync.
The page reads Import users from a group or OU so you can configure their roles before they log in. If directory authentication is off, the page says so and links back to the connection pane.
Browse the directory
Under Browse & import, set Scope type to Group or Organizational Unit, optionally type into Search (optional), and select Load groups or Load OUs.
The table lists what the service account can see, by name.
Preview the members
Select Preview on a row.
The right-hand pane reports N user(s) in name and lists them. A group too large for the directory to return in one response reports that instead of a partial list.
Choose the role and the group
Set Default role to normal_user or admin_user, and optionally set
Auto-enroll into group to an existing CID222 tenant group.
Only those two roles can be granted from a directory scope. The target tenant group must already exist — sync never creates one.
Add the scope
Select Add as sync scope.
A toast reports Scope added and the scope appears under Configured sync scopes with Last sync showing never.
Run the first sync
Select Sync now on the scope's row.
A toast reports Sync complete: with counts of imported, updated, ungrouped and deactivated accounts. Imported users appear under Tenants with the role you chose.
Note
Re-syncing is manual. A scope not re-synced for a day is tagged stale, with the hint Not re-synced in over a day — CID group membership may no longer match the directory. Nothing runs it for you.
How a directory user signs in
The username decides the path. An account whose record says it is directory-backed is always checked against the directory and never against a local password hash; an account that is local is always checked locally, even while the directory is enabled and unreachable. That rule is the break-glass guarantee — there is no flag to set and none to forget.
On a successful bind the appliance records the user's distinguished name, clears any local
password, refreshes the display name and email from the directory, and grants admin_user if the
directory places the user in the admin group. It never demotes: a role the directory no longer
justifies is left alone and reported as LDAP_ADMIN_ROLE_DRIFT instead.
Two refusals read alike but are not:
- Invalid credentials means the directory rejected the password.
- The directory server could not be reached, so directory sign-in is temporarily unavailable. This is not a problem with your password. Local accounts are unaffected. means the directory never answered. Nothing is wrong with the account.
A password-reset link cannot be issued for a directory account. The appliance refuses with This account is managed by your directory (AD/LDAP). Its password must be reset in the directory — a link issued here would set a password sign-in never checks.
Fields reference
GET /admin/ldap/config returns the stored row without the encrypted password, plus
has_bind_password.
| Field on the page | Stored as | Default | Notes |
|---|---|---|---|
| Enable directory authentication | enabled | off | The connection is only usable when a URL, bind DN and base DN are all present as well. |
| Directory type | flavor | ad | ad or openldap. Decides the username and display-name attributes and the object filters. |
| Server URL | url | — | Host, port and transport in one value. |
| Bind DN (service account) | bind_dn | — | Read-only service account. |
| Bind password | encrypted column | — | Never returned. Blank on save keeps the current value. |
| Base DN | base_dn | — | Root of the user and group search. |
| User filter | user_filter | per flavour | {{username}} is substituted at sign-in. |
| Group membership mode | group_mode | memberOf | memberOf or group-search. |
| Admin group DN (optional) | admin_group_dn | empty | Membership grants admin_user. Empty means no directory role mapping. |
| Just-in-time provisioning | jit_provisioning | on | Create an account on first successful login. |
Sync scope fields, from POST /admin/ldap/scopes:
| Field on the page | Stored as | Notes |
|---|---|---|
| Scope type | type | group or ou. |
| — | dn | The distinguished name, taken from the row you previewed. |
| Default role | default_role | normal_user or admin_user only. |
| Auto-enroll into group | tenant_group_id | An existing CID222 tenant group, or none. |
Changing the URL, bind DN or base DN resets the recorded health state to never probed. The
appliance re-probes the directory on its own schedule, every five minutes by default
(LDAP_HEALTH_PROBE_INTERVAL_MS).
Verify
- Select Test connection. It reports Connected. Found N+ user object(s) under the base DN. with a non-zero count.
- The Connection card's badge reads Reachable.
- Sign in as a directory user in a private window. The account appears under Tenants marked Managed in your directory, and members imported by a scope show Synced from AD in their tenant group.
- Stop the directory, or block the port, and confirm Event logs records
DIRECTORY_DEGRADED, thenDIRECTORY_RECOVEREDwhen it returns. A sign-in attempt during the outage recordsDIRECTORY_LOGIN_UNAVAILABLE. - Sign in with your local break-glass administrator while the directory is still down. It succeeds.
If it fails
- LDAP url, bind DN and base DN must be configured → one of the three is empty. Every browse, test, preview and sync path needs all three.
- Testing a different LDAP url requires the bind password to be re-entered; the saved password is only sent to the saved url. → you changed Server URL without retyping the password.
- The test reports an invalid-credentials error → the bind DN or its password is wrong, or
JWT_SECRETwas rotated since the password was saved. Retype Bind password and save. - The test reports a refused connection, an unresolvable name or a timeout → the appliance cannot reach the controller. Check Network prerequisites.
- The test reports a certificate error → the controller's certificate does not validate against
the appliance's trust store. Install the issuing CA, or set
LDAP_TLS_REJECT_UNAUTHORIZEDtofalseif you accept an unvalidated connection. - The service bind succeeded but the base DN returned no entry → the bind works and the base DN is wrong.
- Could not read all members of DN or a message about ranged retrieval → the group is larger than the directory returns in one response. Nothing was removed, deliberately: treating the readable part as the whole membership would de-group everyone in the rest.
- This sync scope is disabled. Re-enable it before syncing. → the scope is inactive.
- Sync scope "…" is mapped to a CID tenant group (…) that no longer exists. → the target tenant group was deleted. Re-point the scope or clear the mapping.
- Deleting a tenant group is refused with
GROUP_MAPPED_BY_SYNC_SCOPE→ a sync scope still points at it. Re-point the scope first. - The sync warns that users were not imported and names a licence count, or a first login is
refused with
LIMIT_EXCEEDED→ the licence seat cap is reached. Deactivate accounts you no longer need, or ask your CID222 contact to raise the limit. Existing users keep signing in. - The sync reports Directory answered only partly … nothing removed → the read was incomplete, so no de-grouping and no deactivation ran, and the scope's last-sync time did not advance. Fix the directory-side cause and sync again.
Limits worth knowing before you design around them
Sync never demotes a role and never deletes an account. A user who leaves a scope loses that scope's group membership; an account is deactivated only when the directory positively answers that the object is gone. A user matching two scopes with different default roles keeps the role the first scope gave them, unless a later run finds them in the admin group.
Warning
Group Role Mappings in the settings navigation is a preview. The page states Preview — not yet wired. and saves nothing. The one directory-to-role mapping that works is Admin group DN (optional) on the connection pane.
Next steps
- Tenant groups — the groups a sync scope enrols users into, and the credentials that follow them.
- Access control — what
normal_userandadmin_useractually reach. - Password delivery — how local accounts, the ones a directory outage leaves you with, receive their reset links.
Last updated on