Kubernetes: ServiceAccount, Role, RoleBinding
Права в Kubernetes — ServiceAccount, Role и ClusterRole, правила apiGroups/resources/verbs, привязки и токен пода
RBAC (role-based access control) решает, кому что можно делать в API Kubernetes. Схема из трёх частей:
| Часть | Объекты | Что описывает |
|---|---|---|
| Кто | ServiceAccount (для программ в подах), User и Group (люди; в Kubernetes объектами не являются — приходят из сертификата или внешней аутентификации) | субъект |
| Что можно | Role (в одном неймспейсе), ClusterRole (во всём кластере или как шаблон) | набор правил «ресурсы × действия» |
| Связка | RoleBinding (в неймспейсе), ClusterRoleBinding (во всём кластере) | выдаёт роль субъектам |
Правила только разрешают: запрещающих правил нет, по умолчанию запрещено всё. Права субъекта — объединение всех привязанных к нему ролей.
Синтаксис
apiVersion: v1
kind: ServiceAccount
metadata:
name: app
namespace: dev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: dev
rules:
- apiGroups: [""] # "" — базовая группа: pods, services, configmaps…
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-pod-reader
namespace: dev
subjects:
- kind: ServiceAccount
name: app
namespace: dev
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
Без кластера генерируются ServiceAccount, RoleBinding и ClusterRoleBinding (kubectl create serviceaccount|rolebinding|clusterrolebinding … --dry-run=client -o yaml). kubectl create role и create clusterrole обращаются к серверу даже с --dry-run=client — роли пиши руками или собирай через yq.
ServiceAccount
| Поле | Что значит | По умолчанию / заметки |
|---|---|---|
metadata.name, metadata.namespace | имя; ServiceAccount всегда живёт в неймспейсе | в каждом неймспейсе есть ServiceAccount default |
automountServiceAccountToken | монтировать ли токен в поды с этим аккаунтом | true |
imagePullSecrets | [{name: секрет}] — добавляются ко всем подам с этим аккаунтом |
В поде:
Поле spec пода | Что значит | По умолчанию |
|---|---|---|
serviceAccountName | от имени какого ServiceAccount под обращается к API | default |
automountServiceAccountToken | монтировать ли токен; перекрывает настройку ServiceAccount | как у ServiceAccount |
Токен монтируется в /var/run/secrets/kubernetes.io/serviceaccount/: файлы token (JWT), ca.crt (сертификат API-сервера), namespace. Токен короткоживущий, kubelet обновляет его сам. В API ServiceAccount выглядит как пользователь system:serviceaccount:<неймспейс>:<имя> и входит в группы system:serviceaccounts и system:serviceaccounts:<неймспейс>.
Role и ClusterRole
| Role | ClusterRole | |
|---|---|---|
| Где действует | только в своём неймспейсе (metadata.namespace) | во всём кластере — или в одном неймспейсе через RoleBinding |
| Ресурсы | неймспейсные: pods, deployments, secrets… | ещё и кластерные: nodes, namespaces, persistentvolumes, clusterroles |
| Не-ресурсные URL | нет | nonResourceURLs: ["/healthz", "/metrics"] |
Поля элемента rules[]:
| Поле | Что значит | Примеры |
|---|---|---|
apiGroups | группа API — часть apiVersion до / | "" (v1: pods, services, configmaps, secrets, serviceaccounts), apps (deployments, statefulsets, daemonsets, replicasets), batch (jobs, cronjobs), networking.k8s.io (ingresses, networkpolicies), autoscaling, rbac.authorization.k8s.io, "*" — все |
resources | ресурсы во множественном числе, строчными | pods, deployments; подресурсы: pods/log, pods/exec, deployments/scale; "*" — все |
verbs | действия | см. таблицу ниже; "*" — все |
resourceNames | только объекты с этими именами | ["app-config"]; с create и deletecollection не работает |
nonResourceURLs | URL вне ресурсов (только ClusterRole) | ["/healthz", "/version"] с verbs: ["get"] |
Действия (verbs) и чему они соответствуют:
| Verb | Запрос | Пример команды |
|---|---|---|
get | прочитать один объект | kubectl get pod web-1, describe |
list | список | kubectl get pods |
watch | следить за изменениями | kubectl get pods -w |
create | создать | kubectl create, apply нового объекта; create на pods/exec — kubectl exec |
update | заменить целиком | kubectl replace |
patch | изменить частично | kubectl apply существующего, scale, label, edit |
delete | удалить один | kubectl delete pod web-1 |
deletecollection | удалить многие | kubectl delete pods --all |
kubectl apply нужны сразу get, create и patch.
У ClusterRole есть ещё aggregationRule: {clusterRoleSelectors: [{matchLabels: …}]} — роль автоматически собирает правила других ClusterRole с этими метками. Так устроены встроенные admin, edit, view.
RoleBinding и ClusterRoleBinding
| Поле | Что значит | Заметки |
|---|---|---|
subjects[].kind | ServiceAccount / User / Group | |
subjects[].name | имя субъекта | для групп ServiceAccount: system:serviceaccounts:dev |
subjects[].namespace | неймспейс ServiceAccount | обязательно для ServiceAccount |
subjects[].apiGroup | rbac.authorization.k8s.io для User и Group; для ServiceAccount — не указывать ("") | |
roleRef.kind | Role или ClusterRole | |
roleRef.name | имя роли | |
roleRef.apiGroup | всегда rbac.authorization.k8s.io |
Какие сочетания возможны:
| Привязка | Роль | Результат |
|---|---|---|
| RoleBinding | Role из того же неймспейса | права в этом неймспейсе |
| RoleBinding | ClusterRole | права ClusterRole, но только в неймспейсе привязки — удобно описать роль один раз и выдавать по неймспейсам |
| ClusterRoleBinding | ClusterRole | права во всех неймспейсах и на кластерные ресурсы |
| ClusterRoleBinding | Role | невозможно |
Встроенные ClusterRole: view (чтение без секретов), edit (изменение большинства объектов, без ролей), admin (полный доступ в неймспейсе, включая роли), cluster-admin (всё).
Примеры
# ServiceAccount и привязки — генераторы работают офлайн
kubectl create serviceaccount ci -n dev --dry-run=client -o yaml > sa.yaml
kubectl create rolebinding ci-edit -n dev --clusterrole=edit \
--serviceaccount=dev:ci --dry-run=client -o yaml > rb.yaml
kubectl create rolebinding devs-view -n dev --clusterrole=view \
--user=alice --group=developers --dry-run=client -o yaml
kubectl create clusterrolebinding ci-nodes --clusterrole=node-reader \
--serviceaccount=dev:ci --dry-run=client -o yaml > crb.yaml
# Role: `kubectl create role` требует кластер — собираем через yq
yq -n '
.apiVersion = "rbac.authorization.k8s.io/v1" |
.kind = "Role" |
.metadata = {"name": "deployer", "namespace": "dev"} |
.rules = [
{"apiGroups": ["apps"], "resources": ["deployments"], "verbs": ["get", "list", "create", "patch"]},
{"apiGroups": [""], "resources": ["pods", "pods/log"], "verbs": ["get", "list"]}
]' > role.yaml
# привязать её вместо ClusterRole — roleRef правим так же
yq '.roleRef.kind = "Role" | .roleRef.name = "deployer" | .metadata.name = "ci-deployer"' rb.yaml > rb-role.yaml
# запретить монтирование токена всем подам этого аккаунта
yq -i '.automountServiceAccountToken = false' sa.yaml
kubeconform -strict -summary sa.yaml rb.yaml crb.yaml role.yaml rb-role.yaml
# в кластере (здесь не сработают):
# kubectl auth can-i create deployments -n dev --as=system:serviceaccount:dev:ci
# kubectl auth can-i --list -n dev --as=system:serviceaccount:dev:ci
# kubectl create token ci -n dev --duration=1h
ClusterRole для чтения узлов и неймспейсов и привязка на весь кластер:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader # у кластерных объектов нет namespace
rules:
- apiGroups: [""]
resources: ["nodes", "namespaces"]
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/healthz", "/version"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitoring-node-reader
subjects:
- kind: ServiceAccount
name: monitoring
namespace: observability
- kind: Group
name: sre
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: node-reader
Доступ к одному конкретному ConfigMap и под без токена:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: read-app-config
namespace: dev
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get", "watch"]
---
apiVersion: v1
kind: Pod
metadata:
name: static-site
namespace: dev
spec:
serviceAccountName: default
automountServiceAccountToken: false # приложению API не нужен — токен не монтируем
containers:
- name: web
image: nginx:1.27
Подводные камни
- Неверный
apiGroups— самая частая ошибка. Deployment живёт вapps, а не в""; Ingress — вnetworking.k8s.io; CronJob — вbatch. Группа — это частьapiVersionдо/, а уapiVersion: v1группа пустая:"". - Имя ресурса — во множественном числе и строчными.
Pod,pod,Deploymentвresourcesничего не дадут: нужноpods,deployments. Схема это не проверяет. - Подресурсы — отдельно. Право на
podsне даёт читать логи и делать exec: нужныpods/log(get) иpods/exec(create). listоткрывает содержимое.listнаsecretsвозвращает секреты целиком, не только имена. Права на секреты выдавай как можно уже.roleRefнельзя изменить у существующей привязки: только удалить и создать заново.subjectsменять можно.namespaceу ServiceAccount вsubjectsобязателен, иначе API отвергнет привязку. Схема это не ловит.--serviceaccountвkubectl create rolebinding— в виденеймспейс:имя. Просто--serviceaccount=ci— ошибка.- Role из другого неймспейса RoleBinding не найдёт:
roleRefищет Role только в своём неймспейсе. - ClusterRoleBinding на
editилиadminвыдаёт права во всех неймспейсах. Если нужен один — RoleBinding на ту же ClusterRole. - Нельзя выдать больше, чем есть у тебя. Создать Role или привязку с правами, которых у тебя самого нет, API не даст (без особого verb
escalate/bind). - Токен смонтирован, даже если программе API не нужен. Любой, кто получил shell в контейнере, может использовать его права. Где API не нужен —
automountServiceAccountToken: false. defaultServiceAccount используют все поды безserviceAccountName. Выдал праваdefault— их получили все такие поды неймспейса. Для приложения заводи свой ServiceAccount.- Ошибки доступа видны только в кластере:
Forbidden: User "system:serviceaccount:dev:ci" cannot list resource "pods" … in the namespace "dev". Из сообщения сразу видно, какого verb, ресурса и неймспейса не хватает.
См. также
kubectl · kubeconform · yq · k8s-workloads · k8s-config · sudo · chmod