Lightweight LDAP (LLDAP)
Modern LDAP server deployment on k3s cluster, replacing the legacy OpenLDAP setup with better management and custom attribute support.
Current LLDAP Deployment
Architecture Overview
- Platform: k3s cluster in
authelianamespace - Database: PostgreSQL 15.8 with streaming replication support
- Storage: Longhorn PVC for data persistence
- Access: Web UI at
https://ldap-admin.mixi.cz(protected by Authelia) - Image:
lldap/lldap:2025-10-14-debian-rootless
LLDAP Structure
dc=mixi,dc=cz
|-- admin (LLDAP admin user)
|-- ou=people,dc=mixi,dc=cz
| |-- user1@mixi.cz
| |-- user2@mixi.cz
| \-- ...
\-- ou=groups,dc=mixi,dc=cz
|-- lldap_admin (admin group)
|-- lldap_password_manager
\-- lldap_strict_readonly
Custom Attributes
LLDAP supports custom attributes via Web UI (no LDIF required):
Immich Integration:
- immichRole: String - User role (admin, user)
- immichQuota: Integer - Storage quota in bytes
Deployment Files
Located in /home/mixi/pg/home/automation/kube/lldap/:
| File | Description |
|---|---|
01-storage.yaml |
Longhorn PVCs for PostgreSQL and LLDAP data |
02-secrets-template.yaml |
Secrets template (copy and customize) |
03-postgres-config.yaml |
PostgreSQL configuration for WAL replication |
04-postgres.yaml |
PostgreSQL database with replication config |
05-lldap.yaml |
LLDAP server deployment and services |
06-ingress.yaml |
Traefik ingress with TLS and Authelia protection |
07-backup.yaml |
Database backup CronJob to NFS |
Management
Web Interface: https://ldap-admin.mixi.cz
- Login: admin / (password from secret)
- Create users, groups, and custom attributes
- No LDIF file management required
Command Line Access:
kubectl port-forward -n authelia svc/lldap-ldap 3890:389
ldapsearch -x -H ldap://localhost:3890 -b "dc=mixi,dc=cz" "(objectClass=person)"
Monitoring:
- Prometheus metrics: Manual configuration in prometheus.yml
- Uptime Kuma: TCP port check on LDAP (port 389) or HTTP check on web interface (port 17170)
- Database backups: Daily at 3:00 AM to /srv/backup/lldap
Note: LLDAP returns the web interface for any HTTP path, so HTTP health checks should verify the actual service rather than relying on specific endpoints.
Services Integration
Authelia:
- URL: ldap://lldap-ldap.authelia.svc.cluster.local:389
- Base DN: dc=mixi,dc=cz
- Users DN: ou=people,dc=mixi,dc=cz
Immich: - OAuth integration via Authelia - Custom attributes for role and quota management
Migration
Phase 1: ✅ Completed - LLDAP deployed on k3s with Immich OAuth Phase 2: 🚧 In Progress - User data migration from OpenLDAP Phase 3: 🚧 Planned - Migrate Postfix/Dovecot from OpenLDAP to LLDAP
User Migration Status
- Migration Script: Python script at
/home/mixi/pg/home/automation/kube/lldap/migration/migrate_ldap.py - User Data: ✅ Successfully migrated (usernames, emails, basic attributes)
- Custom Attributes: ✅ Mail attributes mapped for Postfix/Dovecot compatibility
- Passwords: ❌ Cannot be migrated - LLDAP's zero-knowledge proof architecture doesn't support password hash import
- Solution: Users must reset passwords manually or via admin
- Mail Impact: Existing mail users will need password reset before mail migration
Password Migration Limitations
LLDAP uses a zero-knowledge proof authentication system that prevents importing existing password hashes from OpenLDAP. This architectural decision enhances security but means:
- All users need new passwords set via LLDAP admin interface
- Password reset flow must be implemented for mail users
- Consider phased migration approach to minimize user impact
Performance Characteristics
LLDAP's authentication performance is significantly slower than OpenLDAP due to its security-first architecture. This is an important consideration for high-traffic authentication scenarios.
Performance Comparison
| Implementation | Search Response Time | Password Scheme |
|---|---|---|
| OpenLDAP | ~16ms | SSHA (fast hash) |
| LLDAP | ~620-720ms | OPAQUE (zero-knowledge proof) |
| Difference | 44x slower | Security vs Speed tradeoff |
Breakdown: - Anonymous bind (no authentication): ~20ms - Password verification overhead: ~600-700ms - Database queries: <1ms (PostgreSQL well-optimized)
Root Cause: OPAQUE Protocol
LLDAP uses the OPAQUE protocol for password authentication, which provides:
Advantages: - Zero-knowledge proof authentication (server never sees plaintext password) - Enhanced security against database compromise - Forward secrecy
Performance Impact: - Very CPU-intensive cryptographic operations - Blocks async runtime during authentication (GitHub issue #1337) - Single-threaded operation (1 worker thread) - Particularly slow on ARM processors (ODROID nodes)
Cannot be disabled or changed - OPAQUE is a fundamental architectural design decision in LLDAP. Traditional password hash schemes (SSHA, CRYPT, MD5) are not and will not be supported.
Current Optimizations
The deployment has been optimized for best possible performance:
LLDAP Resources: - CPU: 250m request, 500m limit - Memory: 256Mi request, 512Mi limit - Verbose logging: Disabled
PostgreSQL Resources: - CPU: 500m request, 1000m limit - Memory: 512Mi request, 1Gi limit - shared_buffers: 256MB - effective_cache_size: 512MB - Aggressive autovacuum to prevent table bloat
Status: Even with these optimizations, authentication remains ~600-700ms due to OPAQUE.
When to Use LLDAP vs OpenLDAP
LLDAP is appropriate for: - Web application user management (UI-driven) - Low-traffic authentication scenarios - Security-critical environments requiring zero-knowledge proofs - Modern applications with session-based authentication (caching)
OpenLDAP is better for: - High-traffic authentication (SSO, mail servers) - Performance-critical applications (<100ms requirement) - Legacy LDAP compatibility requirements - Traditional password hash support needed
Current Setup: LLDAP is used for Authelia SSO and Immich. For performance-sensitive deployments, consider hybrid approach (OpenLDAP for authentication, LLDAP for user management).
OpenLDAP export
Replace **** with password.
ldapsearch -x -H ldap://julie-local.mixi.cz -D "cn=auth,dc=mixi,dc=cz" -w **** -b "dc=mixi,dc=cz" "(!(|(uid=ebook)(ou=ftp)))" > openldap-users.ldif
Legacy OpenLDAP Structure (Deprecated)
Original OpenLDAP structure
It was tailored for Courier and Postfix ages ago, which was later migrated to dovecot and postfix with SASL authentication on dovecot.
dc=mixi,dc=cz
|-- cn=auth,dc=mixi,dc=cz (read-only user for postfix, dovecot and authelia)
|-- cn=admin,dc=mixi,dc=cz (OpenLDAP admin user)
|-- ou=People,dc=mixi,dc=cz
| |-- uid=mixi_mixi.cz,ou=People,dc=mixi,dc=cz
| | ...
| \-- uid=xxx_xxx.cz,ou=People,dc=mixi,dc=cz
\-- ou=Group,dc=mixi,dc=cz
|-- cn=wheel,ou=Group,dc=mixi,dc=cz
| ...
\-- cn=xxx,ou=Group,dc=mixi,dc=cz
Attributes / Schema
mail users (ou=People,dc=mixi,dc=cz) objectClass: - top - posixAccount - shadowAccount - qmailUser - CourierMailAccount - person - organizationalPerson - inetOrgPerson