Kubernetes RBAC чаще всего вспоминают в момент, когда пайплайн внезапно получает Forbidden, а «быстрый фикс» в виде cluster-admin уже однажды приводил к инцидентам. Ниже — практичный подход к RBAC для DevOps/CI: как проектировать права под пайплайны, как использовать ServiceAccount, чем отличаются RoleBinding и ClusterRoleBinding, как применять принцип least privilege и как быстро диагностировать доступ командой kubectl auth can-i.
RBAC в Kubernetes: что реально проверяется
RBAC (Role-Based Access Control) отвечает на вопрос: «может ли конкретный субъект выполнить конкретное действие над конкретным ресурсом». Проверка строится на тройке:
- кто: пользователь, группа или
ServiceAccount; - что делает:
get,list,watch,create,update,patch,delete(и специальные глаголы вродеimpersonate); - над чем: ресурс (
pods,deployments,jobs,secrets), API-группа и область видимости (namespace или cluster).
Частая ловушка: RBAC не «даёт доступ к namespace целиком», он даёт доступ к конкретным ресурсам и операциям. Поэтому запрос «дай доступ в неймспейс» на практике превращается в набор правил на наиболее используемые ресурсы и подресурсы этого неймспейса.
Если сомневаетесь, какие права нужны пайплайну, начните с минимального набора (read-only), а затем добавляйте точечно то, что ломает деплой. Это и есть рабочая тактика least privilege.
Role и ClusterRole: где живут правила
Role — набор правил в пределах одного namespace. Подходит, когда CI управляет объектами внутри конкретного окружения: например, dev или staging.
ClusterRole — набор правил на уровне кластера. Он нужен в двух случаях:
- ресурс кластерный (например,
nodes,persistentvolumes,namespaces,clusterroles); - вы хотите переиспользовать один и тот же набор правил в разных namespaces (а привязки делать отдельно).
Вторая причина особенно удобна в GitOps: один набор правил хранится в одном месте, а область действия ограничивается привязками.
RoleBinding и ClusterRoleBinding: что к чему привязывает
RoleBinding создаётся в namespace и выдаёт права субъекту в рамках этого namespace. Он может ссылаться как на Role, так и на ClusterRole.
ClusterRoleBinding выдаёт права на весь кластер (или на все namespaces для namespaced-ресурсов). Для CI это обычно «слишком широко», использовать стоит только по необходимости и с понятным обоснованием.

ServiceAccount для CI: базовый шаблон
Для пайплайна правильный субъект почти всегда — отдельный ServiceAccount в нужном namespace. Он живёт рядом с приложением и хорошо ревьюится в репозитории манифестов.
Минимальная конструкция: ServiceAccount + Role (или ClusterRole) + RoleBinding.
Пример: деплой приложения в одном namespace без прав «на всё»
Ниже — пример, который обычно покрывает типовой CI-деплой: обновить Deployment, посмотреть статус Pods/ReplicaSets, читать события, при необходимости оценить прогресс rollout. Обратите внимание: мы не даём доступ к secrets и не выдаём delete «на всякий случай».
apiVersion: v1
kind: Namespace
metadata:
name: staging
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-deployer
namespace: staging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ci-deployer-role
namespace: staging
rules:
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["pods", "pods/log", "events"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-deployer-binding
namespace: staging
subjects:
- kind: ServiceAccount
name: ci-deployer
namespace: staging
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ci-deployer-role
Что это даёт на практике:
- пайплайн сможет применить патч к
Deployment(например, поменять image tag); - сможет читать состояние подов и логи (если оставили
pods/log); - не сможет читать секреты, создавать CRD, трогать другие namespaces.
Least privilege в CI/CD: как не скатиться в cluster-admin
Принцип least privilege удобнее внедрять не как «идеальную схему сразу», а как процесс:
- Определите границу ответственности: один namespace (лучше) или несколько (реже).
- Выдайте read-only на ключевые ресурсы (
get/list/watch). - Добавляйте write-доступ строго под операции пайплайна (часто
patch/updateнаdeployments, иногдаcreateнаjobs). - Отдельно решите вопрос с секретами: CI почти никогда не должен читать Kubernetes Secrets «как есть».
Почему чтение Secrets — самый частый RBAC-антипаттерн
Если дать CI права get на secrets, вы фактически превращаете любой компрометированный runner/токен в ключ от всех учёток приложения в этом namespace. Даже если «runner внутри периметра», это плохой размен.
Практичнее:
- передавать секреты в CI через защищённое хранилище переменных (а в кластер — через отдельный процесс доставки секретов);
- разделять «деплой» и «управление секретами» разными
ServiceAccountс разными правами; - если очень нужно — ограничивать доступ к секретам по именам через
resourceNamesи документировать риск.
Если тема управления секретами у вас болит регулярно, посмотрите практику ротации и разделения доступа в материале про секреты в Docker Compose: ротация секретов и безопасная работа с ними.
ClusterRole + RoleBinding: переиспользуем правила и не расширяем область
Для нескольких окружений часто хочется иметь один общий набор правил (чтобы не копировать Role в каждый namespace). Здесь удобна связка: ClusterRole с правилами + RoleBinding в каждом namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ci-deployer-common
rules:
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["pods", "pods/log", "events"]
verbs: ["get", "list", "watch"]
И привязка в конкретном namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-deployer-common-binding
namespace: staging
subjects:
- kind: ServiceAccount
name: ci-deployer
namespace: staging
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ci-deployer-common
Ключевой смысл: правила лежат «глобально», но применяются только там, где вы сделали RoleBinding.
Когда без ClusterRoleBinding действительно не обойтись
Для DevOps/CI это редкие, но реальные кейсы:
- pipeline управляет объектами в разных namespaces без заранее известного списка (например, создаёт namespace под preview-окружение);
- нужно управлять кластерными ресурсами (например,
namespaces,nodes, некоторыми объектами контроллеров/операторов); - нужно работать с политиками/допусками на уровне кластера (в зависимости от вашего стека).
Если вы дошли до ClusterRoleBinding, остановитесь и зафиксируйте, почему это оправдано. В большинстве продуктовых деплоев это избыточно.

Диагностика RBAC: kubectl auth can-i и «почему Forbidden»
Команда kubectl auth can-i помогает быстро понять, проблема в RBAC или в чём-то ещё. Её удобно запускать локально и прямо в CI (как диагностический шаг при падении).
Быстрые проверки
kubectl auth can-i patch deployment -n staging
kubectl auth can-i get pods -n staging
kubectl auth can-i get secrets -n staging
Чтобы проверить права конкретного ServiceAccount, используйте impersonation:
kubectl auth can-i update deployments -n staging --as=system:serviceaccount:staging:ci-deployer
kubectl auth can-i create jobs -n staging --as=system:serviceaccount:staging:ci-deployer
Также полезно посмотреть «карту» разрешений целиком:
kubectl auth can-i --list -n staging --as=system:serviceaccount:staging:ci-deployer
Типовые причины ошибок доступа
- Не та API-группа. Например,
deploymentsживут вapps, а не в core-группе"". - Не тот ресурс.
pods/log— отдельный подресурс, на него нужны отдельные правила. - Не тот глагол.
kubectl applyчасто делаетpatch, а неupdate. - Не тот namespace.
RoleBindingдействует только там, где создан. - Ожидали, что ClusterRole «сам применится». Нет, нужна привязка (
RoleBindingилиClusterRoleBinding).
Практика для CI: два ServiceAccount лучше, чем один «универсальный»
В больших проектах удобно разделять роли:
- ci-deployer: обновляет workload-ресурсы (Deployment/StatefulSet), читает статус, смотрит логи;
- ci-migrator (опционально): создаёт
Jobдля миграций или выполняет ad-hoc задачи в кластере.
Почему это полезно: миграции часто требуют больше прав или доступа к сервисам, и безопаснее изолировать риск отдельным токеном/учёткой и отдельным сроком жизни доступа.
Мини-чеклист ревью RBAC для пайплайна
- Есть отдельный
ServiceAccountпод пайплайн (неdefault). - Используется
RoleBindingв нужном namespace;ClusterRoleBinding— только если обосновано. - Нет прав на
secretsбез крайней необходимости; если есть — ограниченыresourceNamesи всё задокументировано. - Есть быстрые проверки через
kubectl auth can-i(в идеале — как диагностический шаг при падении). - Набор глаголов минимален: чаще достаточно
get/list/watchплюсpatch/updateна конкретные ресурсы.
Итог
Kubernetes RBAC для DevOps/CI — это не про «сделать, чтобы работало любой ценой», а про управляемые и проверяемые границы. Делайте пайплайны субъектами через ServiceAccount, выдавайте права через RoleBinding в конкретных namespaces, избегайте ClusterRoleBinding без причины и всегда подтверждайте гипотезы командой kubectl auth can-i. Такой подход обычно даёт и безопасность (least privilege), и предсказуемость деплоев.


