ХабрПостыНовостиМегапосты?

Крупнейшее изменение системы аутентификации в K8s за последние годы: новый KEP от «Фланта», Google и Microsoft

KEP 3331 (Structured Authentication Config) — это самое крупное обновление в системе аутентификации Kubernetes за 6 последних лет, в котором учитываются все просьбы пользователей. Предварительно его альфа-версия должна выйти в составе релиза Kubernetes 1.28 — сам KEP уже смержили, но планы могут немного подкорректироваться (Upd. на днях стало известно, что фича все же появится в K8s 1.29).

В проработке фичи вместе с инженерами из Google и Microsoft активно участвовал наш Platform Lead Максим Набоких, который входит в состав Kubernetes sig-auth и является основным мейнтейнером Dex, свободного провайдера OpenID Connect.

Чтобы понять, в чем его преимущества, посмотрим, какими методами решается вопрос аутентификации пользователей сейчас:

Итак, какие же преимущества дает Structured Authentication Config:

  1. Можно использовать не только OIDC-токены, но и любой ID JWT.

  2. Появляется возможность динамически изменять конфигурацию. В качестве флага передается путь до файла, в котором прописан Structured Authentication Config, а Kubernetes API-сервер автоматически обновляет настройки в случае изменений этого файла.

  3. Можно одновременно подключать несколько провайдеров аутентификации (например, Okta, Keycloak, Gitlab) без использования инструментов вроде Dex.

  4. Можно использовать CEL (Common Expression Language) для определения соответствия claim’ов токена атрибутам пользователя в Kubernetes (имя пользователя, группы).

Как все это будет выглядеть 

Пример Structured Authentication Config:

apiVersion: apiserver.config.k8s.io/v1alpha1
kind: AuthenticationConfiguration
jwt:
- issuer:
    url: https://example.com
    clientIDs:
    - my-app
  claimMappings: {...}
  claimValidationRules: [...]
  userInfoValidationRules: [...]

Файл конфигурации содержит несколько провайдеров, которые в виде массивов передаются в JWT-поле. А с помощью claimMappings можно реализовать правила извлечения информации о пользователях: 

claimMappings:
  username:
    expression: 'claims.username + ":external-user"'
  groups:
    expression: 'claims.roles.split(",")'
  uid:
    claim: 'sub'
  extra:
  - key: '"client_name"'
    value: 'claims.aud'

В этом примере с помощью CEL мы прописали два правила:

  1. Роли пользователя, которые передаются в виде одной строки, автоматически дробятся на элементы массива по разделителю — запятой (claims.roles.split(",")).

  2. К имени каждого внешнего пользователя добавляется постфикс :external-user. Если используется не RBAC, а своя система авторизации и распределения ролей, можно передавать такие атрибуты в авторизационные вебхуки. Очень удобно. 

Теперь коснемся правил валидации для аутентификации. В документации Kubernetes существует следующее примечание: 

Префикс system: зарезервирован для внутреннего использования в Kubernetes, вы должны убедиться, что у вас случайно не используются пользователи или группы, имена которых начинаются с system:

Допустим, у нас есть LDAP (его веб-интерфейс — на скриншоте) и группа system:masters, которую мы указали для нового пользователя при регистрации. 

Если теперь мы залогинимся через Dex, то в списке групп у этого пользователя и правда появится system:masters, а сам пользователь станет суперадмином кластера и сможет делать все что угодно. Вряд ли кто-то осознанно планировал устраивать нечто подобное, но сценарий вполне реалистичный.

{"level":"info","msg":"login successful: connector \"ldap-local\", username=\"kaksenov\", preferred_username=\"\", email=\"konstantin.aksenov@flant.com\", groups=[\"system:masters\" \"developers:maintainers\"]","time":"2023-06-01T19:12:09Z"}

ATTRIBUTE   VALUE
Username    konstantin.aksenov@flant.com
Groups      [system:masters developers:maintainers system:authenticated]

До появления Structured Authentication Config можно было использовать следующие методы валидации при аутентификации:

connectors:
  - type: gitlab
    id: gitlab
    name: GitLab
    config:
      # If `groups` is provided, this acts as a whitelist - only the user's GitLab groups that are in the configured `groups` below will go into the groups claim.  Conversely, if the user is not in any of the configured `groups`, the user will not be authenticated.
      
      groups:
      - my-group

Посмотрим, как это будет работать в Structured Authentication Config. 

В SAC есть claimValidationRules. Мы можем проверить входящие claim’ы, указать в правилах, что существуют обязательные поля и поля, значение которых должно соответствовать определенным ограничениям. Таким образом, на этапе получения claim’ов из токенов мы сумеем распознать и отсеять невалидные токены.

claimValidationRules:
- claim: hd
  requiredValue: example.com
- expression: 'claims.hd == "example.com"'
  message: the hd claim must be set to example.com
- expression: 'claims.exp - claims.nbf <= 86400'
  message: total token lifetime must not exceed 24 hours

Что касается проблемы с system-группами, то в Structured Authentication Config существуют userInfoValidationRules — с их помощью мы можем указать, что ни одно имя пользователя или название группы не может начинаться с system.

userInfoValidationRules:
- rule: "!userInfo.username.startsWith('system:')"
  message: username cannot used reserved system: prefix
- rule: "userInfo.groups.all(group, !group.startsWith('system:'))"
  message: groups cannot used reserved system: prefix

Итак, подведем итог — что же есть в Structured Authentication Config:

Это уже второй KEP, значительную часть которого прорабатывал «Флант» — первый появился в Kubernetes 1.27.

@TimurTukaev
13.07.2023 11:18 UTC
Первоисточник

Комментарии

@citius
13.07.2023 06:37 UTC
+6

Огнище, приседания с oidc были мягко говоря не совсем удобны + облачные кубы далеко не все поддерживают это дело.

@iLexey
01.09.2023 09:20 UTC
0

Ещё б в ингрессе у всех появилось oidc бесплатно и жизнь бы наладилась ))