Skip to content

Opinionated multi-arch Docker image based on debian:bookworm-slim to run an OpenLDAP 2.5 server.

License

Notifications You must be signed in to change notification settings

vegardit/docker-openldap

Repository files navigation

vegardit/openldap

Build Status License Docker Pulls Docker Stars Contributor Covenant

  1. What is it?
  2. Configuration
    1. Initial configuration
    2. Initial LDAP tree
    3. Customizing the Password Policy
    4. Transport Encryption (LDAPS/STARTTLS)
    5. Changing UID/GID of OpenLDAP service user
    6. Periodic LDAP Backup
    7. Synchronizing timezone/time with docker host
    8. Performance tuning
    9. Troubleshooting
  3. References
  4. License

What is it?

An opinionated, multi-arch Docker image - currently based on Debian's debian:bookworm-slim - built for easy deployment of an OpenLDAP 2.5 server.

Automatically rebuilt weekly to include the latest OS security fixes.

Configuration

Initial configuration

Various parts of the LDAP server can be configured via environment variables. All environment variables starting with LDAP_INIT_ are only evaluated on the first container launch. Changing their values later has no effect when restarting or updating the container.

To customize the initial configuration you can set the following environment variables:

LDAP_INIT_ORG_DN='DC=example,DC=com'
LDAP_INIT_ORG_NAME='Example Corporation'
LDAP_INIT_ORG_ATTR_O='' # optional, if not defined will be derived from LDAP_INIT_ORG_DN, e.g. DC=example,DC=com -> example.com
LDAP_INIT_ADMIN_GROUP_DN='cn=ldap-admins,ou=Groups,${LDAP_INIT_ORG_DN}'
LDAP_INIT_PASSWORD_RESET_GROUP_DN='cn=ldap-password-reset,ou=Groups,${LDAP_INIT_ORG_DN}' # users in this group can set password/sshPublicKey attribute of other users
LDAP_INIT_ROOT_USER_DN='uid=admin,${LDAP_INIT_ORG_DN}'
LDAP_INIT_ROOT_USER_PW='changeit'
LDAP_INIT_RFC2307BIS_SCHEMA=0 # 0=use NIS (RFC2307) schema, 1=use RFC2307bis schema
LDAP_INIT_ALLOW_CONFIG_ACCESS='true' # if set to true, the "cn=config" namespace can be read/edited by LDAP admins

Environment variables can for example be set in one of the following ways:

  1. Using docker run with -e, e.g.

    docker run -itd \
      -e LDAP_INIT_ORG_DN='DC=example,DC=com' \
      -e LDAP_INIT_ROOT_USER_PW='newpassword' \
      -e LDAP_INIT_ORG_NAME='Example Corporation' \
      -e LDAP_INIT_PPOLICY_PW_MIN_LENGTH='12' \
      -v /my_data/ldap/var/:/var/lib/ldap/ \
      -v /my_data/ldap/etc/:/etc/ldap/slapd.d/ \
      -p 389:389 \
      vegardit/openldap
  2. Using an env-file to store all changed variables and use the option --env-file with docker run, e.g.:

    docker run -itd --env-file environment vegardit/openldap

    In the env-file values must not be enclosed using quotes (' or "), please remove them. See this example file: example/docker/example.env.

  3. Setting the environment variable INIT_SH_FILE pointing to a shell script that should be sourced during the container start.

    # /path/on/docker/host/my_init.sh
    LDAP_INIT_ORG_DN='DC=example,DC=com'
    LDAP_INIT_ROOT_USER_PW='newpassword'
    LDAP_INIT_ORG_NAME='Example Corporation'
    LDAP_INIT_PPOLICY_PW_MIN_LENGTH='12'
    docker run -itd \
      -e INIT_SH_FILE=/mnt/my_init.sh \
      -v /path/on/docker/host/my_init.sh:/mnt/my_init.sh:ro \
      vegardit/openldap

Initial LDAP tree

The initial LDAP tree structure is imported from /opt/ldifs/init_org_tree.ldif. You can mount a custom file at that path if you need changes.

LDAP entries (users, groups) are imported from /opt/ldifs/init_org_entries.ldif. You can mount a custom file at that path if you need changes.

Customizing the Password Policy

On initial container launch, the password policy is imported from /opt/ldifs/init_org_ppolicy.ldif.

The following parameters can be modified via environment variables before initial container launch:

LDAP_INIT_PPOLICY_DEFAULT_DN='cn=DefaultPasswordPolicy,ou=Policies,${LDAP_INIT_ORG_DN}'
LDAP_INIT_PPOLICY_PW_MIN_LENGTH=8
LDAP_INIT_PPOLICY_MAX_FAILURES=3
LDAP_INIT_PPOLICY_LOCKOUT_DURATION=300

If more customizations are required, simply mount a custom policy file at /opt/ldifs/init_org_ppolicy.ldif before initial container launch.

Password Quality Checker:

pqChecker is configured as the default password quality checker using the rule 0|01010101 with the following meaning:

Pos. Value Effective Rule
0-1 0| Don't broadcast passwords.
2-4 01 Minimum 1 uppercase character.
5-6 01 Minimum 1 lowercase character.
7-8 01 Minimum 1 digit.
9-10 01 Minimum 1 special character.
11-.. empty No characters are disallowed in passwords.

The pqChecker rule syntax is explained here in more detail: https://www.meddeb.net/pqchecker/?Idx=2

A custom rule can be provided via an environment variable, e.g.:

LDAP_PPOLICY_PQCHECKER_RULE='0|01020101@!+-#'

Transport Encryption (LDAPS/STARTTLS)

LDAP traffic can be encrypted in two complementary ways:

  1. Terminate TLS inside the container using static X.509 certificates:

    • Bind-mount your TLS key material to the container to enable STARTTLS on port 389
    • Optionally enable LDAPS as well (TLS-wrapped LDAP port 636)
    Variable Default Description
    LDAP_TLS_ENABLED auto Controls whether TLS features are activated:
    - auto - activate TLS only if both certificate and private key are present at /etc/ldap/certs/server.{crt,key} (or supplied via LDAP_TLS_CERT_FILE/LDAP_TLS_KEY_FILE)
    - true - always enable TLS; fail startup if certificate or private key is missing
    - false - disable all TLS features; ignore other TLS settings
    LDAP_LDAPS_ENABLED true (Only applies if TLS is enabled)
    true - enable implicit TLS (LDAPS) listener on port 636 (ldaps://)
    LDAP_TLS_CERT_FILE /run/secrets/ldap/server.crt Path to the server certificate inside the container
    LDAP_TLS_KEY_FILE /run/secrets/ldap/server.key Path to the matching private key inside the container
    LDAP_TLS_CA_FILE /run/secrets/ldap/ca.crt Path to the CA bundle for verifying peer certificates
    LDAP_TLS_VERIFY_CLIENT try Client certificate policy (see TLSVerifyClient):
    - never - don't request a client certificate
    - allow - request a client certificate; ignore if missing or invalid
    - try - request a client certificate; reject if invalid (ignore if missing)
    - demand - require a valid client certificate
    LDAP_TLS_SSF 128 Minimum Security Strength Factor (SSF) required for all TLS sessions. 0 = clear-text allowed; >=0 enforces that STARTTLS/LDAPS negotiate at minimum that strength (AES-128, AES-256). More details here: OpenLDAP Admin Guide

    How to generate a self-signed cert for testing:

    openssl req -x509 -nodes -newkey rsa:4096 \
      -keyout server.key -out server.crt \
      -days 365 -sha256 \
      -subj "/CN=ldap.example.com" \
      -addext "subjectAltName=DNS:ldap.example.com"

    Docker Compose example with bind-mount at default location:

    Mounting the key and certificate to the default location will automatically enable STARTTLS and LDAPS support.

    services:
      openldap:
        image: vegardit/openldap:latest
        environment:
          # ... other options
        ports:
          - "389:389"  # for STARTTLS
          - "636:636"  # for LDAPS
        volumes:
          - ./certs/server.crt:/run/secrets/ldap/server.crt:ro
          - ./certs/server.key:/run/secrets/ldap/server.key:ro
          - ./certs/ca.crt:/run/secrets/ldap/ca.crt:ro  # optional, if using a private CA

    Docker Compose example with bind-mount at custom location:

    Pointing LDAP_TLS_KEY_FILE and LDAP_TLS_CRT_FILE to paths accessible from within the container will automatically enable STARTTLS and LDAPS support.

    services:
      openldap:
        image: vegardit/openldap:latest
        environment:
          LDAP_TLS_KEY_FILE: /opt/tls/server.key
          LDAP_TLS_CERT_FILE: /opt/tls/server.crt
          # ... other options
        ports:
          - "389:389"  # for STARTTLS
          - "636:636"  # for LDAPS
        volumes:
          - ./certs/:/opt/tls/:ro
  2. Terminate TLS in front of the container with a reverse proxy

    Run the container plain on 389 and put a reverse proxy like Traefik 2.x in front. Configure a Traefik 2.x TCP service with an auto-renewing Let's Encrypt configuration that forwards the encrypted stream to the container.

    Traefik 2.x example (TCP mode):

    services:
      openldap:
        image: vegardit/openldap:latest
        ports:
          - "389:389"
        environment:
          # ... other options
      labels:
        traefik.enable: "true"
        traefik.tcp.routers.ldap.rule: HostSNI(`ldap.example.com`)
        traefik.tcp.routers.ldap.entryPoints: ldaps636 # expose externally on port 636
        traefik.tcp.routers.ldap.tls.certresolver=lets_encrypt
        traefik.tcp.routers.ldap.service: ldap
        traefik.tcp.services.ldap.loadbalancer.server.port=389
    
    traefik:
      image: traefik:latest # https://hub.docker.com/_/traefik?tab=tags
      ports:
        - 636:636  # ldaps
      volumes:
        - /etc/traefik/traefik.yml:/traefik.yml:ro
        - /etc/traefik/keystore.json:/keystore.json # holds self-acquired letsencrypt certs
      labels:
        traefik.enable: true
    # https://docs.traefik.io/reference/static-configuration/file/
    entryPoints:
      # https://docs.traefik.io/routing/entrypoints/
      ldaps636:
        address: ":636"
    certificatesResolvers:
      # https://docs.traefik.io/https/acme/
      lets_encrypt:
        acme:
          email: [email protected]
          storage: /keystore.json
          tlsChallenge: {}
          #httpChallenge:
          #  entryPoint: http80
    providers:
      docker:
        # https://docs.traefik.io/providers/docker/
        endpoint: "unix:///var/run/docker.sock"
        exposedByDefault: false # ignore containers that don't have a traefik.enable=true label
        watch: true

Changing UID/GID of OpenLDAP service user

The UID/GID of the user running the OpenLDAP service can be aligned with the docker host using the environment variables LDAP_OPENLDAP_UID and LDAP_OPENLDAP_GID.

During each container start it is verified that the given UID/GID matches the currently effective UID/GID. If not, the UID/GID of the openldap user are changed accordingly and chown on /etc/ldap and /var/lib/slapd is executed before the OpenLDAP service is started.

Periodic LDAP Backup

This image automatically generates a daily LDIF export at 2 a.m. to /var/lib/ldap/data.ldif.

The following environment variables can be used to configure the automatic LDAP backup:

LDAP_BACKUP_TIME='02:00'  # Format is "HH:MM", i.e. 24-hour format with minute precision
LDAP_BACKUP_FILE='/var/lib/ldap/data.ldif'

To disable automatic backup set an empty value for the environment variable LDAP_BACKUP_TIME.

Synchronizing timezone/time with docker host

To use the same timezone and/or time of the docker host you can run the image with:

--volume /etc/localtime:/etc/localtime:ro \
--volume /etc/timezone:/etc/timezone:ro

Docker compose file example:

version: '3.7'
services:
  openldap:
    image: vegardit/openldap:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro

Performance tuning

DB Indexes

The database indexes configured during initial container launch are imported from /opt/ldifs/init_backend_indexes.ldif.

To use other indexes, mount a custom file at that path before initial container launch.

Memory usage

The maximum number of open files is set to 1024 by default to prevent excessive RAM consumption as reported here.

Increase this limit with the following environment variable:

LDAP_NOFILE_LIMIT=2048

Troubleshooting

The slapd service logs to stdout. You can change the active log levels by setting this environment variable:

LDAP_LOG_LEVELS='Config Stats'

Available log levels:

Any     (-1)     enable all debugging
Trace   (1)      trace function calls
Packets (2)      debug packet handling
Args    (4)      heavy trace debugging
Conns   (8)      connection management
BER     (16)     print out packets sent and received
Filter  (32)     search filter processing
Config  (64)     configuration processing
ACL     (128)    access control list processing
Stats   (256)    stats log connections/operations/results
Stats2  (512)    stats log entries sent
Shell   (1024)   print communication with shell backends
Parse   (2048)   print entry parsing debugging
Sync    (16384)  syncrepl consumer processing
None    (32768)  only messages that get logged whatever log level is set

References

License

All files in this repository are released under the Apache License 2.0.

Individual files contain the following tag instead of the full license text:

SPDX-License-Identifier: Apache-2.0

This enables machine processing of license information based on the SPDX License Identifiers that are available here: https://spdx.org/licenses/.

About

Opinionated multi-arch Docker image based on debian:bookworm-slim to run an OpenLDAP 2.5 server.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

 
 
 

Contributors 2

  •  
  •