Сервисный аккаунт (ServiceAccount) — это учётная запись для программных клиентов Kubernetes: подов, CI/CD-пайплайнов, скриптов, kubectl на другой машине, внешних инструментов мониторинга.
Для подов Kubernetes автоматически создаёт токен сервисного аккаунта и пробрасывает его в под. Этот токен ограничен по времени действия и периодически обновляется: он удобен для работы внутри кластера, но не подходит для внешних клиентов, которым нужнен постоянный не изменяемый доступ.
Токен, выданный через секрет, не имеет срока действия — он валиден, пока существует сам секрет. Это удобно, когда клиенту нужен постоянные токен, который не нужно регулярно перевыпускать.
В данной статье рассмотрим создание сервисного аккаунта с полным доступом к кластеру и постоянного токена для него, а также то, как отозвать токен и изменить права доступа.
Перед началом работы вам понадобится:
Кластер Kubernetes в NetAngels
Установленная утилита kubectl с настроенным доступом (конфигурационный файл кластера)
Создадим сервисный аккаунт admin в неймспейсе kube-system, секрет для постоянного токена и привязку к встроенной роли cluster-admin (полный доступ к кластеру):
kubectl apply -f - <<EOF
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: kube-system
---
apiVersion: v1
kind: Secret
metadata:
name: admin-token-secret
namespace: kube-system
annotations:
kubernetes.io/service-account.name: "admin"
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin
namespace: kube-system
EOF
serviceaccount/admin created
secret/admin-token-secret created
clusterrolebinding.rbac.authorization.k8s.io/admin created
Проверим созданные ресурсы:
kubectl get sa/admin secret/admin-token-secret -n kube-system
NAME SECRETS AGE
serviceaccount/admin 0 0s
NAME TYPE DATA AGE
secret/admin-token-secret kubernetes.io/service-account-token 3 0s
Секрет уже содержит три поля — ca.crt, namespace и token. Токен генерируется Kubernetes сразу после создания секрета: его нельзя задать самому, только получить.
Обратите внимание: роль cluster-admin даёт полный доступ к кластеру, и утечка такого токена означает потерю контроля над всем кластером. В рабочих сценариях выдавайте сервисным аккаунтам минимально необходимые права — как показано в разделе 5.
kubectl get secret admin-token-secret -n kube-system -o jsonpath='{.data.token}' | base64 -d
<токен>
Это JWT без срока действия (в payload нет поля exp). Токен можно сохранить в переменную окружения, файл или сразу подставить в конфигурацию клиента.
Для работы с кластером сформируем конфигурационный файл для kubectl, в котором пользователь описан токеном, а не сертификатом. Сформировать его можно командами kubectl config: из конфига администратора берём только описание кластера — адрес API-сервера и CA-сертификат, — а пользователя создаем с токеном из секрета.
Сначала сохраним CA-сертификат из конфига администратора в файл. Без флага --flatten команда kubectl config view заменяет данные сертификатов плейсхолдером DATA+OMITTED, поэтому флаг обязателен:
kubectl config view --flatten -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt
Теперь создаём sa-cluster.yaml: описываем кластер, встраиваем в него CA-сертификат, добавляем пользователя с токеном и контекст, связывающий их. Значение --server — адрес API-сервера из вашего конфига администратора:
KUBECONFIG=sa-cluster.yaml kubectl config set-cluster my-cluster --server=https://<адрес API-сервера>:6443 --certificate-authority=ca.crt --embed-certs
KUBECONFIG=sa-cluster.yaml kubectl config set-credentials sa-admin --token=<токен>
KUBECONFIG=sa-cluster.yaml kubectl config set-context sa-cluster --cluster=my-cluster --user=sa-admin
KUBECONFIG=sa-cluster.yaml kubectl config use-context sa-cluster
Cluster "my-cluster" set.
User "sa-admin" set.
Context "sa-cluster" created.
Switched to context "sa-cluster".
Флаг --embed-certs встраивает содержимое ca.crt прямо в файл, поэтому sa-cluster.yaml самодостаточен и может быть перенесён на другую машину; сам ca.crt можно удалить.
Результат:
KUBECONFIG=sa-cluster.yaml kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://<адрес API-сервера>:6443
name: my-cluster
contexts:
- context:
cluster: my-cluster
user: sa-admin
name: sa-cluster
current-context: sa-cluster
kind: Config
users:
- name: sa-admin
user:
token: REDACTED
Поля certificate-authority-data и token в выводе маскируются самим kubectl — в файле хранятся настоящий сертификат и токен.
Теперь можно обращаться к API по токену:
KUBECONFIG=sa-cluster.yaml kubectl get nodes
NAME STATUS ROLES AGE VERSION
worker-1 Ready <none> 7d21h v1.33.8+k0s
Для проверки доступа без kubectl можно обратиться к API-серверу напрямую с заголовком Authorization: Bearer:
curl -sk https://<адрес API-сервера>:6443/api/v1/namespaces/default -H "Authorization: Bearer <токен>"
{
"kind": "Namespace",
"apiVersion": "v1",
"metadata": {
"name": "default",
"uid": "984052be-d563-4f82-ae69-9269d695e4f1",
"resourceVersion": "8",
"creationTimestamp": "2026-08-26T12:36:39Z",
"labels": {
"kubernetes.io/metadata.name": "default"
},
"managedFields": [
{
"manager": "kube-apiserver",
"operation": "Update",
"apiVersion": "v1",
"time": "2026-08-26T12:36:39Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:metadata": {
"f:labels": {
".": {},
"f:kubernetes.io/metadata.name": {}
}
}
}
}
]
},
"spec": {
"finalizers": [
"kubernetes"
]
},
"status": {
"phase": "Active"
}
}
Права аккаунта можно проверить командой kubectl auth can-i, используя конфиг с токеном из предыдущего раздела:
KUBECONFIG=sa-cluster.yaml kubectl auth can-i get pods
yes
KUBECONFIG=sa-cluster.yaml kubectl auth can-i create deployments
yes
KUBECONFIG=sa-cluster.yaml kubectl auth can-i get nodes
Warning: resource 'nodes' is not namespace scoped
yes
Аккаунт имеет полный доступ — cluster-admin разрешает любые операции с любыми ресурсами.
Права конфигурируются связями сервисных аккаунтов с ролями (ClusterRoleBinding/RoleBinding) на момент каждого запроса, поэтому изменение прав отражается на действующих токенах сразу.
Изменить права доступа — значит удалить связь и/или создать новую. Например, ограничим аккаунт до чтения подов и сервисов:
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: sa-restricted
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list"]
EOF
clusterrole.rbac.authorization.k8s.io/sa-restricted created
kubectl delete clusterrolebinding admin
clusterrolebinding.rbac.authorization.k8s.io "admin" deleted
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: sa-restricted
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: sa-restricted
subjects:
- kind: ServiceAccount
name: admin
namespace: kube-system
EOF
clusterrolebinding.rbac.authorization.k8s.io/sa-restricted created
Проверим права после:
KUBECONFIG=sa-cluster.yaml kubectl auth can-i get pods
yes
KUBECONFIG=sa-cluster.yaml kubectl auth can-i create deployments
no
KUBECONFIG=sa-cluster.yaml kubectl auth can-i get nodes
Warning: resource 'nodes' is not namespace scoped
no
Токен при этом не меняется — запросы с тем же токеном к ранее разрешённым операциям теперь завершаются отказом в доступе (код 403):
curl -sk https://<адрес API-сервера>:6443/api/v1/nodes -H "Authorization: Bearer <токен>"
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "nodes is forbidden: User \"system:serviceaccount:kube-system:admin\" cannot list resource \"nodes\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "nodes"
},
"code": 403
}
Постоянный токен отзывается удалением секрета, в котором он хранится:
kubectl delete secret admin-token-secret -n kube-system
secret "admin-token-secret" deleted from kube-system namespace
Проверим доступ к API с использованием удаленного токена:
curl -sk https://<адрес API-сервера>:6443/api/v1/pods -H "Authorization: Bearer <токен>"
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
Если вместе с токеном не нужен и сам аккаунт, достаточно удалить ServiceAccount — все связанные с ним токены перестанут работать. Если же действующий токен понадобится снова, секрет можно создать заново — Kubernetes сгенерирует новый токен.
Секрет с токеном уже удалён в разделе 6, удаляем оставшиеся ресурсы:
kubectl delete clusterrolebinding sa-restricted
kubectl delete clusterrole sa-restricted
kubectl delete sa admin -n kube-system
clusterrolebinding.rbac.authorization.k8s.io "sa-restricted" deleted
clusterrole.rbac.authorization.k8s.io/sa-restricted deleted
serviceaccount "admin" deleted from kube-system namespace