Помилки TLS приватного реєстру Docker: правильно виправляємо ланцюги сертифікатів

Було корисно?

Ви розгорнули приватний реєстр Docker. Він працює у вас. Він працює на одному CI-ранері. Потім у кластер приєднується новий вузол і раптом: x509: certificate signed by unknown authority. Люди починають «виправляти» це, вмикаючи insecure-registries, бо вже 2 ранку і сигналізація гучна.

Не робіть так. Помилки TLS навколо реєстрів — це одна з тих проблем, де правильне рішення нудне, повторюване та набагато дешевше, ніж героїчний хаґ. Неправильне рішення швидке, крихке і повертається, як поганий сіквел — зазвичай під час замороження розгортання.

Що насправді означають помилки TLS реєстру Docker

Більшість «помилок TLS реєстру Docker» не є проблемами Docker. Це звичайні відмови валідації TLS, які проявляються через стек клієнта Docker (TLS-бібліотека Go), демон і іноді containerd. Ваш реєстр — це просто HTTPS-сервер зі своїми уподобаннями.

Коли ви запускаєте:

  • docker login registry.example.com
  • docker pull registry.example.com/team/app:tag
  • kubectl apply і вузли починають тягнути образи

…клієнт очікує, що сервер представить сертифікат, який:

  1. Відповідає імені хоста, яке ви використали (Subject Alternative Name, а не лише CN).
  2. Наразі дійсний (не прострочений і в межах NotBefore/NotAfter).
  3. Ланцюжиться до довіреного кореня CA на машині, яка виконує pull.
  4. Містить потрібні проміжні сертифікати (або може завантажити їх через AIA, що ненадійно в мережах з обмеженим доступом).
  5. Використовує допустимі розміри ключів та алгоритми підпису.

Помилки Docker часто короткі й без романтики, наприклад:

  • x509: certificate signed by unknown authority
  • x509: certificate is valid for ..., not registry.example.com
  • remote error: tls: bad certificate
  • tls: handshake failure

Кожна з них відображає певний режим відмови. Ви можете діагностувати це детерміністично. Вам не потрібно «пробувати різні варіанти» у продакшені.

Жарт №1: TLS — як швейцар: якщо ваш ланцюг довіри виглядає підробленим, вас не пустять до клубу, як би голосно ви не кричали, що «ви в списку».

Факти та контекст для постмортему

Трохи фону корисно, бо відмови TLS часто виникають через історію — старі значення за замовчуванням, старі звички, застарілу інфраструктуру.

  1. Docker давно перемістив рішення про довіру до демона. Демон виконує pull, тож його сховище довіри важить більше, ніж ваше shell-середовище.
  2. Subject Alternative Name замінив перевірку CN кілька років тому. Сучасні клієнти ігнорують старий Common Name для перевірки імені хоста; SAN є обов’язковим.
  3. Проміжні CA стали звичними, бо корені жорстко контрольовані. Багато публічних і приватних PKI випускають кінцеві сертифікати через проміжні, а не напряму від коренів.
  4. AIA-завантаження реальне, але не гарантоване. Деякі TLS-стеки можуть завантажувати відсутні проміжні через Authority Information Access, але поведінка Docker залежить від оточення та доступу в мережі.
  5. Let’s Encrypt змінював поведінку ланцюгів з часом. Вибір ланцюга та ротація проміжних спричиняли сюрпризи «вчора працювало», коли сервер починав віддавати неправильний ланцюг.
  6. Старі клієнти відмовляються від нових алгоритмів і навпаки. Реєстр з лише ECDSA-сертифікатами може зламати старі збірки OpenSSL; RSA‑лише сумісніші, але повільніші.
  7. Корпоративна TLS-інспекція порушує припущення. Прозорі проксі, що підписують сертифікати заново, роблять ваше внутрішнє сховище довіри залежністю, хочете ви того чи ні.
  8. Ранери контейнерів еволюціонували. На багатьох системах Docker використовує containerd під капотом; Kubernetes може використовувати containerd напряму. Шляхи до сховищ довіри й поведінка перезавантаження відрізняються.
  9. «Insecure registries» призначалися для розробки, не для продакшену. Це вимикає критичну валідацію. Це не «тимчасове виправлення»; це політичне рішення з боргом безпеки.

Одна операційна цитата, щоб тримати себе в порядку: «Надія — не стратегія.» — генерал Гордон Р. Салліван. Вона болісно точно підходить для ланцюгів сертифікатів.

Швидкий план діагностики

Якщо ви на чергуванні, вам не потрібна лекція. Потрібен швидкий шлях від симптому до корінної причини.

Перше: підтвердьте, до якої кінцевої точки насправді підключається клієнт

  • Чи це registry.example.com чи ім’я балансувальника навантаження?
  • Чи ви використовуєте порт, наприклад :5000?
  • Чи є проксі або MITM TLS-інспекція?

Якщо ім’я хоста відрізняється від того, що покриває сертифікат, це вирішено: виправте DNS або SAN.

Друге: подивіться, що сервер насправді представляє (ланцюг + SAN)

Використовуйте openssl s_client проти кінцевої точки реєстру з проблемного вузла. Не дивіться з вашого ноутбука і не думайте, що шлях той самий.

Якщо сервер віддає лише leaf-сертифікат (без проміжних), виправляйте конфігурацію сервера. Не «вчіть кожен вузол» недостаючим проміжним сертифікатам, якщо реєстр налаштований неправильно.

Третє: визначте, де відсутня довіра

  • Якщо curl падає і Docker падає: сховище довіри машини не має CA або ланцюг неправильний.
  • Якщо curl проходить, а Docker падає: конфігурація довіри демона Docker відрізняється, або ви використовуєте containerd з власними налаштуваннями довіри.
  • Якщо тільки Kubernetes-пуллінги падають: довіра рантайму вузла відрізняється від вашого інтерактивного шелу.

Четверте: перевірте час, бо час руйнує все

Зсув часу робить дійсні сертифікати недійсними. Відмови NTP викликають «випадкові помилки TLS», які виглядають як проблеми PKI.

П’яте: утримуйтесь від «insecure-registries», якщо ви явно не приймаєте ризик

Це забезпечить зелені збірки. Але воно також нормалізує обходи валідації, через що ви ризикуєте відправити облікові дані не туди, де треба, пізніше.

Ментальна модель ланцюга сертифікатів (щоб ви припинили гадати)

Ланцюг TLS-сертифікатів — це історія, яку сервер розповідає клієнту: «Я — registry.example.com, і ось чому ви можете мені вірити.» У історії є персонажі:

  • Leaf-сертифікат: виданий для імен вашого реєстру. Це те, ким «є» ваш сервер.
  • Проміжний(і) сертифікат(и): CA, що видала leaf. Вони з’єднують leaf з коренем.
  • Кореневий сертифікат: точка довіри. Це те, чому клієнт уже довіряє.

Клієнти зазвичай довіряють кореням, а не проміжним. Проміжні зазвичай не потрапляють у системне сховище довіри, якщо їх не додали постачальники CA. Саме тому сервери часто мають надсилати проміжні сертифікати.

Що означає «виправити ланцюг» насправді

Це означає: кінцева точка вашого реєстру має подавати leaf-сертифікат та всі необхідні проміжні сертифікати у правильному порядку, а клієнт має мати довірений корінь (root), що підтверджує цей ланцюг.

На типовому вебсервері це різниця між подачею:

  • Неправильно: cert.pem (лише leaf)
  • Правильно: fullchain.pem (leaf + проміжні)

Також: ваш приватний root CA має бути встановлений на кожному вузлі, що буде тягнути образи, включно з тимчасовими CI-ранерами та автоскейленими Kubernetes-вузлами. Якщо ви випускаєте сертифікати від приватного кореня, який не в системній довірі, нічого іншого не допоможе.

Особливість Docker: місце зберігання довіри й поведінка перезавантаження

Docker не автоматично поглинає будь-які сертифікати, які ви встановлюєте в ОС. Демон використовує системну довіру на багатьох дистрибутивах, але Docker також підтримує індивідуальні бандли довіри для реєстрів у:

  • /etc/docker/certs.d/registry.example.com:5000/ca.crt

І containerd має свої конфігураційні ручки в залежності від дистрибутива та Kubernetes-дистрибуції. Перекладаючи: потрібно знати, який рантайм виконує pull і звідки він читає CA.

Практичні завдання: команди, виводи, рішення (12+)

Ось завдання, які я насправді виконую, коли падають pulls з реєстру. Кожне містить команду, що типовий вивід означає і рішення, яке ви приймаєте. Запускайте їх із машини, що падає (вузол, раннер, агент збірки), а не з машини, якою ви хотіли б, щоб вона падала.

Завдання 1: Підтвердіть точний host:port реєстру, який використовує Docker

cr0x@server:~$ docker image pull registry.example.com:5000/team/app:1.2.3
Error response from daemon: Get "https://registry.example.com:5000/v2/": x509: certificate signed by unknown authority

Що це означає: Docker використовує https://registry.example.com:5000 і терпить невдачу під час перевірки довіри.

Рішення: Усі наступні перевірки мають бути націлені на registry.example.com:5000, включно з перевіркою SAN і шляхом до бандла довіри в certs.d.

Завдання 2: Перевірте базовий DNS та маршрутизацію (так, правда)

cr0x@server:~$ getent hosts registry.example.com
10.20.30.40   registry.example.com

Що це означає: Ім’я резолвиться у 10.20.30.40.

Рішення: Якщо це різниться між вузлами (split-horizon DNS), ви можете натрапляти на різні балансувальники з різними сертифікатами.

Завдання 3: Проінспектуйте ланцюг сертифікатів та SAN, які подає сервер

cr0x@server:~$ echo | openssl s_client -connect registry.example.com:5000 -servername registry.example.com -showcerts 2>/dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
subject=CN = registry.example.com
issuer=CN = Corp Issuing CA 01
notBefore=Dec  1 00:00:00 2025 GMT
notAfter=Dec  1 23:59:59 2026 GMT
X509v3 Subject Alternative Name:
    DNS:registry.example.com, DNS:registry

Що це означає: Leaf-сертифікат покриває registry.example.com; добре. Issuer — проміжний («Corp Issuing CA 01»).

Рішення: Якщо SAN не містить точного імені, яке використовують клієнти, перевипустіть сертифікат. Не покладайтеся на CN. Якщо дати неправильні — виправляйте ротацію або час системи.

Завдання 4: Перевірте, чи сервер надсилає проміжні сертифікати

cr0x@server:~$ echo | openssl s_client -connect registry.example.com:5000 -servername registry.example.com -showcerts 2>/dev/null | awk '/BEGIN CERTIFICATE/{i++} END{print i}'
1

Що це означає: Надсилається лише один сертифікат (лише leaf). Це класична неправильна конфігурація, якщо клієнти не мають проміжного в локальному сховищі.

Рішення: Виправте TLS-конфігурацію реєстру, щоб подавати повний ланцюг (leaf + проміжні). Зазвичай це саме правильне місце для виправлення.

Завдання 5: Перевірте ланцюг локально з конкретним бандлом CA

cr0x@server:~$ openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /tmp/registry-leaf.pem
CN = registry.example.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error /tmp/registry-leaf.pem: verification failed

Що це означає: Системне сховище довіри не може побудувати ланцюг від leaf до довіреного кореня (відсутній проміжний і/або корінь).

Рішення: Або встановіть правильний корпоративний root CA в системне сховище довіри, або виправте сервер, щоб він подавав проміжні (або і те, і інше, залежно від дизайну PKI).

Завдання 6: Перевірте, чи ОС знає ваш корпоративний корінь

cr0x@server:~$ sudo grep -R --line-number "Corp Root CA" /etc/ssl/certs 2>/dev/null | head
/etc/ssl/certs/Corp_Root_CA.pem:1:-----BEGIN CERTIFICATE-----

Що це означає: Корпоративний корінь присутній у системному каталозі сертифікатів (принаймні на цьому хості).

Рішення: Якщо він присутній, але верифікація все одно падає — ви не маєте проміжних на сервері або ланцюг не веде до цього кореня.

Завдання 7: Протестуйте curl, щоб ізолювати «Docker vs система»

cr0x@server:~$ curl -vkI https://registry.example.com:5000/v2/
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
curl: (60) SSL certificate problem: unable to get local issuer certificate

Що це означає: Це не особливість Docker; хост сам не може валідувати ланцюг сервера.

Рішення: Виправляйте ланцюг/довіру спочатку. Не чіпайте конфігурацію Docker поки що.

Завдання 8: Підтвердіть, що демон Docker бачить будь-який per-registry CA-бандл

cr0x@server:~$ ls -la /etc/docker/certs.d/registry.example.com:5000/
total 12
drwxr-xr-x 2 root root 4096 Jan  3 09:12 .
drwxr-xr-x 3 root root 4096 Jan  3 09:12 ..
-rw-r--r-- 1 root root 1984 Jan  3 09:12 ca.crt

Що це означає: Docker має файл CA для цього реєстру.

Рішення: Якщо цього файлу немає на вузлах, що падають, встановіть його (або ще краще — виправте серверний ланцюг і розповсюдьте лише ваш root CA через стандартне управління системною довірою).

Завдання 9: Перезапустіть Docker після зміни довіри (бо він не читає ваші думки)

cr0x@server:~$ sudo systemctl restart docker
cr0x@server:~$ sudo systemctl is-active docker
active

Що це означає: Docker перезапустився коректно.

Рішення: Якщо перезапуск провалюється, вирішіть проблеми конфігурації демона перед повторним тестом. Зміни довіри, які не завантажено, не рахуються.

Завдання 10: Перегляньте конфігурацію демона Docker на предмет небезпечних коротких шляхів

cr0x@server:~$ cat /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "insecure-registries": ["registry.example.com:5000"]
}

Що це означає: Хтось вимкнув перевірку TLS для цього реєстру.

Рішення: Видаліть це після того, як правильний TLS буде налагоджено. Якщо ви його залишите, ви приймаєте ризик MITM для всіх pulls з цього кінцевого пункту.

Завдання 11: Перевірте, який файл сертифіката реально слугує вашій кінцевій точці реєстру (приклад Nginx)

cr0x@server:~$ sudo nginx -T 2>/dev/null | grep -n "ssl_certificate"
57:    ssl_certificate     /etc/nginx/certs/registry.crt;
58:    ssl_certificate_key /etc/nginx/certs/registry.key;

Що це означає: Nginx подає registry.crt. Це може бути лише leaf.

Рішення: Переконайтеся, що ssl_certificate вказує на PEM з повним ланцюгом (leaf + проміжні). Потім перезавантажте Nginx.

Завдання 12: Підтвердіть, що PEM-файл справді містить повний ланцюг

cr0x@server:~$ awk '/BEGIN CERTIFICATE/{i++} END{print i}' /etc/nginx/certs/registry.crt
2

Що це означає: Два сертифікати в PEM (ймовірно leaf + проміжний). Зазвичай це те, що потрібно.

Рішення: Якщо виводить 1, ви, ймовірно, подаєте лише leaf. Виправте файл і перезавантажте сервер.

Завдання 13: Безпечно перезавантажте фронтенд реєстру (Nginx)

cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
cr0x@server:~$ sudo systemctl reload nginx
cr0x@server:~$ sudo systemctl is-active nginx
active

Що це означає: Конфігурація валідна і перезавантаження виконано. Існуючі з’єднання повинні залишитися; нові TLS-хендшейки використовуватимуть нові сертифікати.

Рішення: Під час бізнес-годин надавайте перевагу reload перед повним restart.

Завдання 14: Повторно перевірте презентацію ланцюга після зміни сервера

cr0x@server:~$ echo | openssl s_client -connect registry.example.com:5000 -servername registry.example.com -showcerts 2>/dev/null | awk '/BEGIN CERTIFICATE/{i++} END{print i}'
2

Що це означає: Сервер тепер надсилає більше, ніж лише leaf-сертифікат.

Рішення: Повторно протестуйте curl, а потім docker pull. Якщо все ще падає — можливо, відсутня довірена точка (trust anchor).

Завдання 15: Перевірте через curl знову (тепер має проходити)

cr0x@server:~$ curl -sSI https://registry.example.com:5000/v2/ | head -n 5
HTTP/1.1 401 Unauthorized
Server: nginx
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="https://registry.example.com:5000/token",service="registry.example.com:5000"
Date: Fri, 03 Jan 2026 09:27:31 GMT

Що це означає: TLS пройшов; тепер HTTP-аутентифікація — «проблема», що є нормальним. Реєстр очікує облікові дані.

Рішення: Перейдіть до тестів docker login/pull. Ваш шар TLS тепер у порядку.

Завдання 16: Підтвердіть, що Docker тепер може спілкуватися по TLS з /v2/

cr0x@server:~$ docker login registry.example.com:5000
Username: cr0x
Password:
Login Succeeded

Що це означає: Перевірка TLS і аутентифікація пройшли.

Рішення: Розгорніть те саме виправлення на всіх вузлах/ранерах. Потім видаліть будь-які налаштування insecure registry.

Завдання 17: Перевірте час вузла, якщо дати сертифіката виглядають неправильно

cr0x@server:~$ timedatectl status | sed -n '1,8p'
Local time: Fri 2026-01-03 09:28:02 UTC
Universal time: Fri 2026-01-03 09:28:02 UTC
RTC time: Fri 2026-01-03 09:28:03
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active

Що це означає: Годинник синхронізований.

Рішення: Якщо синхронізації немає — виправте NTP перед тим, як звинувачувати PKI. Повторні або ще не дійсні помилки часто походять від зсуву часу.

Три корпоративні історії з передової

1) Інцидент, викликаний хибним припущенням: «Балансувальник навантаження обробляє ланцюг»

Середня компанія тримала приватний реєстр за layer‑7 балансувальником. Команда платформи ротаціоновала сертифікати щоквартально. Вони припустили, що балансувальник подає повний ланцюг, бо браузери були задоволені. Браузери, звісно, поблажливі: вони кешують проміжні, завантажують через AIA і «просто працюють», поки не перестануть.

Потім вони додали нові Linux‑воркери в пул автоскейлінгу. Свіжі машини, мінімальний базовий образ, заблокований egress. Ці вузли не могли завантажити проміжні з інтернету, і в них не було проміжних у кеші, бо вони були «новонародженими».

Режим відмови був прекрасно повторюваним: кожен новий вузол падав при pull’ах з помилкою x509: certificate signed by unknown authority. Старі вузли продовжували працювати, бо їхні кеші та історична поведінка маскували дефект. Інцидент неправильно інтерпретували як «автоскейл не працює» або «containerd нестабільний». Насправді ланцюг був неповним.

Виправлення було смішно просте: налаштувати балансувальник, щоб він подавав повний ланцюг (leaf + проміжний), і перевірити через openssl s_client з новим вузлом без кешованого стану. Справжній урок: браузер не є тестом відповідності для ваших інфраструктурних клієнтів.

2) Оптимізація, яка обернулася проти: «Ми використовуватимемо лише ECDSA»

Інша організація вирішила модернізувати TLS. Вони згенерували ECDSA‑сертифікати, бо вони швидші та менші, і налаштували інгрес на преференцію сучасних шифрів. На папері все виглядало чудово і це було гарно на слайді для огляду безпеки.

Потім почали падати старі fleet’и збірок. Деякі ранери мали старий стек OpenSSL без підтримки потрібних кривих; кілька пристроїв постачальника робили TLS-термінацію і ре-шифрування з обмеженою підтримкою алгоритмів. Реєстр не «лежав», але став вибірково недоступним.

Перша реакція команди була відкотити. Друга реакція була кращою: зробити dual‑stack стратегію сертифікації — підтримувати RSA і ECDSA де можливо, або щонайменше переконатися, що всі клієнти в межах охоплення можуть узгодити вибрані алгоритми. Також вони навчилися тестувати на фактичному флоті, а не на одному сучасному ноутбуці.

Проблема не в тому, що ECDSA поганий. Проблема — вірити, що «наша інфраструктура» однорідна. Це рідко так.

3) Нудна, але правильна практика, що врятувала день: «Розповсюдження CA як артефакт релізу»

Команда фінтеху використовувала приватний PKI для багатьох внутрішніх сервісів, включно з контейнерним реєстром. У них було правило: корпоративний root CA і потрібні проміжні пакувались і розповсюджувались як будь-яка інша залежність — версіоновані, з чексумацією і розгорнуті через інструмент конфігураційного менеджменту.

Коли вони ротаціоновали проміжний CA (планово, анонсовано, прогнано), вони оновили «bандл довіри» спершу. Вузли отримали його поступово. Лише після того, як флот підтвердив відповідність, вони почали випускати нові leaf‑сертифікати для кінцевих точок, таких як реєстр.

День ротації пройшов без пригод. Декілька відсталих машин впали при pull’ах — передбачувано це були unmanaged snowflake‑сервери — і їх виправили стандартними інструментами. Нічних інцидентів не було. Жодних екстрених insecure registry налаштувань. Жодної загадки «чому лише один кластер зламався?».

Це було нудно. Нудно — те, що вам потрібно. Жарт №2: Якщо ротація сертифікатів захоплива, ви займаєтеся живим театром, а не операціями.

Поширені помилки: симптом → корінна причина → виправлення

1) Симптом: x509: certificate signed by unknown authority

Корінна причина: Клієнт не може побудувати ланцюг до довіреного кореня. Або корінь CA не встановлено, або сервер не надсилає проміжні, або обидва.

Виправлення: Віддавайте перевагу виправленню презентації ланцюга сервером (serve fullchain). Також переконайтеся, що правильний root CA встановлено в системній довірі та/або в /etc/docker/certs.d/ для цього реєстру.

2) Симптом: x509: certificate is valid for foo, not registry.example.com

Корінна причина: Неправильні SAN. Часто трапляється, коли сертифікат випущений для внутрішнього імені, а клієнти використовують зовнішнє, або коли ім’я балансувальника відрізняється від імені реєстру.

Виправлення: Перевипустіть leaf‑сертифікат з SAN для кожного імені, якими користуються клієнти. Не заклеюйте це DNS‑хакерами, якщо ви не контролюєте всіх клієнтів.

3) Симптом: Працює в браузері, не працює в Docker

Корінна причина: Браузер завантажив проміжні через AIA або має їх у кеші; хост Docker не має. Або довіра демона Docker відрізняється від довіри користувача в ОС.

Виправлення: Перевірте через openssl s_client -showcerts на проблемному вузлі. Подавати повний ланцюг на сервері. Підтвердіть бандл довіри Docker.

4) Симптом: Деякі вузли можуть тягнути, нові — не можуть

Корінна причина: Кешовані проміжні, різні базові образи або непослідовне розповсюдження CA. Автоскейл виявляє дрейф.

Виправлення: Стандартизуйте встановлення CA в образі або під час bootstrap. Тестуйте на свіжому вузлі без попередньої TLS‑історії.

5) Симптом: tls: handshake failure без інших підказок

Корінна причина: Несумісність протоколу/шифрів, проблеми SNI або проксі посередині. Іноді реєстр говорить TLS лише на певному порту, а ви потрапляєте на інший.

Виправлення: Використовуйте openssl s_client з -servername. Підтвердіть версії TLS і шифри на сервері та клієнтах. Виявляйте будь-який перехоплюючий проксі.

6) Симптом: remote error: tls: bad certificate на клієнті

Корінна причина: Сервер відхилив клієнтську частину хендшейку. Це може статися через неправильно налаштований mTLS (потрібні клієнтські сертифікати), або через зламаний серверний ланцюг, який плутає серверний стек.

Виправлення: Перегляньте журнали сервера (nginx, envoy, registry). Підтвердіть, чи потрібні клієнтські сертифікати. Якщо так — налаштуйте Docker/клієнт для mTLS або вимкніть вимогу для кінцевих точок реєстру.

7) Симптом: Pull падає лише в Kubernetes, не на bastion

Корінна причина: Сховище довіри рантайму вузла відсутнє, або вузли використовують containerd напряму і не читають Docker’s certs.d. Або pull йде через внутрішній проксі на вузлах.

Виправлення: Дебаг на самому вузлі. Встановіть CA там, де рантайм очікує. Для containerd використовуйте його механізми конфігурації сертифікатів (залежить від дистрибутива). Не припускайте, що «настройки Docker застосовуються» автоматично.

8) Симптом: Раптово впало після ротації сертифікатів

Корінна причина: Введено новий проміжний, неправильний порядок ланцюга, досі подається прострочений проміжний або leaf випущений від нового CA, якому клієнти ще не довіряють.

Виправлення: Подавайте правильний повний ланцюг. Попередньо розповсюдьте нові корені/проміжні перед ротацією leaf. Валідируйте з чистого клієнта.

Чеклісти / покроковий план

Покроково: виправити ланцюг сертифікатів приватного реєстру (здоровий підхід)

  1. Інвентаризація клієнтів. Перелічіть усі системи, що тягнуть: ноутбуки розробників, CI‑ранери, Kubernetes‑вузли, відрізані билдери, edge‑пристрої.
  2. Визначте точку термінації TLS. Це сам реєстр, Nginx, Envoy/Ingress чи балансувальник?
  3. Підтвердіть імена хостів, які використовують клієнти. Включіть варіанти з портами. Включіть внутрішні DNS‑імена.
  4. Випустіть leaf‑сертифікат з правильними SAN. Не домовляйтеся з реальністю: якщо клієнти використовують три імені — SAN має містити три імені.
  5. Зберіть fullchain PEM. Конкатенуйте leaf потім проміжні (без кореня, якщо платформа явно цього не вимагає; багато платформ не вимагають).
  6. Налаштуйте TLS‑кінцеву точку на подачу fullchain. Nginx/Envoy/Ingress мають подавати проміжні.
  7. Перевірте ланцюг з чистого хоста. Використовуйте openssl s_client -showcerts та curl.
  8. Правильно розповсюдьте точки довіри. Встановіть корпоративний root CA в системну довіру кожного вузла; за потреби додавайте per‑registry CA‑бандли.
  9. Перезавантажте сервіси. Перезавантажте/перезавантажте Nginx/Ingress. Перезапустіть Docker/containerd, якщо потрібно для оновлення довіри.
  10. Приберіть небезпечні обходи. Видаліть записи insecure-registries і будь‑які HTTP‑винятки для реєстру.
  11. Автоматизуйте оновлення і reload. Ротація сертифікатів без автоматизації — це план майбутнього інциденту для вас.
  12. Впровадьте канарку. Періодичний pull з чистої нод‑пули виявляє регресії ланцюга рано.

Операційний чекліст: перед тим як звинувачувати PKI

  • Чи DNS резолвиться в очікуваний IP з проблемного вузла?
  • Чи синхронізований часовий годинник проблемного вузла?
  • Чи за вами стоїть корпоративний TLS‑інспекційний проксі?
  • Чи правильно ви використовуєте SNI (ім’я хоста відповідає -servername)?
  • Чи не було нещодавніх змін у конфігурації балансувальника?

Операційний чекліст: перед тим як погодитися на «insecure registries»

  • Ви довели, що сервер не віддає проміжні?
  • Ви довели, що клієнт не має кореня CA?
  • Ви перевірили, чи SAN сертифіката відповідає імені хоста?
  • Ви задокументували ризик і план відкату?

Якщо ви не можете відповісти на ці питання, ви не приймаєте рішення — ви створюєте безлад.

Поширені запитання (FAQ)

1) Чи потрібно додавати корінь CA у повний файл fullchain на сервері?

Зазвичай ні. Сервери зазвичай віддають leaf + проміжні; клієнти вже мають (або повинні мати) корінь. Відсилання кореня може заплутати деякі клієнти й зайво навантажити трафік. Якщо ваше середовище цього вимагає — задокументуйте виняток і ретельно протестуйте.

2) Чому мій браузер довіряє реєстру, а Docker — ні?

Браузери кешують проміжні і можуть автоматично завантажувати відсутні проміжні. Docker на мінімальному хості часто не матиме їх у кеші і може не завантажувати. Вважайте успіх у браузері «приємним», а не доказом.

3) Куди встановити кастомний CA для Docker?

Краще встановити корпоративний root CA в системне сховище довіри, щоб все виграло. Docker також підтримує per‑registry CA під /etc/docker/certs.d/<host:port>/ca.crt. Після змін перезапустіть Docker.

4) Я виправив ланцюг на сервері, але Kubernetes‑вузли все ще падають. Чому?

Kubernetes може використовувати containerd напряму, і вузли можуть не мати вашого CA в системній довірі або в тому місці, де рантайм його очікує. Дебагуйте на вузлі, а не на вашій робочій машині.

5) У чому різниця між «unknown authority» і «valid for X, not Y»?

«Unknown authority» — проблема ланцюга довіри (CA/root/проміжний). «Valid for X, not Y» — проблема валідації імені хоста (несумісність SAN). Це різні виправлення; не плутайте їх.

6) Чи можна тимчасово використати insecure-registries?

Можна, у тому ж сенсі, що можна тимчасово відключити димову сигналізацію під час приготування. Це може зменшити шум, але також прибирає контроль безпеки. Використовуйте лише з явним погодженням і планом видалення.

7) Чи потрібно перезапускати Nginx/Ingress після оновлення файлів сертифікатів?

Так, принаймні виконати reload, щоб процес підхопив новий сертифікат і ланцюг. Після reload перевіряйте через openssl s_client, а не перед ним.

8) Як уникнути простою під час ротації сертифікатів?

Попередньо розповсюдьте нові точки довіри (корені/проміжні) перед переключенням leaf‑сертифікатів, подавайте повні ланцюги і валідируйте з чистих хостів. Обробляйте розповсюдження CA як керований артефакт, а не як усне знання.

9) Чому це падає лише на зовсім нових вузлах?

Нові вузли виявляють відсутні проміжні та корені, бо в них немає кешованих сертифікатів, і часто базові образи мають мінімальні сховища довіри. Саме тому автоскейл — відмінний аудитор.

10) Чи реєстр — це просто HTTPS, чи Docker вимагає щось особливе?

Транспортно це HTTPS з очікуваннями клієнта. З додатку це Docker Registry API. Якщо TLS правильно налаштовано, ви зазвичай отримаєте 401 Unauthorized від /v2/, коли неавторизовані — це ознака здоров’я.

Висновок: кроки, які вас не переслідуватимуть

Виправлення помилок TLS реєстру Docker «по‑людськи» — це скоріше дисципліна в роботі з PKI, ніж робота з Docker. Подайте повний ланцюг. Використовуйте правильні SAN. Встановіть потрібні точки довіри на кожній машині, що тягне образи. Потім видаліть небезпечні хакі, які ви додали під час паніки.

Практичні наступні кроки:

  1. Пройдіть швидкий план діагностики з проблемного вузла і зафіксуйте виводи для інцидентних нотаток.
  2. Оновіть TLS‑термінацію реєстру, щоб подавати leaf + проміжні (перевірте openssl s_client -showcerts).
  3. Стандартизируйте розповсюдження CA по вузлах/ранерах (системна довіра перш за все; /etc/docker/certs.d — лише за потреби).
  4. Додайте канарковий pull з чистого середовища, щоб ловити регресії ланцюга раніше, ніж розробники.
  5. Видаліть insecure-registries і розглядайте будь‑яке повторне додавання як виняток безпеки з датою завершення.

Якщо ви зробите ці п’ять речей, TLS‑реєстр перестане бути постійною драмою і стане тим, чим мав бути: фоном, який ви ніколи не чуєте.

← Попередня
Критична помилка WooCommerce після оновлення: як безпечно відкотити й відновити
Наступна →
Debian 13: флапи LACP-бонда — як довести, хто винен, комутатор чи хост

Залишити коментар