Зачем нужна 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.
Поток аутентификации выглядит так:
- Пользователь запускает
kubectlс настроенным OIDC-плагином. - Плагин открывает браузер и направляет пользователя на Dex.
- Dex показывает форму входа или перенаправляет на LDAP-сервер.
- Пользователь вводит логин и пароль. Dex проверяет их через bind к LDAP.
- При успехе Dex выпускает id_token с claims: username, groups, email.
- Kubectl прикрепляет токен к каждому запросу к API-серверу.
- Kube-apiserver валидирует подпись токена и извлекает claims.
- 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 и веб-интерфейсов.