Выберите продукт

Debian/Ubuntu: как исправить x509: certificate signed by unknown authority в Docker, containerd и kubelet

Если Docker, containerd или kubelet на Debian/Ubuntu не могут скачать образ из registry и отвечают x509: certificate signed by unknown authority, причина обычно связана с CA, trust store, цепочкой сертификатов или именем хоста. Ниже — практическая диагностика и исправление по шагам.
Debian/Ubuntu: как исправить x509: certificate signed by unknown authority в Docker, containerd и kubelet

Ошибка x509: certificate signed by unknown authority встречается в трёх очень похожих сценариях: docker pull не может скачать образ, containerd не доверяет registry, а kubelet уводит Pod в ImagePullBackOff или ErrImagePull. Снаружи это выглядит одинаково, но точка исправления может быть разной: системное хранилище сертификатов Debian/Ubuntu, настройки рантайма, конфиг registry, неполная цепочка сертификатов или несовпадение имени хоста.

Главная идея простая: контейнерный рантайм должен доверять корневому или промежуточному центру сертификации, который подписал сертификат вашего registry. Если этого доверия нет, TLS-рукопожатие не проходит, и вы видите ошибку в Docker, containerd или kubelet.

На Debian и Ubuntu это обычно упирается в два слоя. Первый — системные CA в /usr/local/share/ca-certificates/ и /etc/ssl/certs/, которые обновляются командой update-ca-certificates. Второй — специфические настройки клиента: каталог /etc/docker/certs.d/ для Docker или файл hosts.toml для containerd.

Отдельно важно понимать, что проблема с pull образа в Kubernetes почти никогда не чинится только на control plane. Образы тянет конкретная нода, а значит сертификат, доверенная CA и DNS должны быть исправны именно на ней.

Если registry открывается в браузере или через curl с ноутбука, это ещё не доказывает, что всё в порядке на сервере или worker-ноде. Проверяйте там, где реально выполняется pull.

Как понять, где именно ломается доверие

Прежде чем копировать сертификаты по каталогам, полезно локализовать проблему. Частая ошибка — сразу менять конфиг Docker, хотя на самом деле registry отдаёт не тот сертификат, отсутствует intermediate CA или имя в SAN не совпадает с адресом подключения.

Начните с проверки TLS-ответа самого registry. На Debian/Ubuntu для этого удобнее всего использовать openssl s_client.

openssl s_client -connect registry.example.internal:443 -servername registry.example.internal -showcerts

Смотрите сразу на несколько вещей:

  • совпадает ли имя в -servername с тем именем, которое использует клиент;
  • есть ли полная цепочка сертификатов, а не только leaf-сертификат;
  • нет ли ошибок Verify return code с неизвестным issuer;
  • не идёт ли подключение по IP, когда сертификат выписан только на DNS-имя.

Затем проверьте, доверяет ли системе сам CA. Если у вас внутренний registry с собственным удостоверяющим центром, на чистой Ubuntu он почти наверняка не будет доверенным по умолчанию.

openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt server.crt

Если проверка падает, проблема ещё не в Docker и не в Kubernetes. Сначала нужно починить доверие на уровне ОС.

Что означает ошибка для Docker, containerd и kubelet

Хотя текст ошибки похож, компоненты ведут себя немного по-разному.

Docker

Docker обычно использует системное хранилище сертификатов, но для конкретного registry умеет читать отдельные CA-файлы из /etc/docker/certs.d/ИМЯ_РЕГИСТРИ/. Это удобно, если вы не хотите добавлять внутренний CA глобально для всей системы.

docker pull registry.example.internal/project/app:latest

В ответ обычно видно x509 certificate signed by unknown authority или tls: failed to verify certificate.

containerd

В случае с containerd многое зависит от версии и схемы настройки. В современных конфигурациях чаще используют каталог /etc/containerd/certs.d/ и файл hosts.toml для каждого registry. Если на хосте установлен Kubernetes, именно этот слой часто оказывается реальной причиной проблемы, даже если Docker на той же машине уже умеет тянуть образы.

kubelet

kubelet сам не реализует TLS-клиент к registry, а пользуется контейнерным рантаймом через CRI. То есть если ваш кластер работает на containerd, лечить нужно доверие и конфиг именно у containerd на каждой ноде.

kubectl describe pod my-pod -n my-namespace
journalctl -u kubelet -n 200 --no-pager
journalctl -u containerd -n 200 --no-pager

Если вы разворачиваете registry или CI-раннеры на отдельном сервере, под такие задачи обычно удобнее брать VDS, где есть полный контроль над trust store, DNS и TLS-настройками рантайма.

Базовый путь на Debian/Ubuntu: добавить CA в системное хранилище

Если private registry использует внутренний CA, самый чистый путь на Debian/Ubuntu — установить корневой или промежуточный сертификат УЦ в системный trust store.

Скопируйте CA-сертификат в каталог локальных сертификатов. Обычно это PEM-файл с расширением .crt.

sudo cp company-root-ca.crt /usr/local/share/ca-certificates/company-root-ca.crt

Затем обновите системное хранилище:

sudo update-ca-certificates

После этого перезапустите сервисы, которые могли закешировать старое состояние trust store.

sudo systemctl restart docker
sudo systemctl restart containerd
sudo systemctl restart kubelet

Дальше снова проверьте pull именно тем инструментом, который реально используется в вашей схеме.

docker pull registry.example.internal/project/app:latest
ctr -n k8s.io images pull registry.example.internal/project/app:latest

Если ошибка ушла, значит проблема была именно в отсутствии доверенного CA на уровне ОС.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

На этом этапе уже стоит проверить одинаковое состояние всех worker-нод: одна исправленная машина не решает проблему для всего кластера.

Проверка цепочки сертификатов registry через openssl на сервере Linux

Когда системного trust store недостаточно: Docker certs.d

Иногда вы не хотите добавлять внутренний CA во всю систему. Например, это тестовый стенд, отдельный registry или временная интеграция. Тогда Docker можно настроить точечно.

Создайте каталог по имени registry. Если используется нестандартный порт, он тоже входит в имя каталога.

sudo mkdir -p /etc/docker/certs.d/registry.example.internal
sudo cp company-root-ca.crt /etc/docker/certs.d/registry.example.internal/ca.crt

Если registry работает на порту 5000, каталог должен называться так:

sudo mkdir -p /etc/docker/certs.d/registry.example.internal:5000
sudo systemctl restart docker

Это особенно полезно, когда проблема локализуется именно в Docker. Но такой способ не обязательно поможет containerd. На Kubernetes-хостах полезно также держать под рукой материал про сетевую часть рантайма и фильтрацию трафика: как Docker работает с iptables и nftables.

Настройка containerd для private registry с собственным CA

Для containerd на Debian/Ubuntu удобнее использовать структуру /etc/containerd/certs.d/. На практике она предсказуемее, чем попытки собрать всё в один большой config.toml.

Создайте каталог registry и положите туда CA-сертификат.

sudo mkdir -p /etc/containerd/certs.d/registry.example.internal
sudo cp company-root-ca.crt /etc/containerd/certs.d/registry.example.internal/ca.crt

Затем создайте hosts.toml:

[host."https://registry.example.internal"]
  capabilities = ["pull", "resolve", "push"]
  ca = "/etc/containerd/certs.d/registry.example.internal/ca.crt"

Если используется нестандартный порт, каталог и адрес в файле должны совпадать с фактическим endpoint:

sudo mkdir -p /etc/containerd/certs.d/registry.example.internal:5000
[host."https://registry.example.internal:5000"]
  capabilities = ["pull", "resolve", "push"]
  ca = "/etc/containerd/certs.d/registry.example.internal:5000/ca.crt"

После этого перезапустите containerd:

sudo systemctl restart containerd

И проверьте pull напрямую через ctr или crictl.

sudo ctr -n k8s.io images pull registry.example.internal/project/app:latest
sudo crictl pull registry.example.internal/project/app:latest

Если на этом этапе команда отрабатывает, а Pod всё ещё не стартует, проблема уже не в TLS, а, например, в аутентификации, imagePullSecrets или сетевой доступности registry.

Частая причина: у сервера неполная цепочка сертификатов

Очень типичная ситуация: администратор добавил корневой CA в Debian/Ubuntu, но ошибка не исчезла. Причина в том, что сам registry отдаёт только leaf-сертификат без intermediate CA. Некоторые клиенты это переживают, другие — нет.

Проверяйте не только наличие доверенного корня, но и то, что сервер реально отдаёт полный bundle. Для reverse proxy и registry это означает, что в конфиге должен использоваться файл полной цепочки, а не только сертификат сайта.

  • openssl s_client показывает неполный chain;
  • браузер открывает registry, а CLI-клиент ругается;
  • на части нод pull проходит, а на части — нет;
  • ошибка появилась после перевыпуска сертификата или смены CA.

Если вам нужен публично доверенный сертификат для registry, панели или обратного прокси, проще сразу использовать нормальные SSL-сертификаты, чем потом ловить ошибки с цепочкой и доверием на клиентах.

Проверка имени хоста и SAN: проблема не всегда в CA

Ещё один неприятный сценарий: текст ошибки наводит на мысль о недоверенном CA, но реальная причина — образ тянется по адресу, который не совпадает с именем в сертификате. Например, сертификат выписан на registry.example.internal, а клиент подключается по IP-адресу или по другому DNS-имени.

Проверьте:

  • какой reference используется в docker pull или в манифесте Pod;
  • что находится в SAN сертификата сервера;
  • не делает ли внутренний DNS неожиданный CNAME на другой endpoint;
  • не указывает ли /etc/hosts на старый IP с другим сертификатом.

Для Kubernetes это особенно важно, когда часть нод резолвит имя registry иначе из-за разного DNS-конфига, split-horizon или устаревшего кэша.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Даже при корректно установленном CA ошибка будет повторяться, если имя в сертификате не соответствует адресу подключения.

Диагностика ошибки загрузки образа на Kubernetes-ноде через containerd и kubelet

Как диагностировать проблему на Kubernetes-ноде без догадок

Если у вас ошибка загрузки образа на ноде, проходите проверку в фиксированном порядке. Это экономит много времени.

  1. На проблемной ноде проверьте DNS-резолвинг имени registry.
  2. Проверьте TLS-ответ через openssl s_client.
  3. Проверьте наличие CA в системном trust store.
  4. Проверьте настройки containerd для конкретного registry.
  5. Проверьте pull через crictl или ctr.
  6. Только потом разбирайте imagePullSecrets и авторизацию.

Минимальный набор команд на ноде:

getent hosts registry.example.internal
openssl s_client -connect registry.example.internal:443 -servername registry.example.internal -showcerts
ls -l /usr/local/share/ca-certificates
ls -l /etc/containerd/certs.d/registry.example.internal
sudo crictl pull registry.example.internal/project/app:latest
journalctl -u containerd -n 200 --no-pager

Если crictl pull проходит, а Pod по-прежнему не стартует, смотрите события Pod и секреты авторизации. Если crictl pull падает с тем же x509, лечить надо ноду, а не Deployment.

Чего не стоит делать в продакшене

В интернете часто советуют «быстрое решение» — отключить проверку TLS или объявить registry insecure. Технически это может сработать, но в продакшене такой подход создаёт лишние риски и почти всегда становится источником будущих проблем.

  • не включайте insecure registry вместо нормальной установки CA;
  • не копируйте leaf-сертификат сервера как CA;
  • не исправляйте проблему только на одной ноде кластера;
  • не проверяйте pull только со своей рабочей станции;
  • не игнорируйте неполную цепочку на стороне registry.

Если у вас внутренний registry, правильное решение почти всегда одно: корректная цепочка сертификатов на сервере и штатно установленный доверенный CA на всех клиентах, которые выполняют pull.

Если сертификат публичный, а ошибка всё равно есть

Бывает и обратная история: registry использует сертификат от публичного УЦ, но Debian/Ubuntu всё равно жалуется на неизвестный authority. Тогда проверьте несколько базовых вещей.

  • система давно не обновлялась, и набор доверенных корней устарел;
  • пакет ca-certificates повреждён или удалён;
  • на минимальном образе ОС trust store установлен не полностью;
  • дата и время на ноде неверны;
  • прокси или middlebox подменяет сертификат своим корпоративным CA.

Для начала проверьте пакет и обновите его:

dpkg -l ca-certificates
sudo apt update
sudo apt install --reinstall ca-certificates
sudo update-ca-certificates
timedatectl status

Если в инфраструктуре есть TLS inspection, то фактически перед вами уже не публичный сертификат registry, а сертификат, переподписанный внутренним CA компании. Значит, его корень тоже нужно добавлять в доверенные.

Итог

Ошибка x509: certificate signed by unknown authority в Docker, containerd и kubelet почти никогда не является «магической проблемой Kubernetes». В большинстве случаев это история про доверенный CA, полную цепочку сертификатов или несовпадение имени хоста.

На Debian/Ubuntu базовая точка входа — системное хранилище сертификатов и команда update-ca-certificates. Дальше, в зависимости от стека, добавляется точечная настройка Docker или containerd.

Если запомнить один принцип, то он такой: сначала проверяйте TLS на самой ноде, затем доверие ОС, потом настройки рантайма, и только после этого переходите к Kubernetes-объектам. Такой порядок обычно экономит часы диагностики.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: nftables sets с timeout и interval для динамических списков IP OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: nftables sets с timeout и interval для динамических списков IP

Показываю, как в Debian и Ubuntu применять nftables sets для больших списков IP, временных банов и диапазонов адресов. Разберём ti ...
Debian и Ubuntu: как работает cloud-init на first boot, где искать datasource, cache и почему не применяется user-data OpenAI Статья написана AI (GPT 5)

Debian и Ubuntu: как работает cloud-init на first boot, где искать datasource, cache и почему не применяется user-data

Разбираем, почему в Debian и Ubuntu cloud-init не применяет user-data, как определяется datasource, что хранится в /var/lib/cloud ...
Debian/Ubuntu: как исправить stale file handle в NFS OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить stale file handle в NFS

Ошибка stale file handle в NFS на Debian и Ubuntu обычно появляется после перезагрузки сервера, failover, отката snapshot или пере ...