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

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

16 апреля 2020  • 

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

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

15 апреля
Сергей Жильцов

Главные вопросы при планировании инфраструктуры виртуальных рабочих столов.

08 апреля
Николай Продайвода

Как организовать гарантированный канал доставки трафика, даже если нет возможности подвести оптику и закупить дорогостоящее оборудование.

25 марта
Вячеслав Нечаев

Комментарии

Подпишитесь на нашу рассылку

Получайте свежие и полезные материалы и приглашения на наши мероприятия

randomness