Аутентификация в Kubernetes с помощью Dex: прикручиваем LDAP

от автора

Сегодня я подробно разберу настройку аутентификации в Kubernetes с помощью Dex в связке с LDAP, а также покажу, как можно добавлять статических пользователей в Dex. 

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

Что будем делать:

  1. Установим OpenLDAP и настроим на нем поддержку STARTTLS. 
  2. Опишем структуру LDAP-каталога нашей организации.
  3. Включим поддержку OIDC (OpenID Connect) на kube-api-серверах.
  4. Получим SAN-сертификат для доменов, которые будет использовать Dex.
  5. Установим Dex и Dex-auth, где мы опишем LDAP-каталог и статических пользователей
  6. Сгенерируем kubeconfig нашего пользователя для работы с кластером.
  7. Настроим RBAC-авторизацию для групп и пользователей в кластере.

Итак, поехали.

Показывать буду на примере уже готового кластера Kubernetes с Helm версии 3 и Ingress, а также тремя доменными именами.

Устанавливаем и настраиваем OpenLDAP-сервер

В качестве LDAP будем использовать OpenLDAP на дистрибутиве ubuntu 18.04. 
Имя нашего сервера: openldap.dtln.cloud. 

  1. Подключаемся к серверу и приступаем к установке OpenLDAP. В процессе установки нам предложат установить пароль:
    sudo apt update  sudo apt install slapd ldap-utils 

  2. Переконфигурируем OpenLDAP для нашего домена:
    sudo dpkg-reconfigure slapd  

  3. Выбираем No:
  4. Вводим доменное имя:
  5. Вводим имя организации:
  6. Повторяем ввод пароля:
  7. Включаем поддержку STARTTLS. Ставим необходимые пакеты:
    sudo apt install gnutls-bin ssl-cert 

  8. Генерируем CA-ключ:
    sudo sh -c "certtool --generate-privkey > /etc/ssl/private/cakey.pem" 

  9. Описываем нашу организацию в /etc/ssl/ca.info:
    cn = DTLN Company ca cert_signing_key 

  10. Генерируем 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 

  11. Создаем шаблон для сертификата /etc/ssl/openldap.info:
    organization = DTLN Company cn = openldap.dtln.cloud tls_www_server encryption_key signing_key expiration_days = 3650 

  12. Генерируем сам сертификат:
    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 

  13. Настраиваем 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 

  14. Применяем созданный нами файл следующей командой:
    sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f certinfo.dif 

  15. Назначаем права доступа на сертификат и перезапускаем наш сервис:
    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 

  16. Чтобы проверить работу нашего сервиса с сертификатами, добавляем в /etc/ldap/ldap.conf строчку:
    TLS_CACERT /etc/ssl/certs/cacert.pem 

  17. Проверяем работу через STARTTLS:
    ldapwhoami -H ldap://openldap.dtln.cloud -x -ZZ 

    В случае успеха получаем:

    В случае проблемы проверяем еще раз пути до сертификатов и выполнение команд:

Описываем структуру LDAP-каталога

  1. Теперь опишем структуру каталога, создадим группы и дву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 

  2. Разворачиваем описанную структуру командой:
    ldapadd -x -D cn=admin,dc=openldap,dc=dtln,dc=cloud -W -f content.ldif 

  3. Удостоверимся в наличии наших пользователей в каталоге:
    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-юнит. В остальных случаях настройку лучше сделать с помощью этих утилит.

  1. Редактируем юнит /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/ \ 
  2. Рестартуем наши API, проверяем, что они поднялись:
    sudo systemctl daemon-reload sudo systemctl restart kube-apiserver sudo systemctl status kube-apiserver 

Создаем мультидоменный сертификат

Теперь переходим в кластер Kubernetes. 

  1. Ставим 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 

  2. Описываем запрос на получение 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 

  3. Выполняем команду:
    kubectl apply -f cert.yaml 

  4. Теперь смотрим состояние нашего запроса на получение сертификата следующими командами: 
    kubectl get certificates --all-namespaces kubectl get challenges --all-namespaces 

  5. Ждем подтверждения, процесс может занять некоторое время:

Устанавливаем Dex

Для Dex нам понадобятся ca.crt, ca.key c мастер-сервера. Обычно они лежат в каталоге /etc/kubernetes/pki/
Также нужен сгенерированный нами раннее CA-сертификат с OpenLDAP, расположенный по пути /etc/ssl/certs/cacert.pem

  1. Скачиваем исходники dex-authenticator и переходим в каталог:
    git clone git@github.com:mintel/dex-k8s-authenticator.git cd dex-k8s-authenticator/ 

  2. Готовим конфиг для 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  

  3. Переводим содержимое cacert.pem в base64, чтобы добавить его в конфиг:
    cacert.pem | base64 

  4. Готовим конфиг для 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"  

  5. Теперь ставим 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

  1. Ждем, когда поднимутся pod’ы. Смотрим их логи и идем по адресу login.ash.dtln.cloud. Логинимся под созданной нами учеткой, для авторизации мы использовали mail-формат логина. 

    Для static-записи выбираем вход через mail:

  2. После успешной аутентификации нас перенаправляют на страницу с инструкцией Dex-auth. C ее помощью мы генерируем kubeconfig-файл. В дальнейшем с ним мы будем подключаться к нашему кластеру:
  3. Теперь попытаемся получить доступ к кластеру и получаем ошибку. Все верно, наш пользователь не имеет прав, так что переходим к настройке RBAC.

Настраиваем RBAC-авторизацию

  1. Для примера привяжем статического пользователя к системной роли 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" 

  2. Переключаемся на основной контекст и применяем созданный yaml-файл на кластер:
    kubectl config set-context default kubectl apply -f crb.yml 

  3. Смотрим доступные контексты и переключаемся обратно на нашего пользователя:
    kubectl config get-contexts kubectl config set-context johndoe-ash.dtln.cloud 

На этом настройка Dex в связке с OpenLDAP закончена.

Пара советов напоследок:

  • Если возникают проблемы, первым делом нужно проверить форматирование yaml-файлов и обратить внимание на отступы. 
  • Слэши в адресах должны соответствовать примерам. 
  • Не забудьте посмотреть логи pod’ов Dex, Dex-auth, а также журналы юнитов kube-api на мастерах.

ссылка на оригинал статьи https://habr.com/ru/company/dataline/blog/497482/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *