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

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

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

 • 

Сегодня я подробно разберу настройку аутентификации в 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’ы. Смотрим их логи и идем по адресу https://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 на мастерах.
Расскажите друзьям и коллегам о статье

Последние статьи

Как мы создали мощный инструмент для мониторинга процессов в системе резервного копирования на основе Grafana.

Андрей Александров

Фотоэкскурсия по первой очереди дата-центра в Медведково.

Алексей Приезжев

Рассказываем, как проверять ресурсы ВМ на ошибки и даем ключевые метрики, на которые можно опираться.

DataLine