Сегодня я подробно разберу настройку аутентификации в Kubernetes с помощью Dex в связке с LDAP, а также покажу, как можно добавлять статических пользователей в Dex.
В статье не буду останавливаться на основных принципах работы Dex, а сразу перейду к установке и настройке LDAP. Познакомиться с принципами работы Dex можно в этой статье.
Что будем делать:
Итак, поехали.
Показывать буду на примере уже готового кластера Kubernetes с Helm версии 3 и Ingress, а также тремя доменными именами.
В качестве LDAP будем использовать OpenLDAP на дистрибутиве ubuntu 18.04.
Имя нашего сервера: openldap.dtln.cloud.
Переходим к настройке кластера Kubernetes.
Домен dex.ash.dtln.cloud используем для обращения Dex к API-серверу, а login.ash.dtln.cloud – для получения доступа к кластеру.
Мы разворачивали кластер без установщиков kubeadm или kops, так что OIDC-конфигурацию можно сразу добавлять в systemd-юнит. В остальных случаях настройку лучше сделать с помощью этих утилит.
Теперь переходим в кластер Kubernetes.
Для Dex нам понадобятся ca.crt, ca.key c мастер-сервера. Обычно они лежат в каталоге /etc/kubernetes/pki/
Также нужен сгенерированный нами раннее CA-сертификат с OpenLDAP, расположенный по пути /etc/ssl/certs/cacert.pem
На этом настройка Dex в связке с OpenLDAP закончена.
Пара советов напоследок:
В статье не буду останавливаться на основных принципах работы Dex, а сразу перейду к установке и настройке LDAP. Познакомиться с принципами работы Dex можно в этой статье.
Что будем делать:
- Установим OpenLDAP и настроим на нем поддержку STARTTLS.
- Опишем структуру LDAP-каталога нашей организации.
- Включим поддержку OIDC (OpenID Connect) на kube-api-серверах.
- Получим SAN-сертификат для доменов, которые будет использовать Dex.
- Установим Dex и Dex-auth, где мы опишем LDAP-каталог и статических пользователей.
- Сгенерируем kubeconfig нашего пользователя для работы с кластером.
- Настроим RBAC-авторизацию для групп и пользователей в кластере.
Итак, поехали.
Показывать буду на примере уже готового кластера Kubernetes с Helm версии 3 и Ingress, а также тремя доменными именами.
Устанавливаем и настраиваем OpenLDAP-сервер
В качестве LDAP будем использовать OpenLDAP на дистрибутиве ubuntu 18.04.
Имя нашего сервера: openldap.dtln.cloud.
- Подключаемся к серверу и приступаем к установке OpenLDAP. В процессе установки нам предложат установить пароль:
sudo apt update sudo apt install slapd ldap-utils
- Переконфигурируем OpenLDAP для нашего домена:
sudo dpkg-reconfigure slapd
- Выбираем No:
- Вводим доменное имя:
- Вводим имя организации:
- Повторяем ввод пароля:
- Включаем поддержку STARTTLS. Ставим необходимые пакеты:
sudo apt install gnutls-bin ssl-cert
- Генерируем CA-ключ:
sudo sh -c "certtool --generate-privkey > /etc/ssl/private/cakey.pem"
- Описываем нашу организацию в /etc/ssl/ca.info:
cn = DTLN Company ca cert_signing_key
- Генерируем CA-сертификaт и ключ, который в дальнейшем будем использовать:
sudo certtool --generate-self-signed --load-privkey /etc/ssl/private/cakey.pem --template /etc/ssl/ca.info --outfile /etc/ssl/certs/cacert.pem sudo certtool --generate-privkey --bits 1024 --outfile /etc/ssl/private/openldap_key.pem
- Создаем шаблон для сертификата /etc/ssl/openldap.info:
organization = DTLN Company cn = openldap.dtln.cloud tls_www_server encryption_key signing_key expiration_days = 3650
- Генерируем сам сертификат:
sudo certtool --generate-certificate --load-privkey /etc/ssl/private/openldap_key.pem --load-ca-certificate /etc/ssl/certs/cacert.pem --load-ca-privkey /etc/ssl/private/cakey.pem --template /etc/ssl/openldap.info --outfile /etc/ssl/certs/openldap.pem
- Настраиваем OpenLDAP для работы со STARTTLS. Вот что должно быть внутри файла certinfo.dif:
dn: cn=config add: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem - add: olcTLSCertificateFile olcTLSCertificateFile: /etc/ssl/certs/openldap.pem - add: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/ssl/private/openldap_key.pem
- Применяем созданный нами файл следующей командой:
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f certinfo.dif
- Назначаем права доступа на сертификат и перезапускаем наш сервис:
sudo chgrp openldap /etc/ssl/private/openldap_key.pem sudo chmod 0640 /etc/ssl/private/openldap_key.pem sudo gpasswd -a openldap ssl-cert sudo systemctl restart slapd.service
- Чтобы проверить работу нашего сервиса с сертификатами, добавляем в /etc/ldap/ldap.conf строчку:
TLS_CACERT /etc/ssl/certs/cacert.pem
- Проверяем работу через STARTTLS:
ldapwhoami -H ldap://openldap.dtln.cloud -x -ZZ
В случае успеха получаем:
В случае проблемы проверяем еще раз пути до сертификатов и выполнение команд:
Описываем структуру LDAP-каталога
- Теперь опишем структуру каталога, создадим группы и двуx пользователей, которые будут ходить в Kubernetes. Создаем файл content.ldif:
dn: ou=People,dc=openldap,dc=dtln,dc=cloud objectClass: organizationalUnit ou: People dn: cn=jane,ou=People,dc=openldap,dc=dtln,dc=cloud objectClass: person objectClass: inetOrgPerson sn: doe cn: jane mail: janedoe@openldap.dtln.cloud userpassword: foo_password dn: cn=john,ou=People,dc=openldap,dc=dtln,dc=cloud objectClass: person objectClass: inetOrgPerson sn: doe cn: john mail: johndoe@openldap.dtln.cloud userpassword: bar_password # Group definitions. dn: ou=Groups,dc=openldap,dc=dtln,dc=cloud objectClass: organizationalUnit ou: Groups dn: cn=admins,ou=Groups,dc=openldap,dc=dtln,dc=cloud objectClass: groupOfNames cn: admins member: cn=jane,ou=People,dc=openldap,dc=dtln,dc=cloud dn: cn=developers,ou=Groups,dc=openldap,dc=dtln,dc=cloud objectClass: groupOfNames cn: developers member: cn=jane,ou=People,dc=openldap,dc=dtln,dc=cloud member: cn=john,ou=People,dc=openldap,dc=dtln,dc=cloud
- Разворачиваем описанную структуру командой:
ldapadd -x -D cn=admin,dc=openldap,dc=dtln,dc=cloud -W -f content.ldif
- Удостоверимся в наличии наших пользователей в каталоге:
ldapwhoami -vvv -h openldap.dtln.cloud -p 389 -D cn=john,ou=People,dc=openldap,dc=dtln,dc=cloud -x -w bar_password -ZZ ldapwhoami -vvv -h openldap.dtln.cloud -p 389 -D cn=jane,ou=People,dc=openldap,dc=dtln,dc=cloud -x -w foo_password -ZZ
Подключаем поддержку OpenID Connect
Переходим к настройке кластера Kubernetes.
Домен dex.ash.dtln.cloud используем для обращения Dex к API-серверу, а login.ash.dtln.cloud – для получения доступа к кластеру.
Мы разворачивали кластер без установщиков kubeadm или kops, так что OIDC-конфигурацию можно сразу добавлять в systemd-юнит. В остальных случаях настройку лучше сделать с помощью этих утилит.
- Редактируем юнит /etc/systemd/system/kube-apiserver.service и добавляем параметры запуска в секцию ExecStart:
--oidc-client-id=dex-k8s-authenticator --oidc-groups-claim=groups --oidc-username-claim=email --oidc-issuer-url=https://dex.ash.dtln.cloud/
- Рестартуем наши API, проверяем, что они поднялись:
sudo systemctl daemon-reload sudo systemctl restart kube-apiserver sudo systemctl status kube-apiserver
Создаем мультидоменный сертификат
Теперь переходим в кластер Kubernetes.
- Ставим cert-manager, используя Helm:
helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager --namespace kube-system jetstack/cert-manager --version v0.13.0
- Описываем запрос на получение SAN-сертификата для наших доменов в cert.yml:
--- apiVersion: cert-manager.io/v1alpha2 kind: ClusterIssuer metadata: name: letsencrypt-dex spec: acme: email: kubernetes@dataline.ru server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-key-dex solvers: - http01: ingress: class: nginx --- apiVersion: cert-manager.io/v1alpha2 kind: Certificate metadata: name: auth-dex namespace: kube-system spec: secretName: cert-auth-dex issuerRef: kind: ClusterIssuer name: letsencrypt-dex commonName: dex.ash.dtln.cloud dnsNames: - dex.ash.dtln.cloud - login.ash.dtln.cloud
- Выполняем команду:
kubectl apply -f cert.yaml
- Теперь смотрим состояние нашего запроса на получение сертификата следующими командами:
kubectl get certificates --all-namespaces kubectl get challenges --all-namespaces
- Ждем подтверждения, процесс может занять некоторое время:
Устанавливаем Dex
Для Dex нам понадобятся ca.crt, ca.key c мастер-сервера. Обычно они лежат в каталоге /etc/kubernetes/pki/
Также нужен сгенерированный нами раннее CA-сертификат с OpenLDAP, расположенный по пути /etc/ssl/certs/cacert.pem
- Скачиваем исходники dex-authenticator и переходим в каталог:
git clone git@github.com:mintel/dex-k8s-authenticator.git cd dex-k8s-authenticator/
- Готовим конфиг для Dex-auth, вставляем содержимое ранее скопированного ca.crt, важно соблюдать отступы:
--- global: deployEnv: prod dexK8sAuthenticator: clusters: - name: 'ash.dtln.cloud' short_description: "k8s cluster" description: "Kubernetes cluster" issuer: https://dex.ash.dtln.cloud/ k8s_master_uri: https://kubernetes.dtln.cloud:6443 # url or ip client_id: dex-k8s-authenticator static_context_name: false client_secret: acDEgDEcIg7RX0U7A9hlW2pGGraHDuMAZ4qFEKg2fUHHxr8 redirect_uri: https://login.ash.dtln.cloud/callback k8s_ca_pem: | -----BEGIN CERTIFICATE----- # Вставляем содержимое ca.crt -----END CERTIFICATE----- ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx kubernetes.io/tls-acme: "true" path: / hosts: - login.ash.dtln.cloud tls: - secretName: cert-auth-dex hosts: - login.ash.dtln.cloud
- Переводим содержимое cacert.pem в base64, чтобы добавить его в конфиг:
cacert.pem | base64
- Готовим конфиг для Dex, также важно соблюдать отступы. По желанию добавляем статических пользователей в секцию staticPasswords и генерируем им пароль в формате bcrypt:
--- global: deployEnv: prod tls: certificate: |- -----BEGIN CERTIFICATE----- #содержимое ca.crt -----END CERTIFICATE----- key: |- -----BEGIN RSA PRIVATE KEY----- #содержимое ca.key -----END RSA PRIVATE KEY----- ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx kubernetes.io/tls-acme: "true" path: / hosts: - dex.ash.dtln.cloud tls: - secretName: cert-auth-dex hosts: - dex.ash.dtln.cloud serviceAccount: create: true name: dex-auth-sa config: issuer: https://dex.ash.dtln.cloud/ storage: type: kubernetes config: inCluster: true web: http: 0.0.0.0:5556 frontend: theme: "coreos" issuer: "kube-dtln" issuerUrl: "https://login.ash.dtln.cloud" expiry: signingKeys: "6h" idTokens: "24h" logger: level: debug format: json oauth2: responseTypes: ["code", "token", "id_token"] skipApprovalScreen: true connectors: - type: ldap id: ldap name: LDAP config: insecureNoSSL: false insecureSkipVerify: false startTLS: true # Включаем безопасное соединение rootCAData: |- #Содержимое cacert.pem в base64 #соблюдаем отступы host: openldap.dtln.cloud:389 usernamePrompt: Email Address userSearch: baseDN: ou=People,dc=openldap,dc=dtln,dc=cloud filter: "(objectClass=person)" username: mail idAttr: DN emailAttr: mail nameAttr: cn groupSearch: baseDN: ou=Groups,dc=openldap,dc=dtln,dc=cloud filter: "(objectClass=groupOfNames)" userMatchers: - userAttr: DN groupAttr: member nameAttr: cn staticClients: - id: dex-k8s-authenticator name: Kubernetes Dev Cluster secret: 'acDEgDEcIg7RX0U7A9hlW2pGGraHDuMAZ4qFEKg2fUHHxr8' redirectURIs: - https://login.ash.dtln.cloud/callback enablePasswordDB: True staticPasswords: # Создаем статического пользователя с паролем в base64 - email: "admin@dtln.cloud" # bcrypt hash of the string "password" hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" username: "admin" userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
- Теперь ставим dex и dex-auth-чарты из текущего каталога с нашими конфигами:
helm install dex --namespace kube-system --values dex.yaml charts/dex helm install dex-auth --namespace kube-system --values dex-auth.yml charts/dex-k8s-authenticator
Генерируем kubeconfig
- Ждем, когда поднимутся pod’ы. Смотрим их логи и идем по адресу login.ash.dtln.cloud. Логинимся под созданной нами учеткой, для авторизации мы использовали mail-формат логина.
Для static-записи выбираем вход через mail:
- После успешной аутентификации нас перенаправляют на страницу с инструкцией Dex-auth. C ее помощью мы генерируем kubeconfig-файл. В дальнейшем с ним мы будем подключаться к нашему кластеру:
- Теперь попытаемся получить доступ к кластеру и получаем ошибку. Все верно, наш пользователь не имеет прав, так что переходим к настройке RBAC.
Настраиваем RBAC-авторизацию
- Для примера привяжем статического пользователя к системной роли cluster-admin, а пользователей группы developers – к роли view, позволяющей только просматривать ресурсы. Тогда содержимое файла crb.yml должно быть таким:
--- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: dex-admin namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: User name: "admin@dtln.cloud" --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: dex-developers namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: view subjects: - kind: Group name: "developers"
- Переключаемся на основной контекст и применяем созданный yaml-файл на кластер:
kubectl config set-context default kubectl apply -f crb.yml
- Смотрим доступные контексты и переключаемся обратно на нашего пользователя:
kubectl config get-contexts kubectl config set-context johndoe-ash.dtln.cloud
На этом настройка Dex в связке с OpenLDAP закончена.
Пара советов напоследок:
- Если возникают проблемы, первым делом нужно проверить форматирование yaml-файлов и обратить внимание на отступы.
- Слэши в адресах должны соответствовать примерам.
- Не забудьте посмотреть логи pod’ов Dex, Dex-auth, а также журналы юнитов kube-api на мастерах.