Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

netresearch/ldap-manager

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,355 Commits
1,355 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LDAP Manager

Template Drift managed by netresearch/.github templates

LDAP Manager Logo

Web-based LDAP administration interface for managing users, groups, and computers.

Supports both Active Directory and OpenLDAP with per-user credential binding.

CI Container codecov Go Report Card License: MIT Go Version Release GHCR

Features

  • Browse, search, and filter users, groups, and computers
  • View and edit user details, group memberships, and attributes
  • Per-user LDAP credential binding (no shared admin account required)
  • Active Directory and OpenLDAP support with automatic detection
  • Direct-bind authentication fallback for non-person accounts
  • Configurable via environment variables or command-line flags
  • LDAP connection pooling with health checks
  • LRU caching with background refresh
  • Distroless Docker image (13 MB, nonroot, read-only filesystem)
  • Multi-platform builds (linux/amd64, linux/arm64, darwin, windows)

Quick Start

Docker (Recommended)

docker run -d --name ldap-manager \
  -e LDAP_SERVER=ldaps://dc1.example.com:636 \
  -e LDAP_BASE_DN="DC=example,DC=com" \
  -e LDAP_READONLY_USER=readonly \
  -e LDAP_READONLY_PASSWORD=password \
  -e LDAP_IS_AD=true \
  -p 3000:3000 \
  ghcr.io/netresearch/ldap-manager:latest

Open http://localhost:3000 and log in with your LDAP credentials.

Docker Compose (Development)

The project includes a complete development environment with OpenLDAP, seed data, ACL configuration, and an nginx TLS reverse proxy:

docker compose --profile dev up

This starts:

Native Build

Prerequisites: Go 1.26+, templ CLI.

templ generate
go build -o ldap-manager ./cmd/ldap-manager

./ldap-manager \
  --ldap-server ldaps://dc1.example.com:636 \
  --active-directory \
  --base-dn DC=example,DC=com \
  --readonly-user readonly \
  --readonly-password readonly

The server listens on port 3000 by default. Set the PORT environment variable to override.

Stack

Go + Fiber + Templ on the backend; Pico CSS + a hand-written internal/web/static/app.css + vendored htmx on the frontend. No Node.js toolchain — vendored files are refreshed with bash scripts/vendor.sh, which verifies SHA-256 checksums against scripts/vendor.lock.

Configuration

All options can be set via environment variables, a .env file, or command-line flags. Run ./ldap-manager --help for the full list.

Environment Variable Flag Default Description
LDAP_SERVER --ldap-server (required) LDAP URI (ldap:// or ldaps://)
LDAP_BASE_DN --base-dn (required) Base DN for LDAP searches
LDAP_IS_AD --active-directory false Enable Active Directory mode
LDAP_READONLY_USER --readonly-user Service account DN for background cache
LDAP_READONLY_PASSWORD --readonly-password Service account password
LDAP_ADMIN_GROUP --admin-group Group DN whose members may view the password-expiry roster
LDAP_TLS_SKIP_VERIFY --tls-skip-verify false Skip TLS certificate verification
PORT 3000 HTTP listen port
COOKIE_SECURE --cookie-secure true Require HTTPS for cookies
PERSIST_SESSIONS --persist-sessions false Persist sessions to BoltDB
SESSION_DURATION --session-duration 30m Session lifetime
LOG_LEVEL --log-level info Log level (trace, debug, info, warn, error)

When no readonly user is configured, the app uses per-user LDAP credentials for all operations and the background cache is disabled.

Password-expiry roster

/password-expiry lists accounts whose LDAP password is expiring, resolved live via simple-ldap-go's expiry API. It is admin-only and needs the service account.

An admin is a member of LDAP_ADMIN_GROUP or an account carrying Active Directory's adminCount=1. Note that adminCount is sticky: Active Directory sets it when an account joins a protected group and never clears it on removal, so an account that was ever privileged keeps roster access. Prefer LDAP_ADMIN_GROUP membership where you want access to track current privilege. On OpenLDAP there is no adminCount, so LDAP_ADMIN_GROUP is the only way to grant access — without it, the roster is reachable by no one. Group membership is read from the user's memberOf, which Active Directory populates automatically; an OpenLDAP deployment must have the memberof overlay enabled for the group gate to work.

The default view shows accounts due within a window (?days=, default 30, capped at 366); a Show all accounts toggle adds the never-expires and unknown accounts with a status badge. On OpenLDAP, expiry needs the ppolicy overlay; accounts the directory reports nothing about show as unknown.

Traefik Integration

For production deployments behind Traefik:

docker network create traefik

# In .env:
TRAEFIK_ENABLE=true
TRAEFIK_HOST=example.com
# Access: https://ldap-manager.example.com

Screenshots

Users List User Detail
Users List User Detail
Groups List Group Detail
Groups List Group Detail

Docker Image

Published to GitHub Container Registry:

  • 13 MB distroless runtime (nonroot UID 65532, read-only filesystem, no shell)
  • Multi-platform: linux/amd64, linux/arm64, linux/arm/v7
  • OCI-compliant labels and health check built in
docker run -d --name ldap-manager \
  -v /etc/ssl/certs:/etc/ssl/certs:ro -p 3000:3000 \
  ghcr.io/netresearch/ldap-manager:latest \
  --ldap-server ldaps://dc1.example.com:636 \
  --base-dn DC=example,DC=com

Documentation

Full documentation is available in docs/:

Accessibility

LDAP Manager's login page conforms to WCAG 2.2 Level AAA in comfortable density (the default on touch devices, narrow viewports, and under prefers-reduced-motion). In compact density (the default on desktop), the login page meets Level AA; all AAA success criteria are met except 2.5.5 Target Size (Enhanced), which is a deliberate density-preference trade-off.

Conformance is enforced in CI by a contrast unit test (internal/web/contrast_test.go) and an axe-core AAA pass on every E2E run (internal/e2e/axe_test.go). Additional routes will be brought under the same guarantee as they migrate in subsequent slices.

The relationship graph view at /graph (and the List | Graph mode toggle on the user, group, and computer list pages) meets WCAG 2.2 Level AA. An equivalent flat edge table is always rendered below the visual canvas, providing an AAA-equivalent text alternative for every interaction and relationship the canvas displays. The graph pages are covered by the same axe-core ratchet (internal/e2e/axe_graph_test.go).

Contributing

Contributions welcome! Please open a Pull Request.

This project uses Conventional Commits and formats code with gofumpt + goimports.

License

MIT

Releases

Packages

Used by

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.