LDAP-аутентификация в Kubernetes: пошаговое руководство для DevOps | AdminWiki

LDAP-аутентификация в Kubernetes: пошаговое руководство для DevOps

29 июля 2026 10 мин. чтения

Зачем нужна LDAP-аутентификация в Kubernetes

Kubernetes по умолчанию использует статические токены, X.509-сертификаты или сервис-аккаунты для аутентификации. При росте команды эти механизмы превращаются в административный ад. Каждый новый инженер требует ручной генерации сертификата или внесения записи в статический файл. При увольнении сертификат нужно отзывать, а токен - удалять из всех кластеров. Ошибки неизбежны: забыли удалить доступ, и бывший сотрудник сохранил возможность подключаться к production-окружению.

LDAP-аутентификация решает эту проблему через централизованное управление. Kubernetes делегирует проверку учётных данных внешнему провайдеру - Active Directory или OpenLDAP. Пользователь вводит корпоративный логин и пароль. Кластер проверяет их через настроенный OIDC-провайдер и выпускает краткосрочный токен. RBAC-роли привязываются к LDAP-группам, а не к конкретным учётным записям. Добавили сотрудника в группу k8s-admin - он автоматически получил права администратора. Переместили в k8s-view - остались права только на чтение.

Результат: единая точка входа для всех корпоративных систем, отсутствие ручного управления учётными данными Kubernetes и автоматическое применение принципа минимальных привилегий. Для более глубокого понимания различий между механизмами аутентификации и авторизации изучите наше руководство по аутентификации и авторизации с разбором LDAP, OAuth 2.0, JWT и моделей RBAC/ABAC.

Выбор подхода: Dex или прямая настройка kube-apiserver

Два основных способа интегрировать LDAP с Kubernetes: развернуть OIDC-провайдер Dex или настроить вебхук-аутентификатор напрямую в kube-apiserver. Выбор зависит от размера инфраструктуры и требований к удобству пользователей.

Dex выступает прослойкой между Kubernetes и LDAP. Он принимает учётные данные, проверяет их в каталоге и возвращает стандартный OIDC-токен. Kube-apiserver работает только с этим токеном, не имея прямого доступа к LDAP. Прямая интеграция через вебхук заставляет API-сервер самостоятельно обращаться к LDAP при каждом запросе. Разберём оба варианта.

Dex как OIDC-провайдер: плюсы и архитектура

Dex - проект CNCF, созданный специально для федеративной аутентификации в Kubernetes. Он не хранит пароли и не управляет пользователями. Его задача - преобразовать учётные данные из LDAP в OIDC-токен, понятный kube-apiserver.

Поток аутентификации выглядит так:

  1. Пользователь запускает kubectl с настроенным OIDC-плагином.
  2. Плагин открывает браузер и направляет пользователя на Dex.
  3. Dex показывает форму входа или перенаправляет на LDAP-сервер.
  4. Пользователь вводит логин и пароль. Dex проверяет их через bind к LDAP.
  5. При успехе Dex выпускает id_token с claims: username, groups, email.
  6. Kubectl прикрепляет токен к каждому запросу к API-серверу.
  7. Kube-apiserver валидирует подпись токена и извлекает claims.
  8. RBAC-авторизатор сопоставляет группы из токена с RoleBinding.

Dex поддерживает Active Directory и OpenLDAP через единый коннектор. Конфигурация сводится к указанию параметров подключения и маппинга атрибутов. Пользователи получают привычный браузерный вход, а не возню с сертификатами.

Прямая интеграция LDAP с kube-apiserver: когда это оправдано

Прямая интеграция настраивается через флаг --authentication-token-webhook-config-file в манифесте kube-apiserver. Вы создаёте конфигурационный файл, описывающий HTTP-эндпоинт, который принимает токен и возвращает информацию о пользователе. Этот эндпоинт реализует логику проверки учётных данных через LDAP.

Метод подходит для небольших кластеров, где нет возможности развернуть Dex. Минусы серьёзные: отсутствие единого входа, необходимость управлять токенами на стороне клиента, ручная реализация вебхука. При каждом запросе kube-apiserver дёргает внешний сервис, что добавляет задержку и создаёт дополнительную точку отказа. Для команд от пяти человек и production-кластеров Dex - однозначный выбор.

Подготовка LDAP-окружения

Перед развёртыванием Dex нужно подготовить LDAP-сервер. Требования: работающий Active Directory или OpenLDAP, служебная учётная запись с правами на чтение каталога, структура групп для Kubernetes RBAC.

Создание служебной учетной записи для Dex

Dex требуется учётная запись для выполнения поисковых запросов к LDAP. Использовать администраторскую учётку - грубая ошибка безопасности. Создайте отдельного пользователя с минимальными привилегиями.

Для Active Directory через PowerShell:

New-ADUser -Name "dex-svc" -SamAccountName "dex-svc" -UserPrincipalName "dex-svc@domain.local" -Enabled $true -AccountPassword (ConvertTo-SecureString "StrongPassword123!" -AsPlainText -Force)

Для OpenLDAP через LDIF:

dn: cn=dex-svc,ou=service-accounts,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: dex-svc
userPassword: {SSHA}hashed_password_here

Учётной записи нужны права на чтение поддерева с пользователями и группами. Для Active Directory этого достаточно - рядовой пользователь домена может читать большинство атрибутов. Для OpenLDAP настройте ACL, разрешающий доступ к ou=users и ou=groups.

Формирование LDAP-групп для Kubernetes RBAC

Спроектируйте группы в LDAP так, чтобы они соответствовали ролям в Kubernetes. Рекомендуемая схема:

  • k8s-admin - полный доступ ко всем ресурсам кластера (аналог cluster-admin).
  • k8s-edit - права на изменение ресурсов в своих namespace.
  • k8s-view - права только на чтение в определённых namespace.

В Active Directory создайте группы безопасности:

New-ADGroup -Name "k8s-admin" -GroupScope Global -GroupCategory Security
New-ADGroup -Name "k8s-edit" -GroupScope Global -GroupCategory Security
New-ADGroup -Name "k8s-view" -GroupScope Global -GroupCategory Security
Add-ADGroupMember -Identity "k8s-admin" -Members "username"

В OpenLDAP используйте objectClass groupOfNames или groupOfUniqueNames. Поле member должно содержать DN пользователей.

Проверьте структуру каталога через ldapsearch:

ldapsearch -H ldap://ldap.example.com -D "cn=dex-svc,ou=service-accounts,dc=example,dc=com" -w password -b "dc=example,dc=com" "(objectClass=group)"

Развертывание Dex в Kubernetes

Установка Dex через Helm - самый быстрый способ получить рабочий OIDC-провайдер. Добавьте репозиторий и создайте файл конфигурации.

helm repo add dex https://charts.dexidp.io
helm repo update

Конфигурация Dex для подключения к LDAP

Создайте ConfigMap с настройками Dex. Ключевая секция - connectors, описывающая подключение к LDAP.

Пример для Active Directory:

connectors:
- type: ldap
  id: ad
  name: Active Directory
  config:
    host: ad.example.com:636
    insecureNoSSL: false
    insecureSkipVerify: false
    rootCA: /etc/dex/ldap-ca.crt
    bindDN: CN=dex-svc,OU=service-accounts,DC=example,DC=com
    bindPW: StrongPassword123!
    userSearch:
      baseDN: OU=Users,DC=example,DC=com
      filter: "(objectClass=person)"
      username: sAMAccountName
      idAttr: sAMAccountName
      emailAttr: mail
      nameAttr: displayName
    groupSearch:
      baseDN: OU=Groups,DC=example,DC=com
      filter: "(objectClass=group)"
      userAttr: DN
      groupAttr: member
      nameAttr: cn

Пример для OpenLDAP:

connectors:
- type: ldap
  id: openldap
  name: OpenLDAP
  config:
    host: ldap.example.com:636
    insecureNoSSL: false
    rootCA: /etc/dex/ldap-ca.crt
    bindDN: cn=dex-svc,ou=service-accounts,dc=example,dc=com
    bindPW: StrongPassword123!
    userSearch:
      baseDN: ou=users,dc=example,dc=com
      filter: "(objectClass=inetOrgPerson)"
      username: uid
      idAttr: uid
      emailAttr: mail
      nameAttr: cn
    groupSearch:
      baseDN: ou=groups,dc=example,dc=com
      filter: "(objectClass=groupOfNames)"
      userAttr: DN
      groupAttr: member
      nameAttr: cn

Параметр userSearch.username определяет, какой атрибут LDAP пользователь будет вводить как логин. groupSearch.nameAttr задаёт имя группы, которое попадёт в claims токена и будет использоваться в RoleBinding.

Настройка статических клиентов в Dex

Секция staticClients регистрирует приложения, которым Dex разрешён выпуск токенов. Для kubectl настройте клиент с localhost-редиректом:

staticClients:
- id: kubernetes
  name: Kubernetes
  secret: a-strong-client-secret
  redirectURIs:
  - http://localhost:8000/callback
  - http://localhost:18000/callback

Порт 8000 используется плагином kubectl oidc-login по умолчанию, 18000 - запасной вариант, если первый занят.

Полный файл values.yaml для Helm:

config:
  issuer: https://dex.example.com
  storage:
    type: kubernetes
    config:
      inCluster: true
  web:
    http: 0.0.0.0:5556
  connectors:
  - type: ldap
    id: ad
    name: Active Directory
    config:
      host: ad.example.com:636
      insecureNoSSL: false
      rootCA: /etc/dex/ldap-ca.crt
      bindDN: CN=dex-svc,OU=service-accounts,DC=example,DC=com
      bindPW: StrongPassword123!
      userSearch:
        baseDN: OU=Users,DC=example,DC=com
        filter: "(objectClass=person)"
        username: sAMAccountName
        idAttr: sAMAccountName
        emailAttr: mail
        nameAttr: displayName
      groupSearch:
        baseDN: OU=Groups,DC=example,DC=com
        filter: "(objectClass=group)"
        userAttr: DN
        groupAttr: member
        nameAttr: cn
  staticClients:
  - id: kubernetes
    name: Kubernetes
    secret: a-strong-client-secret
    redirectURIs:
    - http://localhost:8000/callback
    - http://localhost:18000/callback

ingress:
  enabled: true
  hosts:
  - dex.example.com
  tls:
  - secretName: dex-tls
    hosts:
    - dex.example.com

Установите Dex:

helm install dex dex/dex -f values.yaml -n auth --create-namespace

Интеграция Kubernetes с Dex через OIDC

После запуска Dex настройте kube-apiserver на приём OIDC-токенов и создайте kubeconfig для пользователей.

Настройка kube-apiserver для OIDC

Добавьте флаги в манифест kube-apiserver (обычно /etc/kubernetes/manifests/kube-apiserver.yaml):

--oidc-issuer-url=https://dex.example.com
--oidc-client-id=kubernetes
--oidc-username-claim=name
--oidc-groups-claim=groups
--oidc-username-prefix=oidc:
--oidc-groups-prefix=oidc:

Разбор параметров:

  • oidc-issuer-url - URL Dex, должен совпадать с issuer из конфигурации.
  • oidc-client-id - идентификатор клиента из staticClients.
  • oidc-username-claim - поле в токене, которое станет именем пользователя в Kubernetes.
  • oidc-groups-claim - поле в токене, содержащее список групп.
  • oidc-username-prefix - префикс, добавляемый к имени пользователя. Помогает избежать конфликтов с другими методами аутентификации.
  • oidc-groups-prefix - префикс для групп.

После изменения манифеста kube-apiserver автоматически перезапустится. Проверьте логи на наличие ошибок:

kubectl logs -n kube-system kube-apiserver-controlplane | grep oidc

Создание kubeconfig для конечных пользователей

Установите плагин kubectl oidc-login:

kubectl krew install oidc-login

Сгенерируйте kubeconfig для пользователя:

kubectl config set-credentials username \
  --auth-provider=oidc \
  --auth-provider-arg=idp-issuer-url=https://dex.example.com \
  --auth-provider-arg=client-id=kubernetes \
  --auth-provider-arg=client-secret=a-strong-client-secret \
  --auth-provider-arg=idp-certificate-authority=/path/to/ca.crt \
  --auth-provider-arg=id-token= \
  --auth-provider-arg=refresh-token=

kubectl config set-context username-context \
  --cluster=your-cluster \
  --user=username

kubectl config use-context username-context

При первом запуске kubectl плагин откроет браузер, перенаправит на Dex, тот проверит учётные данные в LDAP и вернёт токен. Токен сохранится в kubeconfig и будет автоматически обновляться через refresh-токен.

Привязка RBAC к LDAP-группам

Главная цель интеграции - автоматическое назначение прав на основе членства в LDAP-группах. После успешной аутентификации Dex включает группы пользователя в claims токена. Kube-apiserver извлекает их с префиксом oidc: и передаёт RBAC-авторизатору.

Создание ролей и привязок для типовых сценариев

Создайте ClusterRoleBinding для группы администраторов:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ldap-admin-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: oidc:k8s-admin

Для разработчиков создайте RoleBinding в конкретном namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ldap-edit-binding
  namespace: development
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: edit
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: oidc:k8s-edit

Для наблюдателей - права на чтение:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ldap-view-binding
  namespace: development
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: oidc:k8s-view

Имя группы в subjects.name - это значение атрибута, указанного в groupSearch.nameAttr (обычно cn), с префиксом oidc:. Подробнее о настройке RBAC и управлении доступом читайте в нашем руководстве по группам безопасности через LDAP.

Проверка и отладка RBAC-настроек

Проверьте права текущего пользователя:

kubectl auth can-i create deployments --namespace development
kubectl auth can-i get pods --all-namespaces

Проверьте, какие группы видны в токене. Декодируйте id_token через jwt.io или командой:

kubectl get --raw /apis/openidconnect/v1/userinfo | jq .

Типичные ошибки: несовпадение регистра в именах групп, забытый префикс oidc:, опечатка в nameAttr. Проверьте конфигурацию Dex: параметр groupSearch.nameAttr должен указывать на атрибут, значение которого вы используете в RoleBinding.

Обеспечение безопасности и масштабируемости

Для production-среды обязательны TLS на всех соединениях и высокая доступность Dex.

Настройка TLS для Dex и LDAP

Все соединения должны быть зашифрованы:

  • Пользовательский браузер до Dex - HTTPS через Ingress с сертификатом.
  • Dex до LDAP - LDAPS (порт 636) с проверкой сертификата сервера.
  • Kube-apiserver до Dex - HTTPS с проверкой сертификата.

Выпустите сертификат для Dex через cert-manager:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: dex-tls
  namespace: auth
spec:
  secretName: dex-tls
  dnsNames:
  - dex.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

Для LDAPS укажите корневой CA в конфигурации Dex через параметр rootCA. Монтируйте сертификат в под Dex через Secret.

Высокая доступность Dex

Dex поддерживает запуск нескольких реплик с общим хранилищем состояния. Встроенные варианты - Kubernetes CRD, etcd, PostgreSQL. Для production-среды увеличьте количество реплик:

replicaCount: 3

Настройте Service для балансировки:

service:
  type: ClusterIP
  port: 5556

Ingress будет направлять трафик на Service, а тот распределять между подами. Состояние (выпущенные refresh-токены, коды авторизации) хранится в общем хранилище, поэтому пользователь может попасть на любую реплику.

Для мониторинга Dex предоставляет метрики Prometheus на эндпоинте /metrics. Настройте сбор логов в централизованную систему - это поможет при диагностике проблем аутентификации.

Типичные проблемы и их решение

За годы интеграций LDAP с Kubernetes мы выделили повторяющиеся проблемы. Вот их причины и способы исправления.

Ошибки подключения Dex к LDAP

Симптом: в логах Dex сообщение ldap: bind failed: invalid credentials.

Причина: неверный bindDN или пароль служебной учётной записи.

Решение: проверьте учётные данные через ldapsearch:

ldapsearch -H ldap://ad.example.com -D "CN=dex-svc,OU=service-accounts,DC=example,DC=com" -w password -b "DC=example,DC=com" "(objectClass=*)"

Если команда возвращает Invalid Credentials, сбросьте пароль и обновите ConfigMap Dex.

Симптом: certificate signed by unknown authority.

Причина: Dex не доверяет сертификату LDAP-сервера.

Решение: экспортируйте корневой CA LDAP-сервера и укажите его в параметре rootCA конфигурации Dex. Монтируйте сертификат в под через Secret. Если используется самоподписанный сертификат, временно можно установить insecureSkipVerify: true для отладки, но никогда не оставляйте этот параметр в production. Быструю диагностику LDAP-подключений можно выполнить по нашей шпаргалке по диагностике LDAP.

Пользователь не получает ожидаемые права

Симптом: аутентификация успешна, но kubectl возвращает forbidden.

Причина 1: группы из LDAP не попадают в токен.

Проверка: декодируйте токен и посмотрите поле groups. Если оно пустое, проверьте groupSearch в конфигурации Dex. Параметр userAttr должен содержать атрибут пользователя, значение которого ищется в groupAttr группы. Для Active Directory это DN и member соответственно.

Причина 2: несовпадение имени группы в RoleBinding и токене.

Проверка: сравните значение из поля groups токена с именем в subjects.name RoleBinding. Учитывайте префикс oidc: и регистр символов. В Active Directory имена групп чувствительны к регистру в контексте LDAP-запросов.

Причина 3: пользователь не состоит в нужной группе LDAP.

Проверка: выполните ldapsearch для конкретного пользователя и убедитесь, что его DN присутствует в атрибуте member группы.

После исправления конфигурации перезапустите Dex и запросите новый токен через kubectl с флагом --token="" для принудительного обновления.

Для усиления безопасности кластера после настройки LDAP-аутентификации рекомендуем внедрить двухфакторную аутентификацию для Kubernetes. Это добавит дополнительный уровень защиты для kubectl и веб-интерфейсов.

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