Skip to content

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 authelia namespace
  • 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