Стадия жизненного цикла модуля: General Availability

Пример конфигурации модуля

В примере представлена конфигурация модуля user-authn в Deckhouse Platform.

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: user-authn
spec:
  version: 2
  enabled: true
  settings:
    kubeconfigGenerator:
    - id: direct
      masterURI: https://159.89.5.247:6443
      description: "Direct access to kubernetes API"

Примеры настройки провайдера

Проверка подключения провайдера

На странице провайдера в веб-интерфейсе DP доступно действие «Проверить подключение». Оно создаёт ресурс DexProviderCheck и ждёт, пока контроллер user-authn запишет результат проверки в его status.

Проверка выполняется, чтобы убедиться в следующем:

  • указанный DexProvider существует и включён;
  • эндпоинт Dex discovery внутри кластера доступен;
  • эндпоинт внешнего провайдера доступен.

Для OIDC-провайдеров дополнительно читаются discovery-документ и JWKS. Для LDAP-провайдеров проверяется доступность TCP/TLS/StartTLS и, если включён Kerberos, наличие секрета с keytab. Проверка не выполняет полный сценарий входа и не валидирует пароль тестового пользователя.

GitHub

В примере представлены настройки провайдера для интеграции с GitHub.

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: github
spec:
  type: Github
  displayName: My Company GitHub
  # Опционально: временно отключить провайдер, не удаляя CR
  # enabled: false
  github:
    clientID: plainstring
    clientSecret: plainstring

В организации GitHub необходимо создать новое приложение.

Для этого выполните следующие шаги:

  • перейдите в Settings -> Developer settings -> OAuth Aps -> Register a new OAuth application и в качестве Authorization callback URL укажите адрес https://dex.<modules.publicDomainTemplate>/callback.

Полученные Client ID и Client Secret укажите в Custom Resource DexProvider.

Если организация GitHub находится под управлением клиента, перейдите в Settings -> Applications -> Authorized OAuth Apps -> <name of created OAuth App> и нажмите Send Request для подтверждения. Попросите клиента подтвердить запрос, который придет к нему на email.

GitLab

В примере представлены настройки провайдера для интеграции с GitLab.

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: gitlab
spec:
  type: Gitlab
  displayName: Dedicated GitLab
  gitlab:
    baseURL: https://gitlab.example.com
    clientID: plainstring
    clientSecret: plainstring
    groups:
    - administrators
    - users

В GitLab проекта необходимо создать новое приложение.

Для этого выполните следующие шаги:

  • self-hosted: перейдите в Admin area -> Application -> New application и в качестве Redirect URI (Callback URL) укажите адрес https://dex.<modules.publicDomainTemplate>/callback, выберите scopes: read_user, openid;
  • cloud GitLab.com: под главной учетной записью проекта перейдите в User Settings -> Application -> New application и в качестве Redirect URI (Callback URL) укажите адрес https://dex.<modules.publicDomainTemplate>/callback, выберите scopes: read_user, openid;
  • (для GitLab версии 16 и выше) включить опцию Trusted/Trusted applications are automatically authorized on GitLab OAuth flow при создании приложения.

Полученные Application ID и Secret укажите в Custom Resource DexProvider.

Atlassian Crowd

В примере представлены настройки провайдера для интеграции с Atlassian Crowd.

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: crowd
spec:
  type: Crowd
  displayName: Crowd
  crowd:
    baseURL: https://crowd.example.com/crowd
    clientID: plainstring
    clientSecret: plainstring
    enableBasicAuth: true
    groups:
    - administrators
    - users

В соответствующем проекте Atlassian Crowd необходимо создать новое Generic-приложение.

Для этого выполните следующие шаги:

  • перейдите в Applications -> Add application.

Полученные Application Name и Password укажите в Custom Resource DexProvider.

Группы CROWD укажите в lowercase-формате для Custom Resource DexProvider.

Bitbucket Cloud

В примере представлены настройки провайдера для интеграции с Bitbucket.

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: bitbucket
spec:
  type: BitbucketCloud
  displayName: Bitbucket
  bitbucketCloud:
    clientID: plainstring
    clientSecret: plainstring
    includeTeamGroups: true
    teams:
    - administrators
    - users

Для настройки аутентификации необходимо в Bitbucket в меню команды создать нового OAuth consumer.

Для этого выполните следующие шаги:

  • перейдите в Settings -> OAuth consumers -> New application и в качестве Callback URL укажите адрес https://dex.<modules.publicDomainTemplate>/callback, разрешите доступ для Account: Read и Workspace membership: Read.

Полученные Key и Secret укажите в Custom Resource DexProvider.

OIDC (OpenID Connect)

Аутентификация через OIDC-провайдера требует регистрации клиента (или создания приложения). Сделайте это по документации вашего провайдера (например, Okta, Keycloak, Gluu или Blitz).

Полученные в ходе выполнения инструкции clientID и clientSecret укажите в Custom Resource DexProvider.

Ниже можно ознакомиться с некоторыми примерами.

Keycloak

После выбора realm для настройки, добавления пользователя в Users и создания клиента в разделе Clients с включенной аутентификацией, которая необходима для генерации clientSecret, выполните следующие шаги:

  • Создайте в разделе Client scopes scope с именем groups, и назначьте ему предопределённое сопоставление groups («Client scopes» → «Client scope details» → «Mappers» → «Add predefined mappers»).
  • В созданном ранее клиенте добавьте данный scope во вкладке Client scopes («Clients → «Client details» → «Client Scopes» → «Add client scope»).
  • В полях «Valid redirect URIs», «Valid post logout redirect URIs» и «Web origins» конфигурации клиента укажите https://dex.<publicDomainTemplate>/*, где publicDomainTemplate – это указанный шаблон DNS-имен кластера в модуле global.

В примере представлены настройки провайдера для интеграции с Keycloak:

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: keycloak
spec:
  type: OIDC
  displayName: My Company Keycloak
  oidc:
    issuer: https://keycloak.my-company.com/realms/myrealm # Используйте имя вашего realm
    clientID: plainstring
    clientSecret: plainstring
    insecureSkipEmailVerified: true
    getUserInfo: true
    scopes:
      - openid
      - profile
      - email
      - groups

Если в Keycloak не используется подтверждение учетных записей по email, для корректной работы с ним в качестве провайдера аутентификации внесите изменения в настройку Client scopes одним из следующих способов:

  • Удалите сопоставление Email verified («Client Scopes» → «Email» → «Mappers»). Это необходимо для корректной обработки значения true в поле insecureSkipEmailVerified и правильной выдачи прав пользователям с неподтвержденным email.

  • Если отредактировать или удалить сопоставление Email verified невозможно, создайте отдельный Client Scope с именем email_dkp (или любым другим) и добавьте в него два сопоставления:

    • email: «Client Scopes» → email_dkp → «Add mapper» → «From predefined mappers» → email;
    • email verified: «Client Scopes» → email_dkp → «Add mapper» → «By configuration» → «Hardcoded claim». Укажите следующие поля:
      • «Name»: email verified;
      • «Token Claim Name»: emailVerified;
      • «Claim value»: true;
      • «Claim JSON Type»: boolean.

    После этого в клиенте, зарегистрированном для кластера DP, в разделе «Clients» для Client scopes замените значение email на email_dkp.

    В ресурсе DexProvider укажите параметр insecureSkipEmailVerified: true и в поле .spec.oidc.scopes замените название Client Scope на email_dkp, следуя примеру:

        scopes:
          - openid
          - profile
          - email_dkp
          - groups
    

Okta

В примере представлены настройки провайдера для интеграции с Okta:

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: okta
spec:
  type: OIDC
  displayName: My Company Okta
  oidc:
    issuer: https://my-company.okta.com
    clientID: plainstring
    clientSecret: plainstring
    insecureSkipEmailVerified: true
    getUserInfo: true

Blitz Identity Provider

На стороне провайдера Blitz Identity Provider при регистрации приложения необходимо указать URL для перенаправления пользователя после авторизации. При использовании DexProvider необходимо указать https://dex.<publicDomainTemplate>/, где publicDomainTemplate – указанный в модуле global шаблон DNS-имен кластера.

В примере представлены настройки провайдера для интеграции с Blitz Identity Provider:

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: blitz
spec:
  displayName: Blitz Identity Provider
  oidc:
    basicAuthUnsupported: false
    claimMapping:
      email: email
      groups: your_claim # Claim для получения групп пользователя, группы пользователя настраиваются на стороне провайдера Blitz Identity Provider
    clientID: clientID
    clientSecret: clientSecret
    getUserInfo: true
    insecureSkipEmailVerified: true # Установить true, если нет необходимости в проверке email пользователя
    insecureSkipVerify: false
    issuer: https://yourdomain.idblitz.ru/blitz
    promptType: consent 
    scopes:
    - profile
    - openid
    userIDKey: sub
    userNameKey: email
  type: OIDC

Чтобы корректно отрабатывал выход из приложений (происходил отзыв токена и требовалась повторная авторизация), нужно установить login в значении параметра promptType.

Для обеспечения гранулированного доступа пользователя к приложениям необходимо:

  • добавить параметр allowedUserGroups в ModuleConfig нужного приложения;
  • добавить группы к пользователю (наименования групп должны совпадать как на стороне Blitz, так и на стороне Deckhouse).

Пример для Prometheus:

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: prometheus
spec:
  version: 2
  settings:
    auth:
      allowedUserGroups:
        - adm-grafana-access
        - grafana-access

LDAP

В примере представлены настройки провайдера для интеграции с Active Directory:

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: active-directory
spec:
  type: LDAP
  displayName: Active Directory
  ldap:
    host: ad.example.com:636
    insecureSkipVerify: true

    bindDN: cn=Administrator,cn=users,dc=example,dc=com
    bindPW: admin0!

    usernamePrompt: Email Address

    enableBasicAuth: true

    userSearch:
      baseDN: cn=Users,dc=example,dc=com
      filter: "(objectClass=person)"
      username: userPrincipalName
      idAttr: DN
      emailAttr: userPrincipalName
      nameAttr: cn

    groupSearch:
      baseDN: cn=Users,dc=example,dc=com
      filter: "(objectClass=group)"
      userMatchers:
      - userAttr: DN
        groupAttr: member
      nameAttr: cn

Настройка базовой аутентификации

Чтобы включить доступ к Kubernetes API с использованием базовой аутентификации (Basic Authentication) по учетным записям LDAP:

  1. Убедитесь, что в конфигурации модуля control-plane-manager включен параметр apiserver.publishAPI.
  2. Установите параметр enableBasicAuth: true в ресурсе DexProvider для LDAP.

В кластере может быть только один провайдер аутентификации с включенным параметром enableBasicAuth.

После настройки пользователи смогут обращаться к Kubernetes API с помощью kubectl, используя свой логин и пароль в LDAP.

Пример kubeconfig для пользователя:

apiVersion: v1
kind: Config
clusters:
- name: my-cluster
  cluster:
    server: https://api.example.com
    # Путь к CA сертификату или insecure-skip-tls-verify: true
    certificate-authority: /path/to/ca.crt
users:
- name: ldap-user
  user:
    username: janedoe@example.com
    password: userpassword
contexts:
- name: default
  context:
    cluster: my-cluster
    user: ldap-user
current-context: default

Kerberos (SPNEGO) SSO для LDAP

Dex поддерживает аутентификацию без отображения формы ввода логина/пароля, которая реализуется с помощью механизма Kerberos (SPNEGO) для LDAP‑коннектора. При использовании этого механизма браузер, доверяющий хосту Dex, отправляет Authorization: Negotiate …, Dex валидирует Kerberos‑билет по keytab, пропускает форму вводу логина/пароля, сопоставляет principal с LDAP‑именем, получает группы и завершает OIDC‑поток.

Минимальный пример (расширение спецификации LDAP‑провайдера):

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: active-directory
spec:
  type: LDAP
  displayName: Active Directory
  ldap:
    host: ad.example.com:636
    bindDN: cn=Administrator,cn=users,dc=example,dc=com
    bindPW: admin0!
    userSearch:
      baseDN: cn=Users,dc=example,dc=com
      username: sAMAccountName
      idAttr: uid
      emailAttr: mail
      nameAttr: cn
    groupSearch:
      baseDN: cn=Users,dc=example,dc=com
      nameAttr: cn
      userMatchers:
      - userAttr: uid
        groupAttr: memberUid
    kerberos:
      enabled: true
      keytabSecretName: dex-kerberos-keytab   # Секрет в неймспейсе `d8-user-authn` с ключом 'krb5.keytab'.
      expectedRealm: EXAMPLE.COM              # Опционально, проверка realm (без учёта регистра).
      usernameFromPrincipal: sAMAccountName   # localpart|sAMAccountName|userPrincipalName
      fallbackToPassword: false               # По умолчанию false; если true — при отсутствии/ошибке заголовка `Authorization: Negotiate` будет показана форма ввода логина/пароля.

Примечания:

  • Секрет dex-kerberos-keytab должен находиться в неймспейсе d8-user-authn и содержать ключ krb5.keytab.
  • Один под Dex может обслуживать несколько LDAP+Kerberos провайдеров. У каждого — свой keytab. krb5.conf не требуется (Dex проверяет билеты офлайн по keytab). Для настройки аутентификации заведите в LDAP read-only-пользователя (service account). Полученные путь до пользователя и пароль укажите в параметрах bindDN и bindPW кастомного ресурса DexProvider. В параметре bindPW укажите пароль в открытом виде (plain text). Стратегии с передачей хешированных паролей не предусмотрены. Если в LDAP настроен анонимный доступ на чтение, настройки можно не указывать.

SAML

В примере представлены настройки провайдера для интеграции с SAML 2.0 Identity Provider (например, AD FS, Okta, Keycloak).

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: saml-provider
spec:
  type: SAML
  displayName: Корпоративный SAML
  saml:
    ssoURL: https://saml-idp.example.com/saml/sso
    rootCAData: |
      -----BEGIN CERTIFICATE-----
      MIIFaDC...
      -----END CERTIFICATE-----
    entityIssuer: https://dex.example.com/callback
    ssoIssuer: https://saml-idp.example.com
    usernameAttr: name
    emailAttr: email
    groupsAttr: groups
    nameIDPolicyFormat: persistent

Для настройки SAML Identity Provider:

  1. Зарегистрируйте Dex как Service Provider (SP) у вашего провайдера идентификации со следующими параметрами:
    • ACS URL (Assertion Consumer Service): https://dex.<modules.publicDomainTemplate>/callback
    • Entity ID: https://dex.<modules.publicDomainTemplate>/callback
    • Формат идентификатора имени: persistent или emailAddress
  2. Настройте сопоставление атрибутов в провайдере идентификации для отправки атрибутов email, name (имя пользователя) и groups в SAML assertion.

  3. Экспортируйте сертификат подписи провайдера идентификации и укажите его в поле rootCAData ресурса DexProvider.

SAML не поддерживает refresh tokens нативно. Dex кеширует identity пользователя из первичного SAML assertion и возвращает её при последующих запросах refresh. Время жизни сессии контролируется настройками expiry.refreshTokens в конфигурации модуля user-authn.

Настройка OAuth2-клиента в Dex для подключения приложения

Этот вариант настройки подходит приложениям, которые имеют возможность использовать OAuth2-аутентификацию самостоятельно, без помощи oauth2-proxy. Чтобы позволить подобным приложениям взаимодействовать с Dex, используется Custom Resource DexClient.

apiVersion: deckhouse.io/v1
kind: DexClient
metadata:
  name: myname
  namespace: mynamespace
spec:
  redirectURIs:
  - https://app.example.com/callback
  - https://app.example.com/callback-reserve
  allowedGroups:
  - Everyone
  - admins
  trustedPeers:
  - opendistro-sibling

Списки разрешённых групп и адресов электронной почты в DexClient проверяются при входе и при каждом обновлении refresh-токена. Изменение списков запрещает дальнейшее обновление сессий, которые больше им не соответствуют; таким пользователям нужно войти заново.

После создания такого ресурса в Dex будет зарегистрирован клиент с идентификатором (clientID) dex-client-myname@mynamespace.

Пароль доступа к клиенту (clientSecret) сохранится в секрете:

apiVersion: v1
kind: Secret
metadata:
  name: dex-client-myname
  namespace: mynamespace
type: Opaque
data:
  clientSecret: c2VjcmV0

Предоставление приложению доступа к Kubernetes API

Ресурс DexClient или DexAuthenticator можно настроить для получения токенов, которые принимает API-сервер Kubernetes. Для этого установите на ресурсе одну из следующих аннотаций со значением "true":

  • dexclient.deckhouse.io/allow-access-to-kubernetes — для DexClient;
  • dexauthenticator.deckhouse.io/allow-access-to-kubernetes — для DexAuthenticator.

Пример настройки ресурса DexClient:

apiVersion: deckhouse.io/v1
kind: DexClient
metadata:
  name: myname
  namespace: mynamespace
  annotations:
    dexclient.deckhouse.io/allow-access-to-kubernetes: "true"
spec:
  redirectURIs:
  - https://app.example.com/callback

Аннотация регистрирует клиента в качестве доверенного (trusted peer) для привилегированного OAuth2-клиента kubernetes, что позволяет ему запрашивать ID-токены, предназначенные для API-сервера. В таком токене имя пользователя определяется значением claim email, а группы — значением claim groups. В результате приложение обращается к API-серверу от имени прошедшего аутентификацию пользователя и с предоставленными ему правами.

Предоставляемый таким образом доступ действует на уровне всего кластера, хотя DexClient и DexAuthenticator являются namespaced-ресурсами. По этой причине добавить аннотацию или изменить её значение на "true" может только субъект с правами на изменение конфигурации модуля user-authn — например, пользователь с ролью d8:system-capability:user-authn:edit. Прав на создание ресурсов DexClient или DexAuthenticator в отдельном неймспейсе недостаточно.

Добавление аннотации ограничено независимо от указанного значения, включая "false". Это необходимо для совместимости с версиями DP до 1.78, в которых доступ предоставляется при наличии аннотации независимо от её значения. Если доступ к API-серверу Kubernetes не требуется, не добавляйте аннотацию.

Ограничение не распространяется на ресурсы, у которых аннотация уже установлена. Пользователь с правами на изменение такого ресурса может продолжать изменять его, в том числе удалить аннотацию или изменить значение так, чтобы доступ был отключён.

Локальная аутентификация

Локальная аутентификация обеспечивает проверку и управление доступом пользователей с возможностью настройки парольной политики, поддержкой двухфакторной аутентификации (2FA) и управлением группами.
Реализация соответствует требованиям безопасности ФСТЭК и рекомендациям OWASP, обеспечивая надёжную защиту доступа к кластеру и приложениям без необходимости интеграции с внешними системами аутентификации.

Создание пользователя

Рекомендуемый способ создания локального пользователя — команда d8 iam user create. Она поддерживает интерактивный ввод пароля, автоматическую генерацию пароля, добавление в группы и TTL для временных пользователей.

Примеры:

Интерактивный ввод пароля (по умолчанию если stdin — терминал):

d8 iam user create anton --email anton@abc.com

Автогенерация пароля (сгенерированный пароль показывается в выводе команды один раз):

d8 iam user create anton --email anton@abc.com --generate-password

Пароль из stdin (для CI/CD пайплайнов):

echo "s3cret" | d8 iam user create anton --email anton@abc.com --password-stdin

Готовый bcrypt-хеш (например от htpasswd):

d8 iam user create anton --email anton@abc.com --password-hash '$2y$10$abcdef...'

Создать пользователя и добавить в группы (с автосозданием групп):

d8 iam user create anton --email anton@abc.com --generate-password --member-of admins --create-groups

Создать временного пользователя с TTL:

d8 iam user create anton --email anton@abc.com --generate-password --ttl 24h

Предпросмотр манифеста без применения:

d8 iam user create anton --email anton@abc.com --generate-password --dry-run -o yaml

В качестве альтернативы можно создать ресурс User вручную. Придумайте пароль и укажите его хеш-сумму, закодированную в base64, в поле password. Email-адрес должен быть в нижнем регистре.

Для вычисления хеш-суммы пароля воспользуйтесь командой:

echo -n '3xAmpl3Pa$$wo#d' | htpasswd -BinC 10 "" | cut -d: -f2 | tr -d '\n' | base64 -w0; echo

Если команда htpasswd недоступна, установите соответствующий пакет:

  • apache2-utils — для дистрибутивов, основанных на Debian;
  • httpd-tools — для дистрибутивов, основанных на CentOS;
  • apache2-htpasswd — для ALT Linux.

Также можно воспользоваться онлайн-сервисом.

Обратите внимание, что в приведенном примере указан ttl.

apiVersion: deckhouse.io/v1
kind: User
metadata:
  name: admin
spec:
  email: admin@yourcompany.com
  # echo -n '3xAmpl3Pa$$wo#d' | htpasswd -BinC 10 "" | cut -d: -f2 | tr -d '\n' | base64 -w0; echo
  password: 'JDJ5JDEwJGRNWGVGUVBkdUdYYVMyWDFPcGdZdk9HSy81LkdsNm5sdU9mUkhnNWlQdDhuSlh6SzhpeS5H'
  ttl: 24h

Правила авторизации предоставляют права пользователю на основе email из выданного токена. По этой причине нельзя создать ресурс User, у которого значение spec.email совпадает с субъектом типа User в существующем ресурсе AuthorizationRule или ClusterAuthorizationRule. Это предотвращает незаметное предоставление прав новому пользователю.

Если совпадение необходимо, например, если правило авторизации было создано заранее, укажите другой email или установите для пользователя аннотацию user-authz.deckhouse.io/allow-authorization-rule-collision: "true". Аннотация только подтверждает совпадение имени. Назначить грант по-прежнему можно, только если запрашивающий покрывает роли или они входят в его диапазон can-assign.

При сопоставлении email приводится к нижнему регистру, поскольку в таком виде он записывается в токен. Например, Admin@Example.com совпадает с субъектом admin@example.com.

Ограничение не распространяется на уже существующих пользователей, чей email совпадает с субъектами правил авторизации. Такие пользователи продолжают работать, а при обнаружении совпадения выводится предупреждение.

Учитывайте это ограничение при декларативном управлении пользователями и правилами авторизации. Если пользователь и соответствующее правило создаются одновременно, правило может быть создано раньше пользователя, в результате чего создание пользователя будет отклонено. Чтобы разрешить такое совпадение, добавьте аннотацию user-authz.deckhouse.io/allow-authorization-rule-collision: "true" в манифест User.

При удалении пользователя соответствующий субъект из правила авторизации не удаляется автоматически. Пока он остаётся в правиле, права продолжают предоставляться для указанного email, а система выводит предупреждение об отсутствии соответствующего пользователя. Если впоследствии будет создан пользователь с тем же email, он получит эти права. Если такое поведение не требуется, удалите соответствующий субъект из правила авторизации.

Удаление пользователя

Для удаления локального пользователя используйте команду d8 iam user delete. По умолчанию команда также удаляет пользователя из всех ресурсов Group, в которых он состоит.

Примеры:

Удалить пользователя (и автоматически удалить из всех групп):

d8 iam user delete anton

Удалить пользователя, оставив ссылки в группах:

d8 iam user delete anton --keep-memberships

Операции над локальным пользователем

Операции сброса пароля, сброса 2FA и блокировки выполняются через ресурс UserOperation. В поле initiatorType указывается, кто инициировал операцию: администратор (admin), система (system) или сам пользователь (self).

Важно. Не меняйте User.spec.password после создания User (kubectl edit / прямой patch). Это поле нельзя изменить, и оно не обновляет учётные данные в Dex. Сбрасывайте пароль только через UserOperation (или d8 iam user reset-password).

Административные операции

Для административных действий над локальными пользователями используйте команды d8 iam user. Они создают ресурс UserOperation с initiatorType: admin, дожидаются выполнения операции и выводят результат.

Удалить, пересоздать или выполнить UserOperation (ResetPassword, Reset2FA, Lock, Unlock) над локальным пользователем, чей email или членство в группе уже несёт грант, можно только если вы можете назначить эти роли (покрывающие права или явный диапазон can-assign). initiatorType: self эту проверку не обходит.

Подключить DexProvider — то же назначение. Провайдер утверждает email и набор групп, а имя пользователя в Kubernetes — это и есть email, поэтому провайдер дотягивается до всех грантов, имеющихся у идентичностей, которые он способен утвердить. Что он способен утвердить, ограничивается по двум осям блоком spec.allowedIdentities: emails и emailDomains ограничивают email, groups — claim групп. Фильтры групп, специфичные для типа провайдера, тоже учитываются (oidc.allowedGroups, gitlab.groups, crowd.groups, bitbucketCloud.teams без includeTeamGroups, github.orgs[].teams у каждой организации, saml.allowedGroups вместе с filterGroups: true). Ось без ограничителя открыта и дотягивается до всех грантов субъектов этого вида.

SuperAdmin в каждом кластере выдан пользователю (User), поэтому провайдер без ограничителя по email способен утвердить этот email, и создать его или подключить заново может только SuperAdmin. При ограничителях по обеим осям учитываются только роли, уже выданные перечисленным идентичностям: ClusterAdmin или менеджер подсистемы security подключает провайдер для @contractor.example и группы contractors без SuperAdmin, если ни у одной из этих идентичностей ещё нет роли, которую он не может назначить. Имена групп сравниваются точно; вхождение объекта Group в другие объекты Group список не расширяет: токен внешнего провайдера несёт только те группы, которые провайдер утвердил.

apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
  name: contractors
spec:
  type: OIDC
  displayName: Contractors
  oidc:
    issuer: https://idp.contractor.example
    clientID: dex
    clientSecret: secret
  allowedIdentities:
    emailDomains: [contractor.example]
    groups: [contractors]

Dex применяет те же ограничители при входе: пользователю, чей email не входит в emails и emailDomains, отказывается во входе, claim групп сужается до пересечения со списком groups, пустое пересечение — отказ. Оба ограничителя действуют для любого типа провайдера поверх фильтров, специфичных для типа провайдера.

Ротация clientSecret или bindPW, смена displayName, выключение провайдера, сужение ограничителей и повторное применение того же манифеста проходят без проверки. Любое другое изменение проверяется как новое подключение провайдера в его новом виде: адрес провайдера идентичности, маппинг claim или атрибутов, параметры проверки подписи и email, расширение ограничителей, а также включение выключенного провайдера (выключение — способ изолировать подозрительный провайдер, и его отмена не бесплатна). Удаление провайдера не проверяется.

Отказ называет роли, до которых провайдер мог бы дотянуться, и диапазон запрашивающего, например: dexproviders.deckhouse.io "corp": the provider can assert identities that already carry roles [user-authz:super-admin]; the requester's can-assign range is basic<=ClusterAdmin and does not cover them. Narrow spec.allowedIdentities (emails, emailDomains, groups) or ask a SuperAdmin.

При выполнении операций ResetPassword, Reset2FA и Lock удаляются объекты Dex OfflineSessions и RefreshToken, принадлежащие пользователю. Это завершает активные offline-сессии пользователя и требует повторной аутентификации.

Пример интерактивного сброса пароля:

d8 iam user reset-password admin

Пример сброса пароля с чтением нового пароля из stdin:

echo "N3wPa$$wo#d" | d8 iam user reset-password admin --password-stdin

Пример сброса пароля с автоматической генерацией нового пароля:

d8 iam user reset-password admin --generate-password

Если пароль уже захеширован, передайте bcrypt-хеш без кодирования в Base64:

d8 iam user reset-password admin --password-hash '$2y$10$abcdef...'

Пример сброса 2FA:

d8 iam user reset2fa admin

Пример блокировки пользователя на 30 минут:

d8 iam user lock admin 30m

Разблокировка пользователя:

d8 iam user unlock admin

По умолчанию команды ожидают завершения операции. Чтобы только создать UserOperation и вывести его имя, используйте флаг --wait=false.

Сброс пароля пользователем

Локальный пользователь может самостоятельно сбросить свой пароль в интерфейсе аутентификации DP. При этом создаётся ресурс UserOperation с типом ResetPassword и initiatorType: self.

Самостоятельный сброс пароля доступен только для локальных учётных записей (встроенный коннектор Local). Пользователи, которые входят через внешние провайдеры аутентификации, должны обращаться к администратору соответствующей системы.

При сбросе пароля новый пароль должен соответствовать парольной политике, а активные сессии пользователя завершаются — требуется повторная аутентификация.

Ручное создание UserOperation

Когда CLI d8 iam user недоступен (например, в CI/CD, GitOps или скриптах автоматизации), ресурс UserOperation можно создать напрямую. Используйте apiVersion: deckhouse.io/v1 и укажите initiatorType: admin.

Пример — сброс пароля локального пользователя (в newPasswordHash указывается bcrypt-хеш без кодирования в Base64; хук кодирует его автоматически):

apiVersion: deckhouse.io/v1
kind: UserOperation
metadata:
  name: reset-password-admin
spec:
  user: admin
  type: ResetPassword
  initiatorType: admin
  resetPassword:
    newPasswordHash: "$2y$10$..."

Пример — блокировка локального пользователя на 1 час:

apiVersion: deckhouse.io/v1
kind: UserOperation
metadata:
  name: lock-admin-1h
spec:
  user: admin
  type: Lock
  initiatorType: admin
  lock:
    for: "1h"

Пример — бессрочная блокировка:

apiVersion: deckhouse.io/v1
kind: UserOperation
metadata:
  name: lock-admin-permanent
spec:
  user: admin
  type: Lock
  initiatorType: admin
  lock:
    for: "permanent"

Пример — разблокировка:

apiVersion: deckhouse.io/v1
kind: UserOperation
metadata:
  name: unlock-admin
spec:
  user: admin
  type: Unlock
  initiatorType: admin

Пример — сброс 2FA:

apiVersion: deckhouse.io/v1
kind: UserOperation
metadata:
  name: reset-2fa-admin
spec:
  user: admin
  type: Reset2FA
  initiatorType: admin

Операции над внешними пользователями (LDAP/Crowd)

Для пользователей, аутентифицируемых через внешние провайдеры (LDAP, Atlassian Crowd), вместо spec.user используется поле spec.target. Для внешних пользователей поддерживаются только операции Lock и Unlock.

Пример — блокировка внешнего пользователя по connectorID + email на 30 минут:

apiVersion: deckhouse.io/v1
kind: UserOperation
metadata:
  name: lock-external-user
spec:
  target:
    connectorID: my-ldap
    email: jane.doe@example.org
  type: Lock
  initiatorType: admin
  lock:
    for: "30m"

Жизненный цикл и побочные эффекты UserOperation

Использование объекта UserOperation имеет следующие особенности:

  • UserOperation — одноразовый объект: после создания хук обрабатывает его и записывает результат в status.phase (Succeeded или Failed).
  • Завершённые операции автоматически удаляются через 24 часа.
  • UserOperation — неизменяем: после создания спецификация не изменяется.
  • Для нового действия нужно создать новый UserOperation.

Операции ResetPassword, Reset2FA и Lock завершают все активные сессии пользователя (удаляют объекты Dex OfflineSessions и RefreshToken). Пользователь будет вынужден пройти повторную аутентификацию.

Проверка статуса операции

Для проверки статуса операции выполните следующие действия:

  1. Получите список всех операций:

    d8 k get useroperations
    
  2. Получите полный статус операции:

    d8 k get useroperation <имя> -o yaml
    
  3. Получите только статус завершения:

    d8 k get useroperation <имя> -o jsonpath='{.status.phase}'
    

Автоматические операции системы

Система автоматически создаёт UserOperation с initiatorType: system в следующем случае:

  • Автоблокировка пользователя при превышении количества неудачных попыток входа, заданного в passwordPolicy.lockout.maxAttempts. Блокировка длится lockout.lockDuration, после чего пользователь разблокируется автоматически. Администратор может также разблокировать пользователя вручную командой d8 iam user unlock или создав UserOperation с типом Unlock.

Добавление пользователя в группу

Пользователи могут быть объединены в группы для управления правами доступа. Рекомендуемый способ управления группами — команда d8 iam group.

Примеры:

Создать группу:

d8 iam group create admins

Добавить пользователя в группу:

d8 iam group add-member admins user anton

Добавить вложенную группу:

d8 iam group add-member admins group devops

Удалить пользователя из группы:

d8 iam group remove-member admins user anton

Удалить группу:

d8 iam group delete admins

В качестве альтернативы можно создать ресурс Group вручную. Пример манифеста ресурса Group для группы:

apiVersion: deckhouse.io/v1alpha1
kind: Group
metadata:
  name: admins
spec:
  name: admins
  members:
    - kind: User
      name: admin

Здесь members — список членов: kind: User с name = User.metadata.name, либо вложенная kind: Group с name = Group.spec.name (имя в токене, не metadata.name).

Имя группы записывается в выданный токен без изменений. При этом оно неотличимо от имени группы, полученного от внешнего провайдера аутентификации. Поэтому нельзя создать ресурс Group, если значение spec.name совпадает с субъектом типа Group в существующем ресурсе AuthorizationRule или ClusterAuthorizationRule. Это предотвращает незаметное предоставление прав участникам новой группы.

Если совпадение необходимо, переименуйте группу или установите на ней аннотацию user-authz.deckhouse.io/allow-authorization-rule-collision: "true".

В отличие от email, имя группы при сопоставлении не приводится к нижнему регистру. По этой причине имена, различающиеся только регистром букв, считаются разными.

Ограничение не распространяется на уже существующие группы, имена которых совпадают с субъектами правил авторизации. Такие группы продолжают работать, а при обнаружении совпадения выводится предупреждение.

Учитывайте это ограничение при декларативном управлении группами и правилами авторизации. Если группа и соответствующее правило создаются одновременно, правило может быть создано раньше группы, в результате чего создание группы будет отклонено. Чтобы разрешить такое совпадение, добавьте аннотацию user-authz.deckhouse.io/allow-authorization-rule-collision: "true" в манифест Group.

При удалении группы соответствующий субъект из правила авторизации не удаляется автоматически. Пока он остаётся в правиле, права продолжают предоставляться группе с указанным именем. Группа, впоследствии созданная с тем же именем, получит эти права. Если такое поведение не требуется, удалите соответствующий субъект из правила авторизации.

Просмотр пользователей и групп

Для просмотра пользователей, групп и их эффективных прав (группы, гранты, уровень доступа) используйте команды d8 iam get и d8 iam list.

Примеры:

Список всех пользователей с effective access

d8 iam list users

Детали для конкретного пользователя (группы, гранты, уровень доступа):

d8 iam get user anton

Список всех групп:

d8 iam list groups

Детали для конкретной группы (участники, гранты):

d8 iam get group admins

Парольная политика

Настройки парольной политики позволяют контролировать сложность пароля, ротацию и блокировку пользователей:

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: user-authn
spec:
  version: 2
  enabled: true
  settings:
    passwordPolicy:
      complexityLevel: Fair
      passwordHistoryLimit: 10
      lockout:
        lockDuration: 15m
        maxAttempts: 3
      rotation:
        interval: "30d"

Описание полей:

  • complexityLevel — уровень сложности пароля: None, Low, Fair, Good, Excellent или Custom;
  • custom — пользовательские правила сложности (используются только при complexityLevel: Custom):
    • custom.minLength — минимальное количество символов в пароле;
    • custom.specialCharacters — если true, требуется хотя бы один специальный символ;
    • custom.numbers — если true, требуется хотя бы одна цифра;
    • custom.capitalized — если true, требуется хотя бы одна заглавная буква;
    • custom.repeatedChars — если true, запрещается более 2 одинаковых символов подряд;
  • passwordHistoryLimit — число предыдущих паролей, которые хранит система, чтобы предотвратить их повторное использование;
  • lockout — настройки блокировки при превышении лимита неудачных попыток входа:
    • lockout.maxAttempts — лимит неудачных попыток;
    • lockout.lockDuration — длительность блокировки пользователя;
  • rotation — настройки ротации паролей:
    • rotation.interval — период обязательной смены пароля.

Пример с пользовательскими правилами сложности:

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: user-authn
spec:
  version: 2
  enabled: true
  settings:
    passwordPolicy:
      complexityLevel: Custom
      custom:
        minLength: 10
        specialCharacters: true
        numbers: false
        capitalized: true
        repeatedChars: false
      passwordHistoryLimit: 10

Двухфакторная аутентификация (2FA)

2FA позволяет повысить уровень безопасности, требуя ввести код из приложения-аутентификатора TOTP (например, Google Authenticator) при входе.

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: user-authn
spec:
  version: 2
  enabled: true
  settings:
    staticUsers2FA:
      enabled: true
      issuerName: "awesome-app"

Описание полей:

  • enabled — включает или отключает 2FA для всех статических пользователей;
  • issuerName — имя, которое будет отображаться в приложении-аутентификаторе при добавлении аккаунта.

После включения 2FA каждый пользователь должен пройти процесс регистрации в приложении-аутентификаторе при первом входе.

Выдача прав пользователю или группе

Для настройки прав доступа используются параметры кастомного ресурса ClusterAuthorizationRule.