[Облачные вычисления, DevOps, Kubernetes] Как предоставить доступ к кластеру Kubernetes с помощью клиентского сертификата: простое руководство (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
04-Фев-2021 00:32


ИсточникПредположим, мы создали кластер Kubernetes. И кто-то из команды разработчиков хочет развернуть и протестировать на нем новое приложение. Как нам предоставить ему доступ в кластер? Команда Kubernetes aaS Mail.ru Cloud Solutions перевела простое руководство по предоставлению доступа к новому кластеру Kubernetes, включая настройку аутентификации и привязку ролей. Автор показывает процесс, используя клиентский сертификат x509.Управление пользователями в KubernetesДля управления кластером Kubernetes и запущенными в нем приложениями обычно используют утилиту kubectl или веб-интерфейс. Под капотом эти инструменты вызывают API Server: HTTP Rest API, открывающий конечные точки управления кластером. Этот HTTP API хорошо документирован — посмотрите сами. После отправки запроса на сервер API он проходит сначала аутентификацию, а затем авторизацию. Аутентификация позволяет убедиться, что запрашивающий известен системе, авторизация — что отправителю запроса разрешено выполнить конкретное действие.Аутентификацию выполняют с помощью плагинов, есть плагины с разными механизмами:
  • сертификаты клиентов — о них в этой статье;
  • Bearer tokens (персональные токены);
  • аутентифицирующий прокси;
  • базовая аутентификация HTTP.
В зависимости от механизма аутентификации плагин ищет информацию о пользователе в определенных местах. Например, для аутентификации по сертификату клиента идентификацию пользователя (идентификатор, имя, адрес электронной почты и так далее) указывают в поле Common Name (CN) сертификата. Информацию о группе, если она есть, добавляют в поле Organisation (O).Внутри кластера Kubernetes нет ни ресурсов пользователей, ни ресурсов групп. Их обрабатывают вне кластера и предоставляют с каждым запросом, который направляют на сервер API — я проиллюстрирую это ниже.Некоторые соображения и допущения
  • Кластер используют несколько команд или клиентов (подход с несколькими пользователями), так что нужно изолировать рабочую нагрузку для каждого клиента. Мы создадим пространство имен для команды разработчиков, в которую входит разработчик, которому надо дать доступ (пусть его зовут Дейв). Это пространство имен мы назовем development.
  • Дейву предстоит развернуть стандартные ресурсы Kubernetes. Затем он получит право создавать, просматривать, обновлять, получать список и удалять ресурсы Deployment и Service. Дополнительные права можно предоставить при необходимости, но они ограничены пространством имен development.
  • Скорее всего, членам команды Дейва потребуется такой же уровень доступа. Мы заведем группу dev и предоставим права на уровне группы.
  • Дейву потребуется kubectl, а также openssl — он сгенерирует закрытый ключ и запрос на вход с сертификатом.
Создание закрытого ключа и запроса на подпись сертификата (CSR)Сначала Дейв генерирует закрытый ключ RSA и CSR. Закрытый ключ можно создать с помощью команды:
$ openssl genrsa -out dave.key 4096
С CSR немного сложнее, поскольку Дейву нужно убедиться, что он:
  • использует свое имя в поле Common Name (CN) — оно требуется для идентификации на сервере API;
  • использует имя группы в поле Organisation (O) — это имя нужно для идентификации группы на сервере API.
Ниже файл конфигурации, который Дейв использует для создания CSR:
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[ dn ]
CN = dave
O = dev
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
Примечание: запись clientAuth в поле extendedKeyUsage нужна, поскольку сертификат будут использовать для идентификации клиента.С помощью указанного файла конфигурации, сохраненного в csr.cnf, CSR можно создать одной командой:
$ openssl req -config ./csr.cnf -new -key dave.key -nodes -out dave.csr
Создав файл .csr, Дейв отправляет его администраторам, чтобы они подписали его с помощью центра сертификации кластера.Подписание CSRПосле подписания файла .csr выпускается сертификат. Он будет использоваться для аутентификации запросов, который Дейв отправит на сервер API. Начнем с создания ресурса Kubernetes Certificate Signing Request.Примечание мы могли создать управляемый кластер (например, в DigitalOcean, Google GKE, Microsoft Azure, Mail.ru Cloud Solutions или другой платформе) или собственный (допустим, kubeadm или kubespray). Процесс подписи везде устроен одинаково.Мы используем следующую спецификацию и сохраняем ее в csr.yaml:
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: mycsr
spec:
groups:
- system:authenticated
request: ${BASE64_CSR}
usages:
- digital signature
- key encipherment
- server auth
- client auth
Значение ключа request — содержимое переменной окружения BASE64_CSR. Первый шаг — получить кодированный в base64 файл .csr, созданный Дейвом. Затем использовать envsubst, чтобы заменить значения этой переменной перед созданием ресурса.
# Кодируем файл .csr в base64
$ export BASE64_CSR=$(cat ./dave.csr | base64 | tr -d '\n')
# Подставляем переменную env BASE64_CSR и создаем ресурс CertificateSigninRequest
$ cat csr.yaml | envsubst | kubectl apply -f -
Проверяем статус созданного CSR — мы видим, что он находится в состоянии ожидания:
# Проверяем статус созданного CSR
$ kubectl get csr
NAME        AGE   REQUESTOR            CONDITION
mycsr       9s    28b93...d73801ee46   Pending
Подтверждаем CSR с помощью команды:
$ kubectl certificate approve mycsr
Еще раз проверяем статус CSR — теперь он одобрен:
$ kubectl get csr
NAME        AGE   REQUESTOR            CONDITION
mycsr       9s    28b93...d73801ee46   Approved,Issued
Сертификат создан, теперь извлечем его из ресурса CSR, сохраним в файле с именем dave.crt и проверим, что внутри:
$ kubectl get csr mycsr -o jsonpath='{.status.certificate}' \
| base64 --decode > dave.crt
Следующая команда openssl показывает: сертификат подписан центром сертификации кластера DigitalOcean (часть Issuer). Subject содержит dave в полях CN (CommonName) и O (Organisation), как указал Дейв при создании файла .csr:
$ openssl x509 -in ./dave.crt -noout -text
Certificate:
Data:
    Version: 3 (0x2)
    Serial Number:
        48:29:cf:ae:d6:...:09:33:ef:14:58
Signature Algorithm: sha256WithRSAEncryption
    Issuer: O=DigitalOcean, CN=k8saas Cluster CA
    Validity
        Not Before: Jun  3 07:56:00 2019 GMT
        Not After : Jun  2 07:56:00 2020 GMT
    Subject: O=dev, CN=dave
    Subject Public Key Info:
        Public Key Algorithm: rsaEncryption
            Public-Key: (4096 bit)
            Modulus:
...
Примечание в примере используем управляемый кластер Kubernetes, созданный в DigitalOcean — мы видим это в Issuer кластера. На другой платформе будет похоже.Создание пространства именНачинаем с создания пространства имен development — благодаря этому ресурсы, которые развернут Дейв и его команда, будут изолированы от остальной рабочей нагрузки кластера. Его можно создать с помощью простой команды:
$ kubectl create ns development
или с помощью файла dev-ns.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: development
Применяем dev-ns.yaml с помощью команды:
$ kubectl apply -f dev-ns.yaml
Примечание рекомендую создать ресурс ResourceQuota и связать его с пространством имен. Это позволит ограничить объем CPU и ОЗУ, которые можно использовать в пространстве имен.Настройка правил RBACС помощью сертификата Дейв может пройти аутентификацию на сервере API. Но пока у него нет прав, так что он не может делать многие вещи. Давайте дадим ему права создавать, получать список, обновлять, просматривать и удалять ресурсы Deployment и Service в пространстве имен dev.
Ресурсы, задействованные в управлении доступом к базе ролей Kubernetes (RBAC)Коротко: роль (то же самое справедливо и для ClusterRole) содержит список правил. Каждое правило определяет действия, которые могут быть выполнены (например: list, get, watch) со списком ресурсов (например: Pod, Service, Secret) в apiGroups (например: core, apps/v1). Роль определяет права для конкретного пространства имен, область ClusterRole — весь кластер.Создание ролиСоздадим ресурс Role со следующей спецификацией:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: development
name: dev
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["create", "get", "update", "list", "delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["create", "get", "update", "list", "delete"]
Ресурсы подов и служб принадлежат основной группе API (значение ключа apiGroups — пустая строка), а ресурсы развертывания — группе API приложений. Для этих двух групп apiGroup мы определили список ресурсов и действия, которые нужно авторизовать на этих ресурсах.Строки сохраняем в файл role.yaml, для создания роли используем команду:
$ kubectl apply -f role.yaml
Создание RoleBindingНазначение RoleBinding — связать роль, то есть список разрешенных действий, с пользователем или группой. Чтобы у Дейва были права, указанные в созданной выше роли, мы привязываем его к этой роли. Для этого используем ресурс RoleBinding:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dev
namespace: development
subjects:
- kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: dev
apiGroup: rbac.authorization.k8s.io
Эта RoleBinding связывает:
  • субъект — пользователь Дейв;
  • роль: с именем dev, которая позволяет создавать, просматривать, обновлять, получать список, удалять ресурсы Deployment и Service.
Примечание: поскольку Дейв входит в группу разработчиков, то можно использовать следующую привязку RoleBinding для связи роли с группой, а не отдельным пользователем. Помните: информация о группе указывается в поле Organisation (O) сертификата, его отправляют с каждым запросом.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dev
namespace: development
subjects:
- kind: Group
name: dev
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: dev
apiGroup: rbac.authorization.k8s.io
Мы сохранили спецификацию ресурса RoleBinding в файле role-binding.yaml и создаем его с помощью команды:
$ kubectl apply -f role-binding.yaml
Создание файла конфигурации KubeConfigВсе настроено. Теперь отправляем Дейву информацию, которая необходима для настройки его локального клиента kubectl для связи с нашим кластером. Сначала создаем файл kubeconfig.tpl со следующим содержанием, его мы будем использовать в качестве шаблона:
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: ${CLUSTER_CA}
server: ${CLUSTER_ENDPOINT}
name: ${CLUSTER_NAME}
users:
- name: ${USER}
user:
client-certificate-data: ${CLIENT_CERTIFICATE_DATA}
contexts:
- context:
cluster: ${CLUSTER_NAME}
user: dave
name: ${USER}-${CLUSTER_NAME}
current-context: ${USER}-${CLUSTER_NAME}
Чтобы создать kubeconfig из этого шаблона, нужно сначала установить переменные среды:
# Имя пользователя
$ export USER="dave"
# Имя кластера (полученное из текущего контекста)
$ export CLUSTER_NAME=$(kubectl config view --minify -o jsonpath={.current-context})
# Сертификат клиента
$ export CLIENT_CERTIFICATE_DATA=$(kubectl get csr mycsr -o jsonpath='{.status.certificate}')
# Данные центра сертификации кластера
$ export CLUSTER_CA=$(kubectl config view --raw -o json | jq -r '.clusters[] | select(.name == "'$(kubectl config current-context)'") | .cluster."certificate-authority-data"')
# Точка входа API
$ export CLUSTER_ENDPOINT=$(kubectl config view --raw -o json | jq -r '.clusters[] | select(.name == "'$(kubectl config current-context)'") | .cluster."server"')
Подставляем их, используя удобную утилиту envsubst:
$ cat kubeconfig.tpl | envsubst > kubeconfig
Отправляем Дейву файл kubeconfig. Чтобы взаимодействовать с кластером, ему достаточно добавить в файл свой закрытый ключ.Использование контекстаЧтобы использовать kubeconfig, Дейв устанавливает переменную среды KUBECONFIG, указав путь к файлу.
$ export KUBECONFIG=$PWD/kubeconfig
Примечание: есть разные способы использовать конфигурации Kubernetes. Можно установить переменную среду KUBECONFIG, добавить новую запись в файл $ HOME/.kube/config по умолчанию или использовать флаг --kubeconfig для каждой команды kubectl.Чтобы добавить закрытый ключ dave.key, Дейв использует команду:
$ kubectl config set-credentials dave \
--client-key=$PWD/dave.key \
--embed-certs=true
Команда создает ключ client-key-data в записи пользователя файла kubeconfig и устанавливает dave.key в кодировку base64 в качестве значения.Если все успешно, Дейв может проверить версию сервера (и клиента) с помощью команды:
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.2", GitCommit:"66049e3b21efe110454d67df4fa62b08ea79a19b", GitTreeState:"clean", BuildDate:"2019-05-16T16:23:09Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.2", GitCommit:"66049e3b21efe110454d67df4fa62b08ea79a19b", GitTreeState:"clean", BuildDate:"2019-05-16T16:14:56Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"linux/amd64"}
Теперь проверим, позволяет ли связанная с Дейвом текущая роль отображать узлы кластера:
$ kubectl get nodes
Error from server (Forbidden): nodes is forbidden: User "dave" cannot list resource "nodes" in API group "" at the cluster scope
Конечно, нет! Но Дейв может что-то развертывать в кластере — по крайней мере, в пространстве имен development. Давайте проверим это с помощью YAML-файла, который определяет Deployment на основе образа nginx и Service для его предоставления:
# www.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: www
namespace: development
spec:
replicas: 3
selector:
matchLabels:
    app: www
template:
metadata:
    labels:
    app: www
spec:
    containers:
    - name: nginx
    image: nginx:1.14-alpine
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: www
namespace: development
spec:
selector:
app: vote
type: ClusterIP
ports:
- port: 80
targetPort: 80
Из результата следующей команды видно, что Дейв может создавать эти ресурсы в кластере:
$ kubectl apply -f www.yaml
deployment.apps/www created
service/www created
Дейв ограничен пространством имен development. Если он попытается получить список всех подов в пространстве имен по умолчанию, то получит сообщение об ошибке:
$ kubectl get pods
Error from server (Forbidden): pods is forbidden: User "dave" cannot list resource "pods" in API group "" in the namespace "default"
Еще он не может создавать другие ресурсы, кроме тех, к которым ему предоставили доступ. Например, мы можем попробовать следующую спецификацию ресурса типа Secret:
# credentials.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
namespace: development
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
Давайте посмотрим, как Дейв попытается его создать:
$ kubectl apply -f credentials.yaml
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "/v1, Resource=secrets", GroupVersionKind: "/v1, Kind=Secret"
Name: "mysecret", Namespace: "development"
Object: &{map["apiVersion":"v1" "data":map["password":"MWYyZDFlMmU2N2Rm" "username":"YWRtaW4="] "kind":"Secret" "metadata":map["annotations":map["kubectl.kubernetes.io/last-applied-configuration":""] "name":"mysecret" "namespace":"development"]]}
from server for: "credentials.yaml": secrets "mysecret" is forbidden: User "dave" cannot get resource "secrets" in API group "" in the namespace "development"
ЗаключениеМы показали, как использовать сертификат клиента для авторизации пользователей в кластере Kubernetes. Можно настраивать аутентификацию другим способом, но этот довольно прост.После настройки аутентификации мы использовали роль, чтобы определить некоторые права, ограниченные пространством имен, и привязать их к пользователю с помощью RoleBinding. Если нам нужно будет предоставить права для всего кластера, мы сможем использовать ресурсы ClusterRole и ClusterRoleBinding.Что еще почитать:
===========
Источник:
habr.com
===========

===========
Автор оригинала: Luc Juggery
===========
Похожие новости: Теги для поиска: #_oblachnye_vychislenija (Облачные вычисления), #_devops, #_kubernetes, #_k8s, #_kubernetes, #_kontejnerizatsija (контейнеризация), #_devops, #_blog_kompanii_mail.ru_group (
Блог компании Mail.ru Group
)
, #_oblachnye_vychislenija (
Облачные вычисления
)
, #_devops, #_kubernetes
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 13:52
Часовой пояс: UTC + 5