Как Kubernetes решает, что вам можно:
Любой запрос к API-серверу проходит три этапа. Сначала аутентификация: кто ты. Потом авторизация: можно ли тебе это действие. И третий этап, admission control: цепочка контроллеров, которая может изменить или отклонить запрос уже после успешной авторизации, через нее работают, например, Pod Security Admission и validating-вебхуки. В этой главе занимаемся вторым этапом. За авторизацию по умолчанию отвечает RBAC (Role-Based Access Control), он включен практически везде, от minikube до managed-кластеров в Yandex Cloud.
В RBAC всего четыре типа объектов. Role описывает набор разрешений внутри одного namespace. ClusterRole делает то же самое на весь кластер, плюс покрывает кластерные ресурсы, то есть не привязанные ни к какому namespace: nodes, persistentvolumes, сами namespaces. RoleBinding привязывает роль к субъекту в рамках namespace, ClusterRoleBinding во всем кластере. Субъектом может быть пользователь, группа или ServiceAccount.
Запретить что-то в RBAC нельзя, правил deny не существует. По умолчанию закрыто все, роли только добавляют разрешения. Поэтому думать надо в терминах минимально необходимого доступа, а не отрезания лишнего.
Практика: read-only доступ к подам
Типовая задача: сервису мониторинга нужно читать поды и их логи в namespace shop, и ничего больше.
Код: Выделить всё
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: shop
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
Отдельная категория, спец-verbs: escalate и bind позволяют выдавать через RBAC права шире собственных, impersonate разрешает выполнять запросы от чужого имени, use дает применять политики (в ванильном Kubernetes после удаления PodSecurityPolicy в 1.25 почти не встречается, в OpenShift нужен для SecurityContextConstraints). Все четыре опасны, выдавайте их только осознанно. И не пишите wildcard "*" в verbs, resources или apiGroups: такая роль молча подхватит в том числе разрешения, которые появятся в кластере позже, с новыми CRD или версиями API.
Прежде чем сочинять роль с нуля, посмотрите встроенные. В каждом кластере уже есть ClusterRole view (чтение почти всего в namespace, кроме секретов), edit (правка большинства ресурсов) и admin (почти полный контроль в namespace, включая раздачу прав через RoleBinding). Для типового read-only доступа стандартная практика это забиндить готовый view, а не писать свое. Наш pod-reader учебный, и он заметно уже, чем view.
Теперь субъект и привязка. Поды ходят в API под ServiceAccount, по умолчанию это ServiceAccount с именем default и пустыми правами.
Код: Выделить всё
apiVersion: v1
kind: ServiceAccount
metadata:
name: monitoring
namespace: shop
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: monitoring-pod-reader
namespace: shop
subjects:
- kind: ServiceAccount
name: monitoring
namespace: shop
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Важный паттерн на будущее: ClusterRole можно привязать обычным RoleBinding, и тогда ее права действуют только в namespace биндинга. Так одна роль переиспользуется в любом числе namespace без копипасты Role. Например, read-only доступ через встроенный view:
Код: Выделить всё
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: monitoring-view
namespace: shop
subjects:
- kind: ServiceAccount
name: monitoring
namespace: shop
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
Проверять права созданием тестовых подов не нужно, есть kubectl auth can-i:
Код: Выделить всё
kubectl auth can-i list pods -n shop \
--as=system:serviceaccount:shop:monitoring
# yes
kubectl auth can-i delete pods -n shop \
--as=system:serviceaccount:shop:monitoring
# no
# показать вообще все, что разрешено субъекту в namespace
kubectl auth can-i --list -n shop \
--as=system:serviceaccount:shop:monitoring
Если токен нужен внешнему скрипту, учтите: с версии 1.24 секреты с токенами для ServiceAccount автоматически не создаются. Токен запрашивается явно и живет ограниченное время:
Код: Выделить всё
kubectl create token monitoring -n shop --duration=1h
Типичные грабли:
Выдать всем cluster-admin "временно, чтобы заработало". Откатывать потом тяжело, никто не помнит, кому и зачем выдавали. Лечится регулярным просмотром kubectl get clusterrolebindings.
Право list на secrets фактически раскрывает их содержимое: list возвращает полные объекты со значениями. Если сервису нужен один секрет, выдавайте get на конкретное имя через resourceNames. На list и watch resourceNames тоже действует, но с оговоркой: клиент обязан сам передать field selector по имени, совпадающему с resourceNames, иначе запрос не пройдет авторизацию. Голый kubectl get secrets вернет 403, а kubectl get secrets --field-selector=metadata.name=db-credentials пройдет. Ограничить по имени нельзя только create (имя нового объекта в момент авторизации еще неизвестно) и deletecollection.
roleRef в биндинге неизменяемый. Решили привязать другую роль, придется удалить RoleBinding и создать заново, kubectl apply здесь вернет ошибку.
Классика: ServiceAccount в subjects указан с чужим namespace. RoleBinding при этом создастся без единой ошибки, права просто молча не появятся. У ClusterRoleBinding поведение другое: namespace для ServiceAccount там обязателен, объект без него API-сервер отклонит сразу, с ошибкой subjects.namespace: Required value. Молчаливый вариант с RoleBinding kubectl auth can-i с --as находит за минуту.
И последнее: если под вообще не ходит в Kubernetes API (а большинство приложений не ходит), ставьте automountServiceAccountToken: false в спеке пода. Меньше токенов в файловых системах контейнеров, меньше поверхность атаки.
Что усвоили:
RBAC аддитивен, по умолчанию закрыто все. Role и RoleBinding работают в namespace, ClusterRole и ClusterRoleBinding на весь кластер, при этом ClusterRole через обычный RoleBinding переиспользуется в отдельных namespace. Поды живут под ServiceAccount, права проверяются через kubectl auth can-i, а для типового доступа сначала смотрим встроенные view, edit и admin. Это последняя глава курса, база у вас теперь есть. Дальше по теме безопасности смотрите NetworkPolicy и Pod Security Standards, а навыки отладки из главы 11 пригодятся и тут: заметная часть "не работает" в проде оказывается банальным 403.