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.
Чтобы понять, в чем его преимущества, посмотрим, какими методами решается вопрос аутентификации пользователей сейчас:
-
Static Token File. Его проблема в том, что это статический файл и токены хранятся в нем в открытом виде. Такая механика не пройдет CIS Benchmark.
-
X509 Client Certs. Это хороший и безопасный способ. Однако сейчас сертификаты нельзя отзывать. И если мы выпустили сертификат, придется либо ждать, когда его срок действия истечет, либо запускать сложный механизм замены сертификатов во всем Kubernetes-кластере. Для больших окружений, где много пользователей и K8s-кластеров, такой вариант не подходит.
-
OpenID Connect Tokens, Authenticating Proxy, Webhook Token Authentication — это уже очень неплохие варианты, и у каждого есть свои плюсы. Однако с появлением Structured Authentication Config ни один из этих вариантов может не понадобиться.
Итак, какие же преимущества дает Structured Authentication Config:
-
Можно использовать не только OIDC-токены, но и любой ID JWT.
-
Появляется возможность динамически изменять конфигурацию. В качестве флага передается путь до файла, в котором прописан Structured Authentication Config, а Kubernetes API-сервер автоматически обновляет настройки в случае изменений этого файла.
-
Можно одновременно подключать несколько провайдеров аутентификации (например, Okta, Keycloak, Gitlab) без использования инструментов вроде Dex.
-
Можно использовать 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 мы прописали два правила:
-
Роли пользователя, которые передаются в виде одной строки, автоматически дробятся на элементы массива по разделителю — запятой (
claims.roles.split(",")). -
К имени каждого внешнего пользователя добавляется постфикс
: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 можно было использовать следующие методы валидации при аутентификации:
-
Задать префикс через параметр
--oidc-groups-prefix. -
Использовать фильтры — например, в Dex у коннекторов есть фильтр для групп.
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:
-
У kube-apiserver появится новый флаг, в котором можно задать ссылку на файл конфигурации аутентификации.
-
Динамическое применение файла конфигурации после его редактирования.
-
Одновременное использование нескольких провайдеров OIDC.
-
Использование CEL.
-
Правила для валидации токенов.
-
Правила извлечения информации из токена и применения ее к атрибутам пользователя.
-
Конфигурация становится структурированной и можно использовать нормальное версионирование, а не запутываться в куче флагов.
Это уже второй KEP, значительную часть которого прорабатывал «Флант» — первый появился в Kubernetes 1.27.
ссылка на оригинал статьи https://habr.com/ru/articles/747712/
Добавить комментарий