Ви патчите сервери, пайплайн зелений, і раптом — нізвідки — cert verify failed з’являється як несподівана перевірка.
apt не може завантажити пакети, curl відмовляється спілкуватися, Docker pull-и провалюються, а логи додатків виглядають як середньовічне прокляття:
«unknown authority», «unable to get local issuer certificate», «self-signed certificate in certificate chain».
Ubuntu 24.04 тут не «крихкий» унікально. Він чесний. Він правильно перевіряє TLS і не буде зображати, що ваш ланцюг сертифікатів коректний, якщо це не так.
Виправлення рідко означає «вимкнути перевірку». Правильне виправлення — відновити сховища довіри та подати правильні проміжні ланцюги. Зробіть це один раз, правильно, і рухайтеся далі.
Швидкий план діагностики
Коли перевірка TLS падає, люди зазвичай метушаться: перевстановлюють випадкові пакети, змінюють змінні середовища, звинувачують Ubuntu або «мережу».
Не робіть цього. Ви налагоджуєте проблему ланцюга довіри. Ставтеся до неї як до інциденту в продакшені: ізолюйте, відтворіть і визначте, яке саме сховище довіри використовується.
Перше: відтворіть помилку одним відомим інструментом
- Якщо збій у додатку — відтворіть за допомогою
openssl s_client(еталон) таcurl -v(поведінка клієнта). - Зберіть: hostname, порт, SNI, проксі/без проксі, і чи знаходиться проблемний хост у контейнері/VM.
Друге: вирішіть, «ланцюг сервера» чи «сховище довіри клієнта»
- Якщо
openssl s_clientпоказує відсутні проміжні сертифікати — виправляйте сервер перш за все. Це чисте рішення. - Якщо ланцюг сервера в порядку, але клієнти все одно падають — ваше клієнтське сховище довіри застаріле або обходиться (власний CA bundle, зламаний симлінк, старий образ, дивний Java store).
Третє: перевірте перехоплення
- Якщо видавець сертифіката — ваша компанія, проксі перериває TLS. Додайте корпоративний root CA до системного сховища довіри (а можливо й до сховищ конкретних додатків).
- Якщо subject сертифіката не відповідає hostname — ви не дістаєтеся до того сервера, який думаєте (проксі, captive portal, підміна DNS, неправильний VIP).
Четверте: визначте радіус ураження
- Падає лише на одному хості? Це локальне сховище довіри, годинник або конфіг проксі.
- Падає по всьому флоту? Це ротація CA, зміна політики проксі або зламаний серверний ланцюг, розгорнутий широко.
- Падає лише в контейнерах? Це дрейф CA bundle у образі (або різниця між Alpine та Debian у довірі).
Одна передана ідея від W. Edwards Deming, яку операційники неодноразово вчаться важко: Без даних ви просто ще одна людина з думкою
(парафраз).
Збирайте докази рукостискання перед тим, як щось «виправляти».
Що насправді означає «cert verify failed» в Ubuntu 24.04
«Cert verify failed» — це не одна помилка. Це сімейство збоїв, які всі закінчуються на одній межі: клієнт не зміг побудувати довірений шлях від сертифіката сервера до довіреного кореневого CA.
Це може статися з кількох конкретних причин:
- Відсутні проміжні сертифікати на сервері (найпоширеніше у польових умовах).
- Клієнтське сховище довіри не містить кореневого CA (поширено при приватному PKI або корпоративному TLS-інспектуванні).
- Невірний системний час (сертифікат ще не дійсний / прострочений).
- Несумісність імені хоста (з’єднання з неправильним сервісом, невірний SNI або дивні DNS/проксі).
- Додаток використовує власний CA bundle і ігнорує системне сховище (вітаю, Java; також деякі Python, Node і контейнерні додатки).
- Пошкоджена упаковка CA bundle (рідко, але трапляється після часткових оновлень, ручних правок або шарування образів).
- Політика відкликання/CRL/OCSP у строгих клієнтів (менш поширено за стандартних налаштувань Ubuntu, але часто зустрічається в корпоративних інструментах).
Ubuntu 24.04 використовує OpenSSL 3 у базовій системі та постачає ca-certificates, що містить набір довірених коренів Mozilla у вигляді бандлу.
Більшість командних інструментів в підсумку звертаються до цього, якщо вони не жорстко налаштовані інакше.
Мета — не «змусити помилку зникнути». Мета — зробити ланцюг сертифікатів коректним і явно вказати точку довіри.
Якщо це зробити, помилка зникне як побічний ефект. Це правильний причинно-наслідковий напрям.
Жарт №1: Вимикати перевірку TLS у продакшені — це як зняти сигналізацію диму, бо вона продовжує пищати. Писк робив свою роботу.
Факти та історія, які пояснюють сучасний безлад
Трохи контексту робить сьогоднішні збої менш випадковими. Ось кілька конкретних, реально корисних фактів:
- CA-бандли на Linux переважно відстежують програму коренів Mozilla. Пакет
ca-certificatesпо суті — дружня для дистрибутива оболонка навколо цього списку довіри. - Проміжні сертифікати не завжди кешуються універсально. Деякі клієнти кешують проміжні, деякі — ні, кеші можуть закінчитися. Сервер, який «працює на моєму ноуті», все ще може бути зламаним.
- Ранні зміни ланцюга Let’s Encrypt підпалили багато людей. Крос-підписання і вибір ланцюга спричинили періодичні збої на старіших клієнтах і при некоректних налаштуваннях серверів.
- SNI (Server Name Indication) став фактично обов’язковим. Без SNI ви можете отримати неправильний сертифікат з мультиорендного кінцевого пункту і провалити перевірку імені хоста.
- OpenSSL 3 посилив екосистему. Воно не «зламало TLS»; воно зробило слабку, неоднозначну або некоректну поведінку більш помітною та менш терплячою.
- Корпоративне перехоплення TLS старше за більшість контейнерних платформ. Воно передує Kubernetes, Docker і навіть деяким провайдерам хмар; воно просто стало болючішим, коли все перейшло на HTTPS.
- Java історично несла своє власне сховище довіри. Багато корпоративних додатків досі так роблять, тому «працює з curl, падає в додатку» повторюється постійно.
- Побудова шляху може відрізнятися за бібліотекою. GnuTLS vs OpenSSL vs NSS можуть по-різному пройти чи не пройти на одному й тому ж ланцюгу залежно від того, як обробляються проміжні.
- Не існує «стандартного місця», яке повністю шанує кожна програма. У Linux є конвенції, але кожен стек може їх перевизначити, і багато хто це робить.
Схема сховищ довіри в Ubuntu 24.04: хто що читає
Перед запуском команд зафіксуйте одну ментальну модель: «системне сховище CA» — це не один файл. Це набір джерел, скомпільованих у файли-бандли,
і різні інструменти обирають різні точки входу.
Ключові файли та директорії
/etc/ssl/certs/ca-certificates.crt— головний PEM-бандл (звичайний дефолт для інструментів на основі OpenSSL)./etc/ssl/certs/— хешовані симлінки та індивідуальні сертифікати, які використовуються lookup-ами OpenSSL./usr/local/share/ca-certificates/— куди поміщати локальні CA (.crt), щоб додати їх до системного сховища./etc/ca-certificates.conf— які CA увімкнені/вимкнені при генерації бандлів./var/lib/ca-certificates/— згенерований/керований вміст (не редагуйте вручну).
Хто що зазвичай використовує
- curl: зазвичай використовує шлях/бандл OpenSSL; поважає
SSL_CERT_FILE/SSL_CERT_DIR. - apt: використовує системний стек OpenSSL/gnutls залежно від збірки; на Ubuntu зазвичай покладається на системну довіру через
ca-certificates. - Python requests: за замовчуванням використовує
certifiу багатьох virtualenv, якщо не вказано використовувати системне сховище. - Java: використовує
cacertsу JRE, якщо явно не налаштовано інакше. - Docker: використовує довіру ОС для викликів реєстру, але також має каталоги сертифікатів для кожного реєстру.
Українською для операторів: якщо падає лише один додаток, не перевстановлюйте без кінця ca-certificates. Ви, ймовірно, ремонтуєте не те сховище довіри.
Практичні завдання (команди, виводи, рішення)
Нижче — практичні завдання, які можна виконати на Ubuntu 24.04. Кожне містить: команду, що означає типовий вивід, і рішення, яке потрібно прийняти далі.
Це написано для реальних інцидентів: сервери, CI-рунери, контейнери і корпоративні мережі.
Завдання 1: Підтвердити системний час (нудно, але перше)
cr0x@server:~$ timedatectl
Local time: Mon 2025-12-30 11:22:43 UTC
Universal time: Mon 2025-12-30 11:22:43 UTC
RTC time: Mon 2025-12-30 11:22:43
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Значення: Якщо годинник не синхронізований, ви можете отримувати помилки «certificate not yet valid» або «expired» навіть при ідеальних ланцюгах.
Рішення: Якщо System clock synchronized — no, виправте NTP перш за все. Не чіпайте сертифікати, поки час не стане в порядку.
Завдання 2: Відтворити з curl і зафіксувати точну помилку верифікації
cr0x@server:~$ curl -Iv https://repo.example.internal/
* 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
Значення: Клієнт не зміг побудувати ланцюг до довіреного кореня. Часто це означає або відсутні проміжні сертифікати (на сервері), або відсутній корінь на клієнті.
Рішення: Перейдіть до openssl s_client, щоб побачити, що сервер фактично надсилає.
Завдання 3: Перевірити ланцюг сервера через OpenSSL (еталон)
cr0x@server:~$ openssl s_client -connect repo.example.internal:443 -servername repo.example.internal -showcerts -verify_return_error </dev/null
depth=0 CN = repo.example.internal
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = repo.example.internal
verify error:num=21:unable to verify the first certificate
verify return:1
Verification error: unable to verify the first certificate
---
Certificate chain
0 s:CN = repo.example.internal
i:CN = Example Issuing CA 01
-----BEGIN CERTIFICATE-----
...leaf...
-----END CERTIFICATE-----
---
Значення: Сервер надіслав лише leaf-сертифікат. Проміжні не були відправлені. Клієнти, які не мають проміжного в кеші, будуть падати.
Рішення: Налаштуйте сервер так, щоб він віддавав повний ланцюг (leaf + проміжні). Це бажане виправлення.
Завдання 4: Перевірити, який CA-бандл використовує curl
cr0x@server:~$ curl -v https://example.com/ 2>&1 | grep -E "CAfile|CApath"
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
Значення: curl використовує системний бандл і хешований каталог.
Рішення: Якщо ваш корпоративний CA не довірений, потрібно додати його через /usr/local/share/ca-certificates та виконати update-ca-certificates.
Завдання 5: Перевірити, що OS CA-бандл існує і не очевидно пошкоджений
cr0x@server:~$ ls -l /etc/ssl/certs/ca-certificates.crt
-rw-r--r-- 1 root root 223541 Dec 30 10:58 /etc/ssl/certs/ca-certificates.crt
Значення: Бандл існує і має непорожній розмір.
Рішення: Якщо він відсутній або крихітний (кілька байтів), підозрюйте зламаний стан пакета або пошкодження CM-скриптом. Перевстановіть ca-certificates.
Завдання 6: Перевстановити і згенерувати CA-сертифікати коректно
cr0x@server:~$ sudo apt-get update
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Reading package lists... Done
cr0x@server:~$ sudo apt-get install --reinstall -y ca-certificates
Reading package lists... Done
Building dependency tree... Done
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 0 not upgraded.
Setting up ca-certificates (20240203) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Значення: Пакет присутній; генерація бандлу виконалась.
Рішення: Якщо під час «Updating certificates» з’являються помилки — зупиніться і прочитайте їх. Проблеми з правами, заповнений диск або зламані файли в локальній директорії CA можуть перешкодити оновленню.
Завдання 7: Перевірити наявність локальних CA і чи були вони імпортовані
cr0x@server:~$ ls -l /usr/local/share/ca-certificates
total 8
-rw-r--r-- 1 root root 2048 Dec 30 10:57 corp-proxy-root-ca.crt
-rw-r--r-- 1 root root 1876 Dec 30 10:57 corp-issuing-ca.crt
Значення: Локальні CA-файли існують у правильній директорії і мають розширення .crt.
Рішення: Якщо ваші CA-файли мають .pem або дивні розширення — перейменуйте в .crt і запустіть update-ca-certificates.
Завдання 8: Імпортувати локальні CA в системне сховище Ubuntu
cr0x@server:~$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
2 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
Значення: Ваші два локальні CA додані і хешовані в /etc/ssl/certs.
Рішення: Повторно перевірте інструмент, що падали. Якщо він все одно падає, швидше за все ви маєте справу з проблемою проміжного ланцюга на сервері або додаток використовує інше сховище довіри.
Завдання 9: Явно перевірити ланцюг проти системного бандла
cr0x@server:~$ openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /tmp/server-leaf.pem
CN = repo.example.internal
error 20 at 0 depth lookup: unable to get local issuer certificate
error /tmp/server-leaf.pem: verification failed
Значення: Сам по собі leaf не може бути перевірений, бо OpenSSL не знаходить його видавця (проміжний) у сховищі довіри.
Рішення: Якщо проміжний не призначено робити довіреним коренем — не додавайте його до сховища тільки щоб «запрацювало». Виправте ланцюг на сервері.
Завдання 10: Завантажити і перевірити повний ланцюг з сервера
cr0x@server:~$ openssl s_client -connect repo.example.internal:443 -servername repo.example.internal -showcerts </dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > /tmp/chain.pem
cr0x@server:~$ openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt -untrusted /tmp/chain.pem /tmp/chain.pem
/tmp/chain.pem: OK
Значення: Коли проміжні доступні, верифікація проходить.
Рішення: Якщо openssl verify успішний, але ваш додаток падає, скоріш за все ваш додаток використовує інший CA-бандл (Python certifi, Java cacerts, вбудований бандл).
Завдання 11: Діагностувати помилки apt HTTPS з цільовим виводом
cr0x@server:~$ sudo apt-get update -o Debug::Acquire::https=true
Ign:1 https://repo.example.internal noble InRelease
Err:1 https://repo.example.internal noble InRelease
Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.
Reading package lists... Done
W: Failed to fetch https://repo.example.internal/dists/noble/InRelease Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.
Значення: apt не може перевірити ланцюг сертифікатів репозиторію.
Рішення: Або сервер репозиторію не віддає проміжні, або ваше системне сховище не містить корпоративного кореня. Не використовуйте [trusted=yes] як пластир, якщо вам не подобається отримувати виклики вночі.
Завдання 12: Перевірити, чи проксі впливає на apt і curl
cr0x@server:~$ env | grep -iE 'http_proxy|https_proxy|no_proxy'
https_proxy=http://proxy.corp.internal:3128
no_proxy=localhost,127.0.0.1,.corp.internal
Значення: Запити можуть йти через проксі, який можливо робить TLS-перехоплення.
Рішення: Якщо проксі перехоплює, встановіть його root CA у системне сховище довіри. Якщо ви мали на увазі прямий доступ — виправте змінні середовища та конфіг apt.
Завдання 13: Підтвердити, що отриманий сертифікат відповідає імені хоста (правильність SNI)
cr0x@server:~$ openssl s_client -connect 10.20.30.40:443 -servername repo.example.internal </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer
subject=CN = repo.example.internal
issuer=CN = Example Issuing CA 01
Значення: Зі вказаним SNI ви отримали очікуваний сертифікат.
Рішення: Якщо subject неправильний без SNI, ваш клієнт/інструмент може не відправляти SNI (рідко сьогодні, але все ще можливо в вбудованих стеках). Використовуйте інструменти з підтримкою SNI або виправте кінцеву точку.
Завдання 14: Визначити, чи Python використовує certifi замість системних CA
cr0x@server:~$ python3 -c "import ssl; print(ssl.get_default_verify_paths())"
DefaultVerifyPaths(cafile='/etc/ssl/certs/ca-certificates.crt', capath='/etc/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/lib/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/lib/ssl/certs')
cr0x@server:~$ python3 -c "import requests; import certifi; print(certifi.where())"
/usr/lib/python3/dist-packages/certifi/cacert.pem
Значення: Модуль SSL за замовчуванням дивиться на системне сховище, але requests може віддавати перевагу бандлу certifi в залежності від упаковки і середовища.
Рішення: Якщо ваш корпоративний CA є лише в системному сховищі, налаштуйте додаток використовувати його (або оновіть certifi-бандл у тому середовищі, або пропишіть правильний шлях до CA).
Завдання 15: Перевірити Java trust store, якщо падають лише JVM-додатки
cr0x@server:~$ sudo keytool -list -keystore /etc/ssl/certs/java/cacerts -storepass changeit | head
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 141 entries
Значення: Java має власне сховище CA.
Рішення: Якщо корпоративні корені відсутні, імпортуйте їх у Java cacerts або вкажіть JVM використовувати системний бандл. Виправлення лише OS не врятує тут.
Завдання 16: Шлях довіри Docker реєстру (якщо не вдається тягнути образи)
cr0x@server:~$ sudo ls -l /etc/docker/certs.d
total 4
drwxr-xr-x 2 root root 4096 Dec 30 11:01 registry.corp.internal:5000
cr0x@server:~$ sudo ls -l /etc/docker/certs.d/registry.corp.internal:5000
total 4
-rw-r--r-- 1 root root 2048 Dec 30 11:01 ca.crt
Значення: Docker має довірчі якорі на реєстр за кожним реєстром; він може працювати, навіть якщо системна довіра неповна (або навпаки).
Рішення: Виберіть одну модель. У корпоративному середовищі я пропоную додавати корпоративний root у довіру ОС і мінімізувати перезаписи Docker, документуючи їх.
Проміжні ланцюги: тихий вбивця
Більшість інцидентів «cert verify failed», що виглядають загадково, — просто відсутні проміжні. Сервери повинні подавати ланцюг,
який дозволяє клієнтам зв’язати leaf-сертифікат з довіреним коренем. Сам корінь зазвичай не надсилається; клієнти вже його мають.
Проміжні повинні надсилатися сервером.
Як це зазвичай ламається на практиці
Поширена неправильна конфігурація — встановити лише leaf-сертифікат на TLS-ендпойнті. Браузери іноді все одно працюють, бо:
(a) вони кешували проміжний з іншого джерела, (b) вони завантажили його через AIA (Authority Information Access), або (c) поводяться більш поблажливо.
Тим часом безголові клієнти в продакшені падають, бо вони не завантажують проміжні або їм заблоковано вихідні запити.
Що робити замість цього
- На стороні сервера налаштуйте TLS-сервіс з файлом повного ланцюга (leaf + проміжні, у правильному порядку).
- Підтвердьте через
openssl s_client -showcerts, що проміжний дійсно віддається. - Віддавайте перевагу виправленню сервера. Додавання проміжних як коренів довіри на клієнтах — це операційний борг, замаскований під «швидке виправлення».
Жарт №2: Сертифікатні ланцюги — як оргструктура: якщо пропустити середніх менеджерів, нічого не затверджується і всі звинувачують стажера.
Корпоративні проксі та перехоплення TLS
У багатьох підприємствах вихідний HTTPS перехоплюють: проксі розриває TLS, інспектує трафік, а потім шифрує знову до кінцевого пункту.
Ваш видавець сертифіката стає «Corporate Proxy Root CA» (або схожим), і клієнти будуть падати, якщо цей корінь не довірений.
Як підтвердити перехоплення
Запустіть openssl s_client до публічного сайту з ураженого хоста і подивіться на issuer. Якщо це не публічний CA, якого ви очікуєте,
ви не з’єднуєтеся напряму з інтернетом. Ви спілкуєтесь зі своєю компанією.
Як виправити це правильно
- Отримайте корпоративний root CA (і будь-які проміжні, які використовує проксі) в PEM-форматі.
- Встановіть їх у
/usr/local/share/ca-certificatesі виконайтеupdate-ca-certificates. - Потім перевірте сховища довіри специфічних додатків (Java, Python certifi, вбудовані). Вирішіть, чи стандартизувати на системній довірі або підтримувати per-app сховища.
Чого не варто робити
- Не вимикайте верифікацію в apt/curl глобально.
- Не обсипайте CI-скрипти прапорцями «insecure» як остаточне рішення.
- Не імпортуйте leaf-сертифікати як довірені корені. Це не довіра — це капітуляція.
Три корпоративні історії з поля бою
1) Інцидент через хибне припущення: «Балансувальник навантаження подає ланцюг»
Середня компанія тримала внутрішні репозиторії за керованим балансувальником. Команда оновила leaf-сертифікат,
завантажила його, браузери працювали, і всі заспокоїлися. Наступного ранку вікна патчів почали падати на частині Ubuntu-хостів:
apt не міг отримати оновлення. «Cert verify failed» всюди.
Припущення було простим і хибним: вони думали, що балансувальник автоматично подає правильний проміжний ланцюг.
Він цього не робив. Він подавав лише leaf. Причина, чому «працювало в браузерах» — кешовані проміжні та у деяких мережах — опортуністичне AIA-завантаження. Headless apt-клієнти не завантажували нічого.
Дебаг зайняв більше часу, ніж мав би, бо всі почали перевстановлювати ca-certificates на клієнтах.
Це нічого не змінило. Помилка була на стороні сервера. Коли хтось запустив openssl s_client -showcerts і побачив ланцюг довжини один,
рішення стало очевидним: налаштувати балансувальник з повним ланцюгом.
Тривалий урок не був «використовуйте fullchain» (всі вже знали це). Він був: не довіряйте нічому, чого не перевірили з точки зору ураженого клієнта.
Та сама кінцева точка може виглядати нормально з ноутбука і зламатися з локбоксованого сервера.
2) Оптимізація, що обернулася проти: «Запікали CA-бандли в образ для швидкості»
Інша організація намагалася прискорити збірки контейнерів, зафіксувавши базовий шар з CA-сертифікатами й ніколи його не змінюючи.
Логіка здавалася акуратною: CA-бандли змінюються повільно, і їх оновлення «витрачає час збірки». Платформна команда навіть стандартизувала шлях,
і команди додатків мали на нього покладатися.
Через місяці політика корпоративного проксі змінилась. Перехоплення вихідного HTTPS стало обов’язковим для певних підмереж, і проксі використав новий root CA.
Хости оновили корпоративний корінь через CM. Контейнери — ні. Раптом контейнери не могли викликати зовнішні API,
не могли підтягнути залежності і деякі навіть не могли відправити логи.
Схема аварій була гострою: сервіси працювали на bare-metal, але падали в Kubernetes. Розробники звинувачували Kubernetes.
SRE звинувачували «мережні зміни». Насправді це був образний CA-бандл, що окам’янів.
Рішення було прагматичним: базові образи почали регулярно перебудовувати CA-бандли, а образи додатків перестали перезаписувати шляхи довіри.
Та «оптимізація» зекономила секунди на збірці і коштувала днів інцидентного часу. Дуже дорога економія.
3) Нудна, але правильна практика, яка врятувала день: «Одна пайплайн довіри, одне джерело правди»
Фінансова компанія мала протилежний підхід: невблаганну нудьгу. Всі корпоративні CA жили у версіонованому репозиторії,
розповсюджувались через конфігураційний менеджмент і встановлювались у OS trust store стандартними процедурами.
Вони також мали просту щоденну перевірку: запуск TLS-проб з репрезентативних хостів (включно з контейнерами) до критичних endpoint-ів.
Коли проміжний CA ротувався на внутрішньому сервісі, кілька хостів почали падати. Проба зловила це швидко.
На виклику on-call не потрібні були племінні знання. Ран-буківказував: перевірити довжину поданого ланцюга; порівняти issuer; підтвердити стан локального сховища довіри; виправити серверний ланцюг.
Саме так вони і зробили.
Виправлення було на стороні сервера: у fullchain-файлі після зміни автоматизації оновлення сертифікатів не вистачало одного проміжного.
Оскільки у них був централізований пайплайн довіри, ніхто не намагався «ремонтувати клієнтів», імпортуючи проміжні як корені.
Радіус ураження залишився малим, інцидент — коротким.
Це не було гламурно. Це було правильно. У продакшені «нудне» — комплімент.
Поширені помилки: симптом → корінь проблеми → виправлення
1) curl падає, браузер працює
Симптом: curl: (60) unable to get local issuer certificate; браузери завантажують сторінку нормально.
Корінь проблеми: Сервер не віддає проміжний ланцюг; браузер має кешований проміжний або завантажив його через AIA.
Виправлення: Налаштуйте сервер/балансувальник з fullchain (leaf + проміжні). Перевірте openssl s_client -showcerts.
2) apt update падає лише на деяких хостах
Симптом: HTTPS-помилки apt на підмножині флоту; інші в порядку.
Корінь проблеми: Дрейф: деякі хости пропустили оновлення CA, мають зламаний стан ca-certificates або неправильні змінні proxy.
Виправлення: Перевірте час, перевстановіть ca-certificates, запустіть update-ca-certificates і порівняйте proxy-змінні/конфіг між хостами.
3) «certificate signed by unknown authority» лише в контейнерах
Симптом: curl на хості працює; curl у контейнері падає; Docker pull-и в кластері не вдаються.
Корінь проблеми: Образ контейнера має застарілий CA-бандл або використовує інше сховище довіри, ніж хост.
Виправлення: Переконайтесь, що CA-бандл оновлено всередині образу; уникайте вічного фіксування CA-шару; встановлюйте корпоративний root CA під час збірки або монтуйте системну довіру де потрібно.
4) Java-додаток падає, curl успішний
Симптом: Логи JVM показують PKIX path building failed; curl до того самого endpoint-а працює.
Корінь проблеми: Java-сховище довіри не містить корпоративного root CA або не використовує системне сховище.
Виправлення: Імпортуйте корпоративний CA в Java cacerts або налаштуйте JVM використовувати системний бандл.
5) «self-signed certificate in certificate chain» після розгортання проксі
Симптом: Раптово широкі збої; issuer схоже на корпоративний CA; ланцюг містить «self-signed».
Корінь проблеми: TLS-перехоплення з недовіреним корпоративним коренем на клієнтах (або розповсюджено неправильний корінь).
Виправлення: Встановіть правильний корпоративний root CA у довіру ОС (і в сховища додатків). Переконайтесь, що issuer відповідає очікуваному корпоративному кореню.
6) Верифікація падає після «очищення файлів сертифікатів»
Симптом: update-ca-certificates видає помилки; бандл відсутній; інструменти падають скрізь.
Корінь проблеми: Хтось редагував згенеровані файли в /etc/ssl/certs або видалив хешовані посилання.
Виправлення: Перевстановіть ca-certificates, перезапустіть update-ca-certificates і припиніть керувати згенерованими шляхами ad-hoc-скриптами.
7) Падає лише один домен, все інше працює
Симптом: Один внутрішній сервіс помилюється; інші ОК.
Корінь проблеми: Той сервіс подає неправильний ланцюг, неправильний сертифікат або неправильне SNI-мапування на LB.
Виправлення: Використайте openssl s_client -servername, щоб підтвердити правильний сертифікат; виправте конфіг сервера.
8) Періодичні збої, що «самі по собі зникають»
Симптом: Той самий клієнт іноді успішний, іноді падає, без змін конфігурації.
Корінь проблеми: Кілька бекендів за VIP; деякі подають правильний ланцюг, інші — ні. Або кілька проксі з різними сертифікаційними політиками.
Виправлення: Достукуйтесь до кожного бекенду напряму; порівняйте подані ланцюги; уніфікуйте TLS-конфіг на всіх членах пулу.
Контрольні списки / покроковий план
Покроковий план для одного проблемного хоста Ubuntu 24.04
-
Підтвердьте час і базову мережу (
timedatectl, розв’язання DNS, маршрут/змінні proxy). Виправте час перш за все. -
Відтворіть з curl використовуючи
-Ivі зафіксуйте точну помилку. Якщо це невідповідність імені, зупиніться і виправте endpoint/SNI. -
Запустіть інспекцію ланцюга OpenSSL з
-showcerts -verify_return_error -servername. Визначте, чи відсутні проміжні. - Якщо проміжні відсутні, виправте сервер/LB, щоб віддавати fullchain. Повторно протестуйте з того самого хоста.
-
Якщо issuer корпоративний/проксі, встановіть корпоративний root CA в
/usr/local/share/ca-certificatesі виконайтеupdate-ca-certificates. - Якщо падає лише один додаток, ідентифікуйте його сховище довіри (Python certifi, Java cacerts, бандл у контейнері, вбудований шлях).
- Закріпіть результат: приберіть тимчасові insecure-прапорці, задокументуйте метод розповсюдження CA і додайте просту перевірку, щоб виявляти майбутні ротації.
Чеклист для виправлення серверного ланцюга (як має бути правильно)
- Leaf-сертифікат відповідає імені хоста (SAN містить DNS-ім’я).
- Leaf підписаний проміжним CA (не self-signed, якщо тільки приватний root не використовується навмисно).
- Сервер подає leaf + проміжні в правильному порядку.
- Root CA зазвичай не подається (необхідність рідко і іноді не рекомендується).
- Верифікація проходить з чистого клієнта, що використовує системне сховище довіри.
Чеклист для гігієни клієнтської довіри (як уникнути повторних інцидентів)
- Корпоративні корені розповсюджуються через CM, а не копіюються вручну.
- OS store оновлюється через
update-ca-certificatesпісля змін. - Контейнери періодично перебудовують CA-бандли або роблять це на етапі збірки надійно.
- Команди додатків знають, чи вони мають використовувати системну довіру або app-specific store.
- Проби перевіряють критичні endpoint-и щодня з репрезентативних середовищ (хост + контейнер + CI-рунер).
FAQ
1) Чи перевстановлення ca-certificates завжди вирішує проблему?
Ні. Воно виправляє зламану генерацію локального бандла і застарілі пакети, але не виправить сервер, який не віддає проміжні.
Використайте openssl s_client -showcerts, щоб вирішити, де саме проблема: ланцюг сервера чи довіра клієнта.
2) Чи варто додавати проміжний сертифікат до клієнтського сховища довіри?
Зазвичай ні. Проміжні — це не точки довіри; вони частина ланцюга, який сервер має віддавати.
Додавати проміжні в сховища довіри «працює», але це поширює серверну помилку по всіх ваших клієнтах і контейнерах.
3) Чому на моєму ноутбуці працює, а на серверах падає?
Кешовані проміжні, різні сховища довіри, різні проксі або різна поведінка DNS/SNI.
Сервери часто строгіші і більш ізольовані, саме тому вони падають першими.
4) Куди покласти корпоративний root CA в Ubuntu 24.04?
Покладіть PEM-кодований сертифікат у /usr/local/share/ca-certificates/ з розширенням .crt, потім виконайте sudo update-ca-certificates.
Перевірте включення, перевіривши інструменти, наприклад curl.
5) apt падає з помилками сертифіката. Чи можу я використати [trusted=yes] в sources.list?
Це обходить перевірку підписів для того репозиторію, а не вирішує TLS-перевірку коректно, і це зниження безпеки в будь-якому випадку.
Виправте довіру CA або серверний ланцюг. Розглядайте ненадійні скорочення лише як короткостроковий аварійний захід і видаляйте їх негайно.
6) Мій Python-додаток падає, а системний curl працює. Чому?
Багато Python-середовищ використовують certifi-бандл замість системного сховища.
Підтвердіть за допомогою python3 -c "import certifi; print(certifi.where())" і вирішіть, чи вказувати requests на системні CA або оновити бандл.
7) Як визначити, чи проксі перехоплює TLS?
Перевірте issuer сертифіката при з’єднанні з відомим публічним сайтом.
Якщо issuer — внутрішній корпоративний CA, вас перехоплюють. Це не обов’язково зло; це вимога до розповсюдження довіри.
8) Чи потрібно перезапускати сервіси після оновлення CA?
Часто так для довгоживучих процесів. Багато програм читають бандл CA при старті і тримають його в пам’яті.
Для системних демонів і серверів додатків плануйте рестарт або rolling deploy після оновлення CA.
9) У чому різниця між «unable to get local issuer certificate» і «self-signed certificate»?
«Unable to get local issuer» зазвичай означає відсутній проміжний або відсутній довірений корінь.
«Self-signed» часто означає, що ланцюг містить сертифікат, який не довірений як корінь, або ви трапляєтеся на проксі/mitm-сертифікат без довіри до його кореня.
10) Як запобігти цьому класу відмов?
Виправляйте серверні ланцюги правильно, централізуйте розповсюдження CA, уникайте закам’янілих CA-бандлів в образах і додайте просту щоденну перевірку TLS для критичних endpoint-ів.
Секрет — узгодженість, а не героїчні вчинки.
Висновок: наступні кроки, які дійсно працюють
Ubuntu 24.04 не «капризує», коли каже «cert verify failed». Він каже правду.
Найшвидше довготривале рішення майже завжди одне з двох: сервіс має подавати правильний проміжний ланцюг на сервері, або інсталюйте правильний корінь CA на клієнті.
Усе інше — це обхідна доріжка, яка стає політикою, а політика — болем.
Наступні кроки, що приносять користь:
- Запустіть швидкий план діагностики на одному проблемному хості і збережіть вивід OpenSSL.
- Виправте server-side fullchain там, де контролюєте кінцеву точку; вважайте це первинним ремедіумом.
- Стандартизуйтесь на встановленні корпоративного CA через
/usr/local/share/ca-certificates+update-ca-certificates. - Аудитуйте app-specific сховища довіри (Java, Python certifi, контейнери) і оберіть стандартний підхід.
- Додайте просту пробу, яка перевіряє TLS з репрезентативних середовищ, щоб виявляти наступний розрив до того, як користувачі його помітять.
Зробіть ланцюг правильно один раз. Майбутній ви буде трохи менш втомленим — і це найприближеніший варіант параду перемоги для операцій.