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

Автор: | 25/03/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:

[simterm]

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

[/simterm]

В 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: именованные профили доступа:

[simterm]

$ 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

[/simterm]

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

[simterm]

$ 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"
}

[/simterm]

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

[simterm]

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

[/simterm]

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"]

Применяем:

[simterm]

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

[/simterm]

Проверяем:

[simterm]

$ 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: ""

[/simterm]

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

Применяем:

[simterm]

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

[/simterm]

aws-auth ConfigMap

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

[simterm]

$ kubectl edit configmap aws-auth -n kube-system

[/simterm]

Добавляем 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

Проверяем:

[simterm]

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

[/simterm]

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

[simterm]

$ 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

[/simterm]

Отлично.

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

[simterm]

$ 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

[/simterm]

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

[simterm]

$ curl -I localhost:8000
HTTP/1.1 200 OK

[/simterm]

Логи:

[simterm]

$ 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" "-"

[/simterm]

Готово.

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