Kubernetes: знакомство, часть 5 — RBAC авторизация и примеры Role и RoleBinding

Автор: | 03/25/2020
 

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

AWS EKS использует AWS IAM для аутентификации в в Kubernetes-кластере (см. пост Kubernetes: знакомство, часть 4 — аутентификация в AWS EKS, aws-iam-authenticator и AWS IAM), но для авторизации, т.е. определения конкретных прав доступа — используется встроенный RBAC-механизм самого Kubernetes.

Предыдущие части:

Рассмотрим общие понятия RBAC, а затем создадим пользователя с нужными правами.

Обзор Kubernetes RBAC

Документация — Authorization Overview и Using RBAC Authorization.

RBAC модель в Kubernetes состоит  из трёх компонентов:

  • Роли: определение разрешений
  • Субъекты: Пользователи (люди или приложения), или группы пользователей
  • RoleBingdings: указывает, какие Пользователи имеют какие Роли

RBAC Role

Пример роли с именем example-role для доступа к подам в неймспейсе mynamespace, которая разрешает выполнять get, watch и list операции:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: mynamespace
  name: example-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Для получения списка Kubernetes apiGroups используем kubectl api-resources:

kubectl api-resources -o wide
NAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KIND                             VERBS
...
pods                              po                                          true         Pod                              [create delete deletecollection get list patch update watch]
...

В rules примера выше мы:

  1. apiGroups: [""] — указываем core API group
  2. resources: ["pods"] — к ресурсам какого типа разрешено обращение
  3. ["get", "watch", "list"] — какие actions разрешены над этими ресурсами

RBAC RoleBingding

Для того, что бы пользователь получил эти разрешения — создаётся RoleBingding, который в неймспейсе mynamespace связывает роль example-role с пользователем example-user:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-rolebinding
  namespace: mynamespace
subjects:
- kind: User
  name: example-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: example-role
  apiGroup: rbac.authorization.k8s.io

Тут:

  • subjects:
    • kind: User — тип объекта, которому разрешён доступ, в нашем случае это будет обычный пользователь
    • name: example-user — имя пользователя, которому подключаем права
  • roleRef:
    • kind: Role — что именно подключаем пользователю, в этом случае объект типа Role
    • name: example-role — собственно имя роли, как мы её задали в name: example-role в примере самой роли выше

Role vs ClusterRole

Role и ClusterRole представляют собой набор правил, которые описывают доступы, аналогично имеются RoleBinding и ClusterRoleBinding.

Разница между ними в том, что Role задаёт права доступа в определённом неймспейсе, тогда как ClusterRole — на уровне всего кластера, например:

  • к ресурсам типа ноды кластера
  • ресурсы по всем неймспейсам кластера
  • доступ к ендпоинтам типа /healthz

Выглядит ClusterRole аналогично, с той разницей, что kind указывается ClusterRole:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-clusterrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

И пример ClusterRoleBinding:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-clusterrolebinding
subjects:
- kind: User
  name: example-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: example-clusterrole
  apiGroup: rbac.authorization.k8s.io

Имейти ввиду, что после создания Binding у вас не будет возможности изменить roleRef — для этого биндинг треубется удалить, и создать заново.

EKS аутентификация и авторизация

Вкратце, аутентификация и авторизация происходит в следующем порядке:

  1. Аутентификация
    1. клиент выполняет запрос к Kubernetes-кластеру, передавая токен аутентификации, в котором включён ID пользователя
    2. Kubernetes, используя aws-iam-authenticator обращается к AWS IAM, и проверяет — имеется ли пользователь в системе, и является ли он тем, за кого себя выдаёт
  2. Авторизация
    1. если пользователь прошёл Аутентификацию — то Kubernetes передёт его в свой механизм RBAC вместе со всеми запрошенными действиями и ресурсами
    2. в RBAC ищется RoleBinding, которая связывает пользователя с определённой ролью
    3. по имени роли проверяются разрешения на доступ к ресурсам и действиям
    4. принимается решение о разрешении или запрете действий

 

Далее выполним:

  1. создадим IAM пользователя
  2. настроим AWS CLI
  3. создадим RBAC Role с правами read-only на поды
  4. создадим RBAC RoleBinding, которая свяжет пользователя и роль

IAM пользователь

Начнём с создания IAM-юзера.

Добавляем пользователя с Programmatic Access:

Получаем его ключи доступа:

IAM policy

Если пользователю потребуются права на выполнение запросов к самому AWS EKS сервису, например — kubectl get nodes — то отдельно добавляем политику с разрешениями на API-вызовы к ядру AWS.

Переходим в Policies — Add Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "eks:DescribeCluster",
                "eks:ListClusters"
            ],
            "Resource": "*"
        }
    ]
}

Тут разрешаем всего два действия — eks:DescribeCluster и eks:ListClusters, во всех регионах для всех кластеров EKS.

Сохраняем её, и подключаем политику к пользователю:

AWS CLI config

Что бы настроить kubectl — сначала настраиваем AWS CLI под отдельный профиль, см. AWS: именованные профили доступа:

aws configure --profile eks-ro-user
AWS Access Key ID [None]: AKI***FYC
AWS Secret Access Key [None]: SzH***VGi
Default region name [None]: eu-north-1
Default output format [None]: json

Проверяем доступ к AWS:

aws --profile eks-ro-user sts get-caller-identity
{
"UserId": "AID***XGK",
"Account": "534***385",
"Arn": "arn:aws:iam::534***385:user/eks-ro-user"
}

И проверяем доступ к EKS-кластерам  (вернее — к AWS API):

aws --profile eks-ro-user eks list-clusters --output text
CLUSTERS        eks-alb-testing-3
CLUSTERS        eks-alb-testing-2

Kubernetes RBAC — пример

Role

Создаём роль — указываем доступ только к pods, их логам и на создание port-forwading, и только на операции get, list, create:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: eks-ro-role
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/portforward"]
  verbs: ["get", "list", "create"]

Применяем:

kubectl apply -f rbac-role.yml
role.rbac.authorization.k8s.io/eks-ro-role created

Проверяем:

kubectl get roles -o yaml
apiVersion: v1
items:
- apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","metadata":{"annotations":{},"name":"eks-ro-role","namespace":"default"},"rules":[{"apiGroups":[""],"resources":["pods","pods/log"],"verbs":["get","list"]}]}
creationTimestamp: "2020-03-24T10:34:27Z"
name: eks-ro-role
namespace: default
resourceVersion: "681997"
selfLink: /apis/rbac.authorization.k8s.io/v1/namespaces/default/roles/eks-ro-role
uid: 09a78b6f-6dbb-11ea-827f-0a9eb3e1782e
rules:
- apiGroups:
- ""
resources:
- pods
- pods/log
verbs:
- get
- list
kind: List
metadata:
resourceVersion: ""
selfLink: ""

RoleBinding

Добавляем биндинг — связываем нашу роль и пользователя:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: eks-ro-role-binding
subjects:
- kind: User
  name: eks-ro-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: eks-ro-role
  apiGroup: rbac.authorization.k8s.io

Применяем:

kubectl apply -f rbac-rolebinding.yml
rolebinding.rbac.authorization.k8s.io/eks-ro-role-binding created

aws-auth ConfigMap

Редактируем aws-auth ConfigMap (см. AWS EKS aws-auth ConfigMap):

kubectl edit configmap aws-auth -n kube-system

Добавляем mapUsers — указываем ARN пользователя, его имя и его группу(ы):

apiVersion: v1
data:
  mapRoles: |
    - groups:
      - system:bootstrappers
      - system:nodes
      rolearn: arn:aws:iam::534***385:role/eksctl-eks-alb-testing-2-nodegrou-NodeInstanceRole-M6BS1WV48RLR
      username: system:node:{{EC2PrivateDNSName}}
  mapUsers: |
    - userarn: arn:aws:iam::534***385:user/eks-ro-user
      username: eks-ro-user
      groups: eks-ro-role

Проверяем:

kubectl get pods --as eks-ro-user
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7db9fccd9b-7d4rq   1/1     Running   0          58m

Попробуем получить список Worker Nodes — к ним доступа мы не давали:

kubectl get nodes --as eks-ro-user
Error from server (Forbidden): nodes is forbidden: User "eks-ro-user" cannot list resource "nodes" in API group "" at the cluster scope

Отлично.

Проверим логи — запускаем порт-форвардинг на под с NGINX:

kubectl --as eks-ro-user port-forward nginx-7db9fccd9b-7d4rq 8000:80
Forwarding from 127.0.0.1:8000 -> 80
Forwarding from [::1]:8000 -> 80

Выполняем запрос к поду:

curl -I localhost:8000
HTTP/1.1 200 OK

Логи:

kubectl --as eks-ro-user logs -f nginx-7db9fccd9b-7d4rq
127.0.0.1 - - [25/Mar/2020:07:29:06 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.69.1" "-"

Готово.

Ссылки по теме