Настройка LDAP в Docker Compose: интеграция контейнеров с Active Directory и OpenLDAP | AdminWiki

Настройка LDAP в Docker Compose: интеграция контейнеров с Active Directory и OpenLDAP

29 июля 2026 11 мин. чтения
Содержание статьи

Зачем нужна LDAP-интеграция в Docker Compose

Десятки контейнеров, сотни пользователей, разрозненные базы учетных записей. Каждый новый сервис требует ручного создания аккаунтов, а увольнение сотрудника превращается в квест по отключению доступа. Это не гипотетическая проблема, а ежедневная реальность для администраторов, управляющих Docker-инфраструктурой без централизованной аутентификации.

LDAP-интеграция решает эти задачи одним архитектурным решением. Вы подключаете контейнеры Nextcloud, GitLab, Grafana и любых других сервисов к единому каталогу Active Directory или OpenLDAP. Пользователи получают сквозную аутентификацию (SSO) с одной парой логин-пароль. Администратор управляет доступом централизованно: добавил пользователя в группу LDAP, и он автоматически получил нужные права во всех подключенных сервисах.

В этом руководстве разобраны готовые конфигурации docker-compose.yml, настройка демонов sssd и nslcd внутри контейнеров, методы диагностики ошибок. Материал построен на проверенных сценариях, которые сразу применимы в production-окружении. Если вы уже работаете с Docker и хотите углубить понимание оркестрации, изучите наше руководство по Docker Compose.

Архитектура LDAP-аутентификации для контейнеров

Контейнер не спрашивает пароль напрямую у пользователя. Он делегирует проверку credentials специализированному компоненту, который обращается к LDAP-серверу. Схема проста: приложение в контейнере отправляет запрос аутентификации демону (sssd, nslcd) или собственному LDAP-клиенту, тот связывается с каталогом, проверяет учетные данные и возвращает результат.

Различия между Active Directory и OpenLDAP затрагивают схему данных и формат Distinguished Name (DN). AD использует собственную схему на базе LDAPv3 с расширениями Microsoft, где пользователи находятся в CN=Users,DC=domain,DC=com. OpenLDAP применяет стандартную схему rfc2307, где типичный базовый DN выглядит как dc=example,dc=com, а пользователи размещаются в ou=users. При настройке контейнеров нужно указывать корректные search_base и фильтры объектов под конкретный тип каталога.

Порты для соединения стандартные: 389 для LDAP без шифрования, 636 для LDAPS. В production-среде обязательно используйте LDAPS или StartTLS, чтобы учетные данные не передавались открытым текстом. Для глубокого понимания сетевого взаимодействия контейнеров обратитесь к статье сетевое взаимодействие контейнеров Docker.

Встроенная поддержка LDAP vs внешние демоны (sssd/nslcd)

Выбор метода интеграции зависит от возможностей приложения. Nextcloud, GitLab, Grafana имеют встроенные LDAP-клиенты, которые напрямую подключаются к каталогу. Достаточно передать параметры подключения через переменные окружения или конфигурационные файлы. Этот подход проще в настройке и не требует модификации образа контейнера.

Внешние демоны sssd и nslcd нужны, когда приложение не поддерживает LDAP, но умеет работать с системной аутентификацией через PAM и NSS. Например, SSH-сервер в контейнере или самописное приложение, которое вызывает getpwnam(). Демон интегрируется с системой на уровне glibc, и все процессы в контейнере автоматически получают доступ к LDAP-пользователям.

Сравнение подходов:

  • Встроенная поддержка: минимальная настройка, не требует модификации Dockerfile, подходит для 80% типовых сервисов.
  • sssd: полная интеграция с PAM/NSS, кэширование учетных данных, поддержка failover, но требует прав суперпользователя и увеличивает размер образа.
  • nslcd: легковесная альтернатива sssd без кэширования, проще в конфигурации, идеальна для контейнеров, где нужна только аутентификация без офлайн-режима.

Подготовка LDAP-сервера: Active Directory и OpenLDAP

Ошибки интеграции чаще всего возникают на стороне LDAP-сервера: неверный bind DN, недостаточные права у пользователя для биндинга, неправильно указанный search_base. Проверьте эти параметры до настройки контейнеров.

Active Directory: настройка учетной записи для биндинга

Создайте отдельного пользователя в AD для подключения контейнеров. Не используйте учетную запись администратора домена, это нарушает принцип минимальных привилегий. Достаточно рядового пользователя с правами на чтение каталога.

# Создание пользователя через PowerShell на контроллере домена
New-ADUser -Name "ldap-binder" -SamAccountName "ldap-binder" -UserPrincipalName "ldap-binder@domain.local" -Enabled $true -AccountPassword (ConvertTo-SecureString "StrongPassword123!" -AsPlainText -Force)

Формат DN для биндинга в AD может быть в двух вариантах: классический LDAP-стиль (CN=ldap-binder,CN=Users,DC=domain,DC=local) или UPN (ldap-binder@domain.local). Большинство приложений корректно работают с обоими форматами. При использовании SSL/TLS убедитесь, что сертификат контроллера домена доверенный, или отключите проверку сертификата на этапе тестирования (параметр TLS_REQCERT never в конфигурации).

OpenLDAP: структура каталога и пользователь для подключения

Для OpenLDAP создайте пользователя-биндера через ldif-файл. Базовая структура каталога должна включать организационные единицы для пользователей и групп.

# bind-user.ldif
dn: cn=ldap-binder,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: ldap-binder
userPassword: {SSHA}hashed_password_here
description: LDAP bind user for Docker services

dn: ou=users,dc=example,dc=com
objectClass: organizationalUnit
ou: users

dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: groups

Загрузите ldif командой ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f bind-user.ldif. Проверьте доступность сервера с хоста Docker: ldapsearch -x -H ldap://ldap.example.com -D "cn=ldap-binder,dc=example,dc=com" -W -b "dc=example,dc=com". Успешное выполнение этой команды подтверждает, что LDAP-сервер готов к интеграции.

Настройка демона sssd в Docker-контейнере

sssd (System Security Services Daemon) обеспечивает полноценную интеграцию контейнера с LDAP на уровне системы. После настройки пользователи из каталога видны через стандартные утилиты id, getent passwd, а аутентификация работает через PAM.

Dockerfile: установка и базовая конфигурация sssd

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y \
    sssd \
    sssd-ldap \
    sssd-tools \
    libpam-sss \
    libnss-sss \
    ldap-utils \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

COPY sssd.conf /etc/sssd/sssd.conf
RUN chmod 600 /etc/sssd/sssd.conf

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

Файл entrypoint.sh запускает sssd перед стартом основного приложения:

#!/bin/bash
set -e

# Запуск sssd в фоновом режиме
sssd -D

# Проверка, что демон запустился
sleep 2
if ! pgrep sssd > /dev/null; then
    echo "ERROR: sssd failed to start"
    exit 1
fi

# Запуск основного приложения
exec "$@"

Конфигурация sssd.conf для Active Directory

[sssd]
services = nss, pam
config_file_version = 2
domains = domain.local

[nss]
filter_users = root
filter_groups = root

[pam]
offline_credentials_expiration = 2

[domain/domain.local]
id_provider = ldap
auth_provider = ldap
access_provider = ldap
ldap_uri = ldaps://dc.domain.local:636
ldap_search_base = DC=domain,DC=local
ldap_schema = ad
ldap_id_mapping = True
ldap_user_object_class = user
ldap_group_object_class = group
ldap_user_name = sAMAccountName
ldap_user_uid_number = objectSid
ldap_user_gid_number = objectSid
ldap_group_gid_number = objectSid
ldap_default_bind_dn = CN=ldap-binder,CN=Users,DC=domain,DC=local
ldap_default_authtok = StrongPassword123!
ldap_tls_reqcert = demand
enumerate = False
cache_credentials = True

Конфигурация sssd.conf для OpenLDAP

[sssd]
services = nss, pam
config_file_version = 2
domains = example.com

[nss]
filter_users = root
filter_groups = root

[pam]

[domain/example.com]
id_provider = ldap
auth_provider = ldap
access_provider = ldap
ldap_uri = ldaps://ldap.example.com:636
ldap_search_base = dc=example,dc=com
ldap_schema = rfc2307
ldap_user_object_class = posixAccount
ldap_group_object_class = posixGroup
ldap_user_name = uid
ldap_user_uid_number = uidNumber
ldap_user_gid_number = gidNumber
ldap_group_gid_number = gidNumber
ldap_default_bind_dn = cn=ldap-binder,dc=example,dc=com
ldap_default_authtok = StrongPassword123!
ldap_tls_reqcert = demand
enumerate = False
cache_credentials = True

После запуска контейнера проверьте работу sssd командой getent passwd username. Если пользователь из LDAP отображается, интеграция выполнена корректно.

Настройка демона nslcd в Docker-контейнере

nslcd легче sssd и потребляет меньше ресурсов. Он не кэширует учетные данные и не поддерживает офлайн-режим, но для контейнеров, которым нужна только онлайн-аутентификация, это оптимальный выбор.

Dockerfile и конфигурация nslcd для OpenLDAP

FROM debian:12-slim

RUN apt-get update && apt-get install -y \
    nslcd \
    libnss-ldapd \
    libpam-ldapd \
    ldap-utils \
    && rm -rf /var/lib/apt/lists/*

COPY nslcd.conf /etc/nslcd.conf
RUN chmod 600 /etc/nslcd.conf

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

Конфигурация nslcd.conf:

uid nslcd
gid nslcd

uri ldaps://ldap.example.com:636
base dc=example,dc=com
binddn cn=ldap-binder,dc=example,dc=com
bindpw StrongPassword123!

ssl on
tls_reqcert demand

map passwd uid           uid
map passwd uidNumber     uidNumber
map passwd gidNumber     gidNumber
map passwd homeDirectory homeDirectory
map passwd loginShell    loginShell

map group  cn            cn
map group  gidNumber     gidNumber

Настройка NSS для использования nslcd требует изменения /etc/nsswitch.conf в контейнере:

passwd: files ldap
group:  files ldap
shadow: files ldap

Сравнение с sssd: nslcd не поддерживает failover из коробки, для этого нужно настраивать несколько URI в конфигурации. Кэширование отсутствует, при недоступности LDAP-сервера аутентификация не работает. Однако размер образа с nslcd меньше на 30-40 МБ, а потребление памяти ниже на 15-20 МБ по сравнению с sssd.

Интеграция популярных сервисов с LDAP в Docker Compose

Три сервиса покрывают большинство потребностей корпоративной инфраструктуры: Nextcloud для файлового обмена, GitLab для управления кодом, Grafana для мониторинга. Каждый из них имеет встроенную поддержку LDAP, что упрощает интеграцию до минимума.

Nextcloud: подключение к LDAP через переменные окружения

Nextcloud поддерживает LDAP-интеграцию через официальный образ. Переменные окружения передаются в docker-compose.yml, и при первом запуске Nextcloud автоматически настраивает подключение к каталогу.

version: '3.8'

services:
  nextcloud:
    image: nextcloud:29
    container_name: nextcloud
    restart: always
    ports:
      - "8080:80"
    environment:
      - NEXTCLOUD_ADMIN_USER=admin
      - NEXTCLOUD_ADMIN_PASSWORD=admin_password
      - NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.example.com
      - LDAP_HOST=ldaps://dc.domain.local:636
      - LDAP_BASE=DC=domain,DC=local
      - LDAP_BINDDN=CN=ldap-binder,CN=Users,DC=domain,DC=local
      - LDAP_BINDPW=StrongPassword123!
      - LDAP_USER_FILTER=(&(objectClass=user)(memberOf=CN=NextcloudUsers,CN=Users,DC=domain,DC=local))
      - LDAP_LOGIN_FILTER=(&(objectClass=user)(sAMAccountName=%uid))
      - LDAP_GROUP_FILTER=(objectClass=group)
    volumes:
      - nextcloud_data:/var/www/html
    networks:
      - ldap_net

volumes:
  nextcloud_data:

networks:
  ldap_net:
    external: true

Параметр LDAP_USER_FILTER ограничивает доступ только членами группы NextcloudUsers. Это критически важно для безопасности: без фильтра любой пользователь домена сможет войти в Nextcloud.

GitLab: аутентификация через LDAP в gitlab.rb

GitLab настраивается через файл gitlab.rb, который монтируется в контейнер как том. В отличие от Nextcloud, GitLab требует указания конфигурации LDAP в формате Ruby.

version: '3.8'

services:
  gitlab:
    image: gitlab/gitlab-ce:17.0.0-ce.0
    container_name: gitlab
    restart: always
    ports:
      - "443:443"
      - "2222:22"
    volumes:
      - gitlab_config:/etc/gitlab
      - gitlab_logs:/var/log/gitlab
      - gitlab_data:/var/opt/gitlab
      - ./gitlab.rb:/etc/gitlab/gitlab.rb:ro
    networks:
      - ldap_net

volumes:
  gitlab_config:
  gitlab_logs:
  gitlab_data:

networks:
  ldap_net:
    external: true

Фрагмент gitlab.rb с настройками LDAP для Active Directory:

gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
  main:
    label: 'Active Directory'
    host: 'dc.domain.local'
    port: 636
    uid: 'sAMAccountName'
    bind_dn: 'CN=ldap-binder,CN=Users,DC=domain,DC=local'
    password: 'StrongPassword123!'
    encryption: 'simple_tls'
    verify_certificates: true
    base: 'DC=domain,DC=local'
    user_filter: '(memberOf=CN=GitLabUsers,CN=Users,DC=domain,DC=local)'
EOS

Для OpenLDAP измените uid на 'uid' и user_filter на соответствующий фильтр групп.

Grafana: настройка LDAP-аутентификации

Grafana использует файл ldap.toml для конфигурации LDAP. Файл монтируется в контейнер, и Grafana автоматически подхватывает настройки при запуске.

version: '3.8'

services:
  grafana:
    image: grafana/grafana:11.0.0
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"
    environment:
      - GF_AUTH_LDAP_ENABLED=true
      - GF_AUTH_LDAP_CONFIG_FILE=/etc/grafana/ldap.toml
    volumes:
      - grafana_data:/var/lib/grafana
      - ./ldap.toml:/etc/grafana/ldap.toml:ro
    networks:
      - ldap_net

volumes:
  grafana_data:

networks:
  ldap_net:
    external: true

Пример ldap.toml для OpenLDAP:

[[servers]]
host = "ldap.example.com"
port = 636
use_ssl = true
start_tls = false
ssl_skip_verify = false
bind_dn = "cn=ldap-binder,dc=example,dc=com"
bind_password = "StrongPassword123!"
search_filter = "(uid=%s)"
search_base_dns = ["ou=users,dc=example,dc=com"]

[servers.attributes]
name = "givenName"
surname = "sn"
username = "uid"
member_of = "memberOf"
email = "mail"

[[servers.group_mappings]]
group_dn = "cn=grafana_admins,ou=groups,dc=example,dc=com"
org_role = "Admin"

[[servers.group_mappings]]
group_dn = "cn=grafana_viewers,ou=groups,dc=example,dc=com"
org_role = "Viewer"

Маппинг групп позволяет автоматически назначать роли в Grafana на основе членства в LDAP-группах. Пользователь, добавленный в группу grafana_admins, сразу получает права администратора без ручного вмешательства.

Диагностика и устранение типовых ошибок LDAP-аутентификации

Систематический подход к диагностике сокращает время простоя с часов до минут. Первое правило: проверяйте каждый уровень стека отдельно, от сети до приложения.

Проверка подключения к LDAP-серверу из контейнера

Базовая проверка сетевой доступности выполняется утилитой ldapsearch. Запустите её внутри контейнера:

docker exec -it container_name ldapsearch -x -H ldaps://dc.domain.local:636 -D "CN=ldap-binder,CN=Users,DC=domain,DC=local" -W -b "DC=domain,DC=local"

Если команда возвращает результаты поиска, сетевой уровень и аутентификация работают. Типовые ошибки на этом этапе:

  • Can't contact LDAP server: проверьте DNS-резолвинг внутри контейнера, доступность порта 636 через telnet или nc.
  • TLS certificate verification failed: сертификат LDAP-сервера не доверенный. Временно установите LDAPTLS_REQCERT=never для диагностики, в production импортируйте корневой сертификат в контейнер.
  • Invalid credentials: неверный bind DN или пароль. Проверьте экранирование специальных символов в DN.

Типовые ошибки конфигурации sssd и nslcd

Логи sssd находятся в /var/log/sssd/ внутри контейнера. Включите детальное логирование для диагностики, добавив в секцию [domain] файла sssd.conf:

debug_level = 7

Распространенные проблемы sssd:

  • Неверный id_provider: для LDAP должен быть указан "ldap", а не "ad" (последний используется только при прямом присоединении к домену AD).
  • Ошибка прав доступа к sssd.conf: файл должен иметь права 600 и владельца root:root.
  • Кэширование устаревших данных: очистите кэш командой sss_cache -E перед повторной проверкой.

Для nslcd логи пишутся в syslog. Запустите nslcd в foreground-режиме с флагом -d для отладки:

nslcd -d

Проблемы интеграции с конкретными сервисами

Nextcloud: ошибка "LDAP extension not found" означает, что в контейнере отсутствует PHP-расширение ldap. В официальном образе Nextcloud оно установлено, но при использовании кастомных образов проверьте наличие пакета php-ldap.

GitLab: сообщение "Could not authenticate you from Ldapmain" указывает на неверный формат uid. Для Active Directory используйте sAMAccountName, для OpenLDAP - uid. Проверьте, что пользователь существует в каталоге и соответствует user_filter.

Grafana: неверный маппинг групп проявляется в том, что пользователь входит, но получает роль Viewer вместо Admin. Проверьте, что group_dn в ldap.toml точно соответствует DN группы в LDAP, включая регистр символов.

Организация единого входа (SSO) для Docker-инфраструктуры

SSO на базе LDAP работает по принципу: пользователь аутентифицируется один раз, а все сервисы доверяют результатам этой аутентификации. В контейнерной среде каждый сервис независимо проверяет credentials через LDAP, но для пользователя это выглядит как единый вход, если браузер сохраняет сессию.

Полноценный SSO с прозрачной аутентификацией между сервисами требует дополнительного компонента - Identity Provider (IdP), например Keycloak или Authelia, который поддерживает протоколы OIDC или SAML. Однако для большинства корпоративных сценариев достаточно LDAP-аутентификации с одинаковыми учетными данными.

Пример docker-compose.yml с тремя сервисами, использующими общий LDAP-сервер:

version: '3.8'

services:
  nextcloud:
    image: nextcloud:29
    environment:
      - LDAP_HOST=ldaps://ldap.example.com:636
      - LDAP_BASE=dc=example,dc=com
      - LDAP_BINDDN=cn=ldap-binder,dc=example,dc=com
      - LDAP_BINDPW=StrongPassword123!
    networks:
      - ldap_net

  gitlab:
    image: gitlab/gitlab-ce:17.0.0-ce.0
    volumes:
      - ./gitlab.rb:/etc/gitlab/gitlab.rb:ro
    networks:
      - ldap_net

  grafana:
    image: grafana/grafana:11.0.0
    volumes:
      - ./ldap.toml:/etc/grafana/ldap.toml:ro
    networks:
      - ldap_net

networks:
  ldap_net:
    external: true

Управление доступом через группы LDAP - ключевой механизм безопасности. Создайте отдельные группы для каждого сервиса: NextcloudUsers, GitLabDevelopers, GrafanaAdmins. Пользователь получает доступ только к тем сервисам, в группах которых он состоит. Это реализует принцип минимальных привилегий на уровне инфраструктуры.

Заключение: чек-лист для быстрой настройки LDAP в Docker Compose

Внедрение LDAP-аутентификации для Docker-инфраструктуры сводится к пяти шагам. Пройдите их последовательно, проверяя результат на каждом этапе.

  1. Подготовьте LDAP-сервер: создайте пользователя для биндинга с правами чтения каталога, настройте группы для управления доступом, проверьте доступность портов 389/636.
  2. Выберите метод интеграции: для сервисов со встроенной поддержкой LDAP (Nextcloud, GitLab, Grafana) используйте переменные окружения или конфигурационные файлы. Для сервисов без поддержки LDAP внедрите sssd или nslcd в образ контейнера.
  3. Настройте сервисы: скопируйте готовые конфигурации из этого руководства, подставив свои параметры подключения. Проверьте фильтры пользователей и групп.
  4. Проверьте аутентификацию: выполните тестовый вход под учетной записью из LDAP. При ошибках используйте ldapsearch и логи демонов для диагностики.
  5. Настройте управление доступом: ограничьте вход в сервисы через LDAP-группы, регулярно аудируйте членство в группах.

Для углубленного изучения Docker и построения надежной контейнерной инфраструктуры рекомендуем практическое руководство по Docker для системных администраторов и полное руководство по Docker в 2026 году.

Если вам нужна облачная инфраструктура для развертывания контейнеров, Timeweb Cloud предоставляет VDS, Kubernetes и управляемые базы данных с гибким масштабированием.

Поделиться:
Сохранить гайд? В закладки браузера