Как добавить пользователя в Kubernetes?

Рассмотрим варианты аутентификации в k8s и попробуйем разобраться в их плюсах и минусах

Все кластеры Kubernetes имеют две категории пользователей: управляемые Kubernetes service accounts и обычные пользователи. Другими словами, нет возможности добавить пользователя в Kubernetes через kubectl или вызов API. Как решить эту проблему разбираемся ниже.

В отличие от пользователей, service account может быть добавлен в k8s как отдельный ресурс и данные для его доступа хранятся в Secrets

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

  • Tokens учетной записи службы для service accounts;
  • как минимум один другой метод для аутентификации пользователей.

Когда включены несколько модулей аутентификации, первый модуль, успешно аутентифицирующий запрос, прерывает дальнейшее выполнение. API-сервер не гарантирует порядок выполнения аутентификаторов.

x.509

Несмотря на то, что обычного пользователя нельзя добавить через вызов API, любой пользователь, представляющий действительный сертификат, подписанный удостоверяющим центром (CA) кластера, считается аутентифицированным. В этой конфигурации Kubernetes определяет имя пользователя из поля Common name в "subject" сертификата (например, "/CN=bob"). Затем подсистема контроля доступа на основе ролей (RBAC) определит, имеет ли пользователь права на выполнение определенной операции с ресурсом.

Для начала надо создать приватный ключ и certificate signing request(CSR):

1openssl genrsa -out devopstrain.pem
2openssl req -new -key devopstrain.pem -out devopstrain.csr -subj "/CN=devopstrain"

Можно также задать группы пользователя:

1openssl req -new -key devopstrain.pem -out devopstrain.csr -subj "/CN=devopstrain/O=devgroup"

В данном примере имя пользователя будет devopstrain. На него и будут завязаны RBAC.

Выведем содержимое CRS в base64 формате:

1cat devopstrain.csr | base64 | tr -d '\n'

Создадим yaml с CertificateSigningRequest. Обратите внимание на поле request, его нужно заполнить содержимым полученным в прошлой команде.

 1cat <<'EOF'> devopstrain-csr.yaml
 2apiVersion: certificates.k8s.io/v1
 3kind: CertificateSigningRequest
 4metadata:
 5  name: user-request-devopstrain
 6spec:
 7  groups:
 8  - system:authenticated
 9  request: LS0tLS1CRUdJTi...
10  signerName: kubernetes.io/kube-apiserver-client
11  expirationSeconds: 315569260
12  usages:
13  - digital signature
14  - key encipherment
15  - client auth
16EOF

Поле expirationSeconds задает срок дейстия сертификата. В данном случае 10 лет.

Создадим ресурс и проверим его статус:

1kubectl create -f devopstrain-csr.yaml
2kubectl certificate approve user-request-devopstrain

Сертификат должен быть подписан. Теперь скачаем его

1kubectl get csr user-request-devopstrain -o jsonpath='{.status.certificate}' | base64 -d > devopstrain-user.crt

В уже активном(текущем рабочем kubeconfig) нужно достать certificate authority:

1kubectl config view --raw -o go-template='{{index ((index (index .clusters 0) "cluster")) "certificate-authority-data"|base64decode}}' > ca.crt

И создадим kubeconfig для нового пользователя:

1kubectl --kubeconfig ~/.kube/config-devopstrain config set-cluster preprod --server=https://KUBERNETES-API-ADDRESS
2kubectl --kubeconfig ~/.kube/config-devopstrain config set-cluster preprod --certificate-authority=ca.crt
3kubectl --kubeconfig ~/.kube/config-devopstrain config set-credentials devopstrain --client-certificate=devopstrain-user.crt --client-key=devopstrain.pem --embed-certs=true
4kubectl --kubeconfig ~/.kube/config-devopstrain config set-context default --cluster=preprod --user=devopstrain
5kubectl --kubeconfig ~/.kube/config-devopstrain config use-context default

Замените KUBERNETES-API-ADDRESS на хост или IP-адрес API сервера k8s

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

 1cat <<'EOF'> devopstrain-rbac.yaml
 2apiVersion: v1
 3kind: Namespace
 4metadata:
 5  name: devopstrain-ns
 6spec: {}
 7status: {}
 8---
 9kind: Role
10apiVersion: rbac.authorization.k8s.io/v1
11metadata:
12  name: devopstrain
13  namespace: devopstrain-ns
14rules:
15- apiGroups: ["", "extensions", "apps"]
16  resources: ["*"]
17  verbs: ["*"]
18- apiGroups: ["batch"]
19  resources:
20  - jobs
21  - cronjobs
22  verbs: ["*"]
23---
24kind: RoleBinding
25apiVersion: rbac.authorization.k8s.io/v1
26metadata:
27  name: devopstrain
28  namespace: devopstrain-ns
29subjects:
30- kind: User
31  name: devopstrain
32  apiGroup: rbac.authorization.k8s.io
33roleRef:
34  apiGroup: rbac.authorization.k8s.io
35  kind: Role
36  name: devopstrain
37EOF
38
39kubectl apply -f devopstrain-rbac.yaml

Протестируем доступ через созданный kubeconfig:

1kubectl --kubeconfig ~/.kube/config-devopstrain get pods -n devopstrain-ns

Минусы данного подхода:

  • требуется внешнее управление сертификатами(нет встроенной базы пользователей)
  • невозможно отозвать сертификат для пользователя(то есть ограничить доступ можно только на уровне IP или RBAC)

Static token

API-сервер читает токены из файла, когда указан параметр --token-auth-file=SOMEFILE в командной строке. В настоящее время токены действительны бессрочно, и список токенов не может быть изменен без перезапуска API-сервера.

Файл токенов - это файл csv с минимум 3 столбцами: токен, имя пользователя, uid пользователя, за которыми следуют необязательные имена групп.

Примечание:

Если у вас есть более одной группы, столбец должен быть в двойных кавычках, например:

1token,user,uid,"group1,group2,group3"

Добавление токена-носителя в запрос

При использовании аутентификации по токену-носителю из http-клиента, API-сервер ожидает заголовок Authorization со значением Bearer .

1Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

Bootstrap token

Для обеспечения упрощенной инициализации новых кластеров Kubernetes включает динамически управляемый тип токена, называемый Bootstrap Token. Эти токены хранятся в виде Secrets в пространстве имен kube-system, где их можно динамически управлять и создавать. Contoller Manager содержит контроллер TokenCleaner, который удаляет токены Bootstrap по мере их истечения.

Service account token

Это включенный по умолчанию метод аутентификации, который использует подписанные токены для валидации запросов. Создадим нужные ресурсы:

 1apiVersion: v1
 2kind: ServiceAccount
 3metadata:
 4  name: devopstrain
 5  namespace: default
 6secrets:
 7- name: devopstrain-token
 8---
 9apiVersion: v1
10kind: Secret
11metadata:
12  name: devopstrain-token
13  annotations:
14    kubernetes.io/service-account.name: devopstrain
15type: kubernetes.io/service-account-token

После этого вы можете схожим образом как в случае с x.509 сертфикатми создать kubeconfig файл. Разница будет в том, что нужно прокинуть токен:

1kubectl config set-credentials USER --token=TOKEN-FROM-SECRET

Минус данного подхода в том, что данные доступа лежат в secrets, тот кто может читать их может получить уровень доступа такой же как у данного сервисного аккаунта. Плюс в том, что можно отозвать доступ.

OpenID Connect token

OIDC означает "OpenID Connect" и является протоколом аутентификации, который построен на основе протокола OAuth 2.0. OIDC предоставляет стандартизированный способ для аутентификации пользователей и передачи утверждений о пользователе между веб-приложениями и поставщиками идентификации.

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

Для настройки поддержки OIDC в Kubernetes API сервере вам нужно передать следующие параметры:

--oidc-issuer-url - URL-адрес OpenID провайдера, который вы хотите использовать для аутентификации.

--oidc-client-id - идентификатор клиента, который был зарегистрирован на стороне провайдера OpenID, идентифицирующий ваш кластер Kubernetes.

--oidc-username-claim - название поля, которое содержит имя пользователя в токене OpenID. Это может быть различным в зависимости от провайдера OpenID.

--oidc-groups-claim - название поля, которое содержит список групп пользователя в токене OpenID. Это также может быть различным в зависимости от провайдера OpenID.

--oidc-ca-file - путь к файлу сертификата корневого удостоверяющего центра

Кроме этого есть еще и другие параметры. Обратитесь к документации.

Webhooks

В этом сценарии каждому пользователю выдается токен сторонним поставщиком идентификации (часто сокращенно до IdP). Подобно другим потокам аутентификации, пользователь включает это при отправке запроса API в кластер. Однако вместо того, чтобы пытаться распарсить этот токен самостоятельно, кластер вместо этого запускает webhook при получении запроса и передает токен стороннему поставщику для проверки подлинности. Это по сути похоже на поток статического token, за исключением того, что вместо сравнения токена с файлом в API-сервере кластер обращается к поставщику идентификации для получения ответа «да» или «нет».

Authenticating proxies

Последний метод аутентификации сторонних пользователей, который мы рассмотрим в этой статье, это использование Аутентифицирующего Прокси (часто сокращенно до AP). Этот подход отличается от всех остальных в этой статье тем, что он не требует использования токенов доступа. Вы можете потребовать от пользователей аутентификацию для каждого запроса к вашему кластеру отдельно и избежать проблем с отзывом токенов в целом.

Этот метод работает таким образом, что запросы не направляются напрямую на API-сервер вашего кластера, а отправляются на сторонний сервис: Аутентифицирующий Прокси. Он функционирует как Провайдер Идентификации для этого метода аутентификации , что означает, что это место, где ваши пользователи должны доказать свою личность. Это может быть любым способом, который вам нравится - имя пользователя и пароль, аппаратный токен, такой как Yubikey, или SSH-ключи, настроенные в профиле терминала.

После того, как пользователь прошел аутентификацию с помощью Аутентифицирующего Прокси, прокси перенаправляет запрос к кластеру вместе со всей необходимой информацией о пользователе. Коммуникация между AP и вашим кластером осуществляется через HTTP, защищенный клиентскими сертификатами. AP должен представить действительный клиентский сертификат, подписанный удостоверяющим центром, признанным кластером, прежде чем любая другая информация в его HTTP-запросах к кластеру будет прочитана.

Этот метод аутентификации очень гибкий, позволяя использовать любой метод аутентификации пользователей, который вам нравится, и полностью отделяет слой аутентификации от вашего кластера. Если вам нужно отозвать доступ для определенного пользователя, вы можете сделать это на уровне AP, не изменяя настройки вашего кластера и рискуя простоем.