Ошибка аутентификации в Docker и Kubernetes возникает на одном из трех уровней: при входе в Docker registry и загрузке образа, при подключении клиента к Kubernetes API или при проверке прав через RBAC. Эти сценарии дают похожие сообщения, но требуют разных проверок.
Код 401 Unauthorized обычно означает, что система не получила учетные данные или не смогла их проверить. Код 403 Forbidden чаще говорит об обратном: пользователь или ServiceAccount распознаны, но им запрещено выполнять конкретное действие. Локальный docker login не передает учетные данные в Kubernetes. Kubelet получает credentials через imagePullSecrets, ServiceAccount или настройки container runtime.
Сначала зафиксируйте полный текст ошибки, имя образа или API endpoint, активный context, namespace и действие, которое завершилось отказом. После этого проверяйте только тот компонент, который участвовал в операции.
Короткий ответ: где обычно возникает ошибка аутентификации
При работе с приватным registry ошибка появляется во время docker pull или запуска Pod. Для этого сценария характерны сообщения unauthorized: authentication required, pull access denied и Failed to pull image.
При обращении к Kubernetes API проблема возникает до проверки RBAC. Команда kubectl может вернуть You must be logged in to the server, Unauthorized или сообщение о невозможности получить credentials. Если личность установлена, но разрешения недостаточны, API возвращает Forbidden.
В Kubernetes цепочка выглядит так: клиент или kubelet предъявляет credentials, API-сервер проверяет личность, затем авторизатор RBAC сопоставляет субъект, действие, ресурс и namespace. Сбой на каждом шаге имеет собственные признаки.
Как отличить registry, Kubernetes API и RBAC по сообщению об ошибке
| Где возникает проблема | Типичные признаки | Что проверять первым |
|---|---|---|
| Docker registry | unauthorized, authentication required, pull access denied | Адрес registry, результат docker login, право pull, имя repository и tag |
| Kubelet и загрузка образа | Failed to pull image, ImagePullBackOff, 401 в Events Pod | imagePullSecrets, ServiceAccount, namespace и доступ узла к registry |
| Kubernetes API | You must be logged in, Unauthorized, ошибки token, certificate или exec plugin | Текущий context, endpoint, kubeconfig и срок действия credentials |
| RBAC | Forbidden, cannot get resource, cannot create | Verb, resource, namespace, RoleBinding или ClusterRoleBinding |
| TLS или сеть | x509, timeout, DNS error, connection refused | DNS, CA certificate, hostname, proxy, маршрут и время на узле |
Что проверить в первую очередь
- Уточните точку отказа: команда Docker, запуск Pod, команда
kubectlили запрос приложения к API. - Сверьте полное имя образа или адрес API. Ошибка в hostname, порте, repository и tag часто выглядит как отказ в доступе.
- Проверьте активный context командой
kubectl config current-context. Неизвестный context может направить команду в другой кластер. - Уточните namespace. Secret, ServiceAccount, Deployment и Pod должны относиться к ожидаемому namespace.
- Проверьте срок действия токена, client certificate, refresh token и сессии внешнего провайдера.
- Для запрета RBAC определите точное действие: например,
get pods,list secretsилиcreate deployments.
Ошибка аутентификации Docker registry
Приватный registry участвует в двух разных операциях. Docker CLI получает credentials локального пользователя, а kubelet на узле Kubernetes получает собственные данные для загрузки образа. Успешная проверка в одном месте не подтверждает доступ в другом.
Проверка docker login и доступа к образу
Сначала задайте hostname registry без пути к repository. Для Docker Hub и self-hosted registry формат имени отличается, поэтому лишний путь в параметре входа может привести к сохранению credentials под другим ключом.
export REGISTRY_HOST=registry.example.com
printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY_HOST" --username "$REGISTRY_USER" --password-stdin
docker pull "$REGISTRY_HOST/team/app:1.4.2"
Ключевой результат проверки: команда docker login завершается успешно, а docker pull получает конкретный образ. Первая команда подтверждает проверку личности. Вторая дополнительно проверяет право чтения repository и существование указанного tag.
Ошибка denied: requested access to the resource is denied может означать отсутствие разрешения на repository, даже если логин прошел. Проверьте учетную запись, scope токена и регистр символов в имени repository. У некоторых registry токен должен иметь отдельное право на чтение, например pull или read_registry.
Docker сохраняет настройки в ~/.docker/config.json или передает их credential helper. Не публикуйте этот файл и не выводите его в CI-логи: в нем могут находиться закодированные или получаемые через helper credentials. После теста на общей машине удалите локальную сессию командой docker logout "$REGISTRY_HOST".
Почему docker login не помогает Kubernetes
Kubelet выполняет загрузку образа от имени узла кластера. Он не читает автоматически домашний каталог пользователя, который запускал docker login на рабочей станции. В Kubernetes credentials передают через Secret типа kubernetes.io/dockerconfigjson, подключенный к Pod или его ServiceAccount.
Минимальная связь между ресурсами выглядит так:
apiVersion: v1
kind: Pod
metadata:
name: private-app
namespace: app
spec:
imagePullSecrets:
- name: regcred
containers:
- name: app
image: registry.example.com/team/app:1.4.2
Secret создают в том же namespace, где запускается Pod. Пример команды с переменными окружения:
kubectl create secret docker-registry regcred \
--namespace=app \
--docker-server="$REGISTRY_HOST" \
--docker-username="$REGISTRY_USER" \
--docker-password="$REGISTRY_TOKEN"
В CI используйте защищенные переменные и маскирование значений. Команда с параметром --docker-password может попасть в список процессов на некоторых системах. Для production лучше передавать заранее подготовленный docker config через защищенный канал и контролировать время его жизни.
Проверка адреса registry, имени образа и TLS
Сообщение об аутентификации не всегда связано с паролем. Если клиент обращается к неправильному hostname, registry может ответить от другого виртуального хоста или вернуть общий отказ. Проверьте полное имя вида registry.example.com/team/app:1.4.2, порт, repository и tag.
Проверяйте доступ с узла, где работает kubelet, а не только с ноутбука администратора:
getent hosts registry.example.com
nslookup registry.example.com
openssl s_client -connect registry.example.com:443 -servername registry.example.com </dev/null
Результаты разделяйте по типу:
unauthorizedозначает, что registry получил запрос, но не принял credentials или не выдал право на образ;x509: certificate signed by unknown authorityуказывает на недоверенный CA или неполную цепочку сертификатов;certificate is valid for ...обычно говорит о несовпадении hostname и сертификата;i/o timeoutтребует проверки маршрута, firewall, proxy и доступности порта;- ошибка DNS указывает на неправильную запись, search domain или DNS-конфигурацию узла.
Для self-hosted registry CA нужно добавить в доверенное хранилище container runtime на каждом узле, который скачивает образы. Настройка доверия только в Docker CLI администратора не меняет поведение containerd или CRI-O. Режим insecure registry снижает защиту канала и подходит только для изолированного тестового стенда с контролируемой сетью.
Service account, Secret и imagePullSecrets в Kubernetes
При ошибке загрузки образа проверяйте всю цепочку: Pod выбирает ServiceAccount, ServiceAccount может содержать imagePullSecrets, а Secret хранит credentials для конкретного hostname registry. Любое несоответствие разрывает цепочку.
Проверка Secret для приватного registry
Сначала убедитесь, что Secret существует в нужном namespace и имеет ожидаемый тип:
kubectl get secret regcred -n app -o jsonpath='{.type}'
kubectl get secret regcred -n app -o json | jq -r '.data | keys[]'
Первый вывод должен содержать kubernetes.io/dockerconfigjson, второй обычно показывает ключ .dockerconfigjson. Для проверки hostname декодируйте содержимое в защищенной временной среде и выведите только ключи раздела auths, без пароля и токена. Не используйте kubectl get secret -o yaml в общей консоли или CI-логе.
Частая ошибка появляется, когда Secret создан с параметром --docker-server=registry.example.com, а в Pod указан образ через другой hostname, например с портом или альтернативным DNS-именем. Ключ в docker config должен совпадать с адресом, который container runtime извлекает из image reference.
Какой ServiceAccount использует Pod
Проверьте ServiceAccount непосредственно в Pod и в шаблоне Deployment:
kubectl get pod private-app -n app -o jsonpath='{.spec.serviceAccountName}'
kubectl get deploy private-app -n app -o jsonpath='{.spec.template.spec.serviceAccountName}'
kubectl get sa app-runner -n app -o yaml
Если serviceAccountName не задан, Kubernetes обычно использует ServiceAccount default текущего namespace. Secret, добавленный к другому ServiceAccount, не повлияет на такой Pod.
Настройка через ServiceAccount может выглядеть так:
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-runner
namespace: app
imagePullSecrets:
- name: regcred
После изменения ServiceAccount уже созданный Pod может сохранить прежний набор параметров. Для Deployment пересоздайте Pod через штатное обновление шаблона или удаление конкретного Pod с последующим созданием ReplicaSet. Проверяйте результат в Events, а не по факту успешного применения YAML.
Ошибки namespace и Deployment
Secret и Pod должны находиться в одном namespace. Secret из default не подключается к Pod из app по одному имени. Проверяйте ресурсы с явным указанием namespace:
kubectl get pod -n app
kubectl get secret regcred -n app
kubectl get sa app-runner -n app
kubectl describe pod private-app -n app
В секции Events ищите точный ответ registry и имя используемого образа. Команды kubectl describe pod часто показывают, какой Secret не удалось найти, какой hostname получил runtime и на каком шаге возник ImagePullBackOff.
Проверьте и сам Deployment. Ошибка может находиться в одном из ReplicaSet, если новый манифест применили не к тому namespace или к другому кластеру:
kubectl get deploy private-app -n app -o yaml
kubectl get rs -n app
kubectl config current-context
Kubeconfig и аутентификация в Kubernetes API
kubeconfig описывает три связанные сущности: clusters с endpoint и CA, users с token, client certificate или exec plugin и contexts, которые связывают cluster, user и namespace. Ошибка в любой части мешает kubectl пройти аутентификацию.
Проверка текущего context и endpoint
Начните с безопасных команд, которые не требуют публикации всего файла конфигурации:
kubectl config current-context
kubectl config get-contexts
kubectl config view --minify
kubectl cluster-info
Сверьте имя кластера, endpoint, пользователя и namespace с ожидаемой средой. Вывод kubectl config view --minify может содержать token, certificate data или параметры exec plugin, поэтому не отправляйте его в чат, тикет и CI-лог без очистки.
Если kubectl cluster-info обращается к другому кластеру, исправьте context до выполнения любых изменений. Для разовой команды безопаснее явно указать --context и --namespace, когда такая проверка поддерживается вашей версией клиента.
Истекший токен и client certificate
Внезапный отказ после периода нормальной работы часто связан с истекшим bearer-токеном, client certificate или refresh token. Проверьте способ выдачи credentials: managed Kubernetes, корпоративный OIDC, kubeadm, сертификат пользователя или отдельный exec plugin.
Для локального client certificate срок действия можно проверить в защищенной копии файла:
openssl x509 -in client.crt -noout -dates -subject
Токен из kubeconfig не нужно декодировать и публиковать. Получите новый credential через штатную команду вашей платформы или провайдера. Ручное продление строки token в kubeconfig не решает проблему сессии, issuer, audience и отзывом учетной записи.
Exec plugin, OIDC и проблемы TLS
Exec plugin запускается клиентом kubectl и возвращает credentials через стандартный вывод. Проверяйте наличие команды, право запуска, версию интерпретатора и зависимости:
command -v kubelogin
command -v aws
command -v gcloud
kubectl auth whoami
Названия команд зависят от платформы. Если plugin завершился с ошибкой, изучите stderr локально, не записывая токены в журнал. Сбой часто связан с удаленным кэшем сессии, отсутствием браузерной авторизации, переменными окружения или неверным путем к CA.
Ошибки x509 требуют проверки CA и имени API endpoint. Ошибка hostname mismatch означает, что адрес в kubeconfig не соответствует сертификату API-сервера. Прокси может менять маршрут или TLS-сессию, поэтому проверьте переменные HTTP_PROXY, HTTPS_PROXY и NO_PROXY на машине с kubectl.
RBAC: когда вход выполнен, но доступа все равно нет
Аутентификация отвечает на вопрос «кто выполняет запрос», а RBAC отвечает на вопрос «что этому субъекту разрешено». Пользователь может успешно войти в кластер и получить Forbidden при чтении Pod, создании Deployment или просмотре Secret.
Модель RBAC строится вокруг четырех параметров: subject, verb, resource и области действия. Для запроса get pods в namespace app должны совпасть пользователь или ServiceAccount, действие get, ресурс pods и namespace.
Как читать ошибку Forbidden
Сообщение API обычно содержит полезные поля:
Error from server (Forbidden): pods is forbidden: User "dev-user" cannot get resource "pods" in API group "" in the namespace "app"
Из него нужно извлечь subject dev-user, verb get, resource pods, API group и namespace app. Сверяйте именно эти значения с правилами RBAC. Право на deployments не дает права на pods, а разрешение в default не распространяется на app.
Для системных ресурсов учитывайте subresource. Право на pods отличается от права на pods/log или pods/exec. Ошибка при чтении логов может сохраняться даже при успешном чтении самого Pod.
Проверка через kubectl auth can-i
Проверьте текущую учетную запись:
kubectl auth can-i get pods -n app
kubectl auth can-i list deployments -n app
kubectl auth can-i --list -n app
Для ServiceAccount укажите полное имя субъекта:
kubectl auth can-i get pods -n app --as=system:serviceaccount:app:app-runner
kubectl auth can-i get secrets -n app --as=system:serviceaccount:app:app-runner
kubectl auth can-i '*' '*' --all-namespaces --as=system:serviceaccount:app:app-runner
Ответ yes подтверждает наличие подходящего разрешения для конкретной проверки. Ответ no означает, что нужно искать binding или исправлять verb, resource, API group и namespace. Проверка с wildcard полезна для аудита, но не заменяет список точных прав.
Поиск RoleBinding и ClusterRoleBinding
Сначала найдите объекты, которые могут давать разрешение:
kubectl get role,rolebinding -n app
kubectl get clusterrole,clusterrolebinding
kubectl describe rolebinding app-reader -n app
kubectl describe clusterrolebinding app-reader-global
Проверяйте три поля binding:
subjectsдолжен содержать правильное имя пользователя, группу или ServiceAccount;- для ServiceAccount должны совпадать имя и namespace;
roleRefдолжен указывать на нужный Role или ClusterRole.
Role ограничен namespace. ClusterRole может описывать права для кластерных ресурсов и использоваться в namespace через RoleBinding. RoleBinding дает доступ в своем namespace, а ClusterRoleBinding распространяет права на весь кластер согласно правилам роли.
Изменение Role без корректной привязки не меняет фактические права. Не исправляйте любой Forbidden выдачей cluster-admin. Сначала добавьте конкретный verb и ресурс, затем подтвердите результат через kubectl auth can-i. Практические примеры поиска опасных привязок собраны в материале про RBAC в Kubernetes.
Внешние провайдеры аутентификации: OIDC, LDAP и SSO
При OIDC, LDAP или SSO Kubernetes зависит от нескольких систем. Пользователь проходит вход у внешнего провайдера, exec plugin получает credentials, API-сервер проверяет token, а RBAC использует имя пользователя и группы из claims. Ошибка может находиться за пределами узлов Kubernetes.
Истечение сессии и refresh token
Старая SSO-сессия или отозванный refresh token часто проявляются как внезапный отказ у одного пользователя. Повторите штатную авторизацию через exec plugin и проверьте, создается ли новый access token. Очистка локального кэша допустима только по правилам вашей платформы и не должна приводить к публикации token.
Если новый вход не помогает, сравните время отказа с изменением политики IdP, блокировкой учетной записи, сменой пароля, отзывом refresh token и ограничением по группе. Один и тот же kubeconfig может работать у двух пользователей по-разному, если провайдер применяет персональные политики.
Проблемы issuer, audience и групп
issuer идентифицирует провайдера, выпустившего token. audience показывает, для какого сервиса token предназначен. Если API-сервер ожидает другие значения, он отклоняет token даже при корректном логине.
Группы из claims влияют на RBAC только при правильном сопоставлении. Пользователь может пройти проверку личности, но потерять доступ после изменения названия группы, префикса или формата claim. Сверяйте ожидаемого пользователя и группы по audit log или безопасным диагностическим данным провайдера. Полный token не копируйте в тикеты и сообщения.
TLS, DNS и синхронизация времени
Внешний IdP должен быть доступен клиенту или компоненту, который получает credentials. Проверяйте DNS и TLS из той сети, где запускается exec plugin или находится API-сервер:
getent hosts idp.internal
nslookup idp.internal
openssl s_client -connect idp.internal:443 -servername idp.internal </dev/null
date -u
timedatectl status
Расхождение часов между клиентом, API-сервером и IdP ломает проверку полей iat, nbf и exp. Ошибка доверия к CA блокирует TLS до проверки token. При LDAP отдельно изучите доступность сервера каталога, bind account, сертификат и журналы API-сервера или соответствующего authentication proxy.
Пошаговый алгоритм диагностики ошибки аутентификации
Диагностика занимает меньше времени, когда каждый тест проверяет один слой. После изменения повторяйте исходную операцию и фиксируйте результат. Перезапуск всего кластера не заменяет проверку причины.
Диагностика по компонентам: Docker CLI, kubelet, kubectl и API-сервер
- Docker CLI. Проверяйте hostname registry, локальный credential helper, результат
docker loginи загрузку конкретного образа. - Kubelet. Изучайте Events Pod, журналы kubelet и container runtime. Ищите имя Secret, hostname registry и исходный ответ registry.
- kubectl. Сверяйте context, user, endpoint, namespace, exec plugin и срок действия token или сертификата.
- API-сервер. Для отказов RBAC сопоставляйте subject, verb, resource и namespace. Для token и OIDC ищите audit log и server log с учетом политики доступа к журналам.
На worker node полезны команды journalctl -u kubelet и journalctl -u containerd, если кластер использует containerd. Название службы меняется при использовании другого runtime. Логи могут содержать hostname, имя образа и код ответа, но не должны включать секреты.
Минимальный набор команд для проверки
kubectl config current-context
kubectl get pod private-app -n app -o wide
kubectl describe pod private-app -n app
kubectl get events -n app --sort-by=.lastTimestamp
kubectl get secret regcred -n app -o jsonpath='{.type}'
kubectl get sa app-runner -n app -o yaml
kubectl auth can-i get pods -n app
docker pull registry.example.com/team/app:1.4.2
Для Pod, который не запускается, первые четыре команды показывают состояние, события и причину ImagePullBackOff. Проверка Secret подтверждает только наличие ресурса и тип. Право загрузки образа дополнительно нужно проверить через docker pull с той же учетной записью и, по возможности, с узла кластера.
Не добавляйте в диагностический набор команды, которые печатают token, client key или декодированный .dockerconfigjson. Перед отправкой вывода удаляйте значения credentials, внутренние адреса, имена пользователей и идентификаторы кластеров, если они относятся к защищенной инфраструктуре.
Как проверить исправление
- Повторите исходную операцию с тем же пользователем, context, namespace, образом и действием.
- Для registry проверьте новый
docker pullили состояние Pod. Для API повторите исходную командуkubectl. Для RBAC снова выполнитеkubectl auth can-i. - Убедитесь, что в Events не появляются новые ошибки
401,403,x509илиImagePullBackOff. - Проверьте журналы kubelet, API-сервера, registry и внешнего IdP за время повторной попытки.
- Сохраните обезличенные команды и результаты, которые объясняют исправление. Секреты и полные token в отчет не включайте.
Если после изменения Pod запустился только после ручного перезапуска, проверьте, применилось ли изменение к шаблону Deployment и был ли создан новый Pod с нужным ServiceAccount. Временный restart скрывает проблему с конфигурацией и не подтверждает корректность следующего выката.
Профилактика повторных ошибок аутентификации
Повторные отказы обычно связаны с неуправляемым сроком жизни credentials, широкими правами и отсутствием проверки перед выкатыванием. Эти риски закрываются контролем доступа, ротацией и наблюдаемостью.
Минимальные привилегии и разделение доступов
Разделяйте права на загрузку образов, чтение ресурсов и административные операции. ServiceAccount приложения должен получать доступ к registry через отдельный Secret. Правила RBAC выдавайте на конкретные ресурсы и verbs, когда задача не требует широкого набора.
CI/CD-процессу часто нужен доступ к Deployment, Pod и ConfigMap в одном namespace. Это не означает, что ему нужен доступ к Secret во всех namespace или роль cluster-admin. Проверяйте реальные действия пайплайна через kubectl auth can-i и удаляйте временные привязки после завершения работ.
Для регулярной проверки конфигурации используйте аудит безопасности контейнеров и Kubernetes-кластера. Он помогает найти избыточные права, небезопасные настройки registry и открытые точки доступа.
Ротация Secret, токенов и сертификатов
Зафиксируйте владельца и срок действия каждого credential: registry token, ServiceAccount token, client certificate, refresh token и CA certificate. Настройте предупреждения до истечения срока, а замену проводите с перекрытием, чтобы старый и новый credential не менялись одновременно во время выката.
Храните Secret в защищенном хранилище и исключайте их из Git, Docker image, shell history и открытых CI-логов. После утечки отзывайте token, выпускайте новый и проверяйте все места, где он был подключен. Одного удаления строки из манифеста недостаточно, если значение уже попало в журнал или историю коммитов.
Для тестовых и рабочих кластеров можно использовать управляемую облачную инфраструктуру с Kubernetes, например Timeweb Cloud. При таком выборе все равно нужно отдельно контролировать kubeconfig, RBAC, Secret и политики доступа registry: платформа не исправляет ошибки манифестов приложения.
Проверки в CI/CD и observability
До выката проверяйте существование образа, доступ CI-учетной записи к нужному repository, корректность namespace и наличие ссылок на Secret. Для Kubernetes добавьте проверку context, endpoint и минимального набора действий через kubectl auth can-i.
В мониторинге выделяйте события 401, 403, ImagePullBackOff, истечение сертификатов и ошибки внешнего IdP. Уведомление должно содержать компонент, namespace, имя образа или ресурс RBAC, но не token и содержимое Secret.
Документируйте context, способ получения credentials, container runtime, тип registry и версию Kubernetes. При обновлении кластера повторяйте проверки, потому что поведение exec plugin, admission-механизмов, ServiceAccount и container runtime зависит от версии и конфигурации платформы.
Для системной проверки Kubernetes-доступов и типичных ошибок пригодится шпаргалка по ошибкам Kubernetes в production. Она помогает сопоставить отказ аутентификации с проблемами RBAC, Secret, сетевой политики и настроек control plane.
Рабочий порядок остается неизменным: зафиксируйте ошибку, определите компонент, проверьте endpoint и credentials, сверяйте namespace и ServiceAccount, затем проверяйте RBAC и логи. После исправления повторите исходный тест и сохраните результат без секретных данных.