MWS Cloud описала, як після публікації приватних ключів восьми проміжних центрів сертифікації eMudhra прибирала пов’язані довірені корені з хмарної інфраструктури. Практичний урок для команд CI простий і не надто приємний: оновлений сертифікатний пакет на хості ще не означає, що контейнери, рантайми й кешовані образи перестали довіряти скомпрометованим центрам.

За описом компанії, інцидент набув терміновості ввечері 20 жовтня, коли в чат команди надійшло посилання на GitHub-репозиторій із закритими ключами. MWS оголосила фриз розгортань, а згодом поширила обмеження і на CI/CD. Роботи тривали тиждень: довіру довелося перевіряти на різних рівнях, від вузлів і базових образів до JVM-сховищ та окремих бандлів сертифікатів у бібліотеках.

За матеріалом MWS, першопричиною стала помилка у скрипті генерації ключів: у квітні 2025 року приватний ключ виявився числом від 0 до 255, а не випадковим 384-бітним значенням. Дослідники змогли відновити ключі з публічних сертифікатів. Під загрозою опинилися вісім проміжних CA бренду emSign, що використовувалися для TLS і підпису коду.

Чому блокування в браузерах не закриває проблему

Браузери отримали блокування через власні механізми, зокрема CRLSet і OneCRL; для Chrome важливу роль також відіграє Certificate Transparency. Але багато інструментів розробки не користуються тими самими каналами відкликання. Вони перевіряють сертифікат за локальним набором довірених коренів, який може бути в системі, контейнері або вбудованим у виконуваний файл.

Тому відсутність сертифікатів eMudhra на власному сайті не є достатньою перевіркою. Якщо клієнт довіряє emSign ECC Root CA — G3 або AAA Certificate Services, він може прийняти ланцюжок, побудований через скомпрометований ключ. У переліку потенційно зачеплених компонентів MWS називає curl і wget, Docker та containerd, npm, pip, Go-бінарники, JVM, gRPC і Terraform-провайдери. Залежно від місця такого клієнта в CI-ланцюжку наслідком може стати підміна залежності під час завантаження.

Сценарій, який розглядала команда, починається з перехоплення трафіку раннера до реєстру чи репозиторію пакетів. Якщо TLS-клієнт довіряє скомпрометованому кореню, він може прийняти підроблений сертифікат; далі раннер завантажує змінений пакет, а скрипт встановлення виконується в середовищі збірки. MWS окремо зауважує, що атакувальнику спершу потрібна позиція на мережевому шляху. Команда, однак, оцінювала не лише ймовірність, а й можливі наслідки для секретів і подальших збірок.

Ось де закінчується зручна модель «пакет сертифікатів оновлено — отже, все гаразд»: один контейнерний образ може містити п’ять або шість незалежних сховищ довіри. Ручної інвентаризації тут вистачає приблизно до першого сервісу, який читає інший файл.

Де шукали довіру і що змінювали

Команда визначила два корені, які потрібно прибрати з відповідних бандлів: emSign ECC Root CA — G3 та AAA Certificate Services, відомий також як Comodo AAA Services root. Другий шлях до довіри проходив через крос-підписи Sectigo, тому перевірити лише основний ланцюжок було недостатньо. MWS повідомляє, що перевірила 12 тестових ланцюжків після видалення коренів; водночас попереджає, що без AAA можуть перестати будуватися деякі старі легітимні ланцюжки Sectigo.

Оновлення ca-certificates на вузлах було лише першим кроком. containerd і dockerd тримають сертифікати в пам’яті після запуску, тому після зміни системного сховища їх перезапускали. Нові вузли теж потребували виправлення: команда оновлювала golden image та процедури їх підготовки, інакше хост міг з’явитися вже зі старим набором коренів.

Найбільше роботи було навколо CI. У MWS нарахували близько шестисот раннерів шести типів, частина з яких належала окремим командам. Оновлення хоста не виправляло контейнер джоби: його TLS-запити продовжували використовувати сховище образу. Як тимчасовий захід, у конфігурацію раннерів додали передавання системного бандла хоста в контейнери та налаштували змінні для окремих клієнтів.

Цей обхід має межі. Монтований каталог сертифікатів конфліктував із розташуванням cacerts у Temurin на Debian та Ubuntu: символьне посилання опинялося без цільового файлу, і Java-процеси завершувалися помилкою. Монтований лише файл бандла не ламав Java так само, але заважав образам оновлювати сховище або додавати власні корпоративні CA. Тому MWS залишила цей спосіб тимчасовим і паралельно додала побудову Java-сховища з актуального бандла.

Виявилися й менш очевидні копії коренів. Серед них — certifi у Python та вендорна копія в pip, власний файл CA у botocore і boto2, системний файл коренів gRPC, а також NSS і Java cacerts. Отже, виправлення системного пакета саме по собі не змінює файли, які постачаються разом із бібліотекою або рантаймом. Для частини стеків потрібні оновлені версії, для інших — налаштування використання системного бандла або окреме оновлення сховища.

У матеріалі наведені конкретні версії виправлень: Go 1.27.3 і 1.26.10, Node.js 22.23.4, 24.22.1 і 26.12.1, certifi 2026.10.19 та NSS 3.131.1. Для JVM описано два варіанти: виправлений JDK або блокування відбитків сертифікатів через blocked.certs. Уже зібрані Go-бінарники потребували повторної збірки, а для ранніх гілок Go виправлення, за матеріалом, не планувалися.

Образи, теги та перевірка результату

Перебудова образів створила окрему проблему залежностей: виправлений збірочний образ сам спочатку потребував виправленої бази. Команда випустила перші виправлені образи під попередніми тегами, а потім — із новими. Через кеші вузлів тег не гарантував, що запуститься саме новий вміст. MWS відмовилася масово вмикати imagePullPolicy: Always, щоб не створювати одночасне навантаження на реєстр, і натомість точково очищала кеші. Перевірка охопила понад дві тисячі хостів; старий образ знайшли на шести.

Для перевірки команда не покладалася на те, що файл зник із відомого каталогу. Виправлення зараховували, коли конкретний сервіс відхиляв тестовий TLS-ланцюжок. Для образів використовували чекер, який запускав образ і шукав небажані корені в відомих сховищах. Водночас автори попереджають: спрощений пошук може дати хибне спрацювання, наприклад на JVM, де проблему закриває список відбитків, або на пакеті pip у Debian та Ubuntu, який використовує системний бандл.

У підсумку MWS пов’язує довгострокове виправлення з централізованим керуванням довіреними коренями, інвентаризацією образів та власником для кожного раннера. Команда також описує перехід збірок на проксі-репозиторії, внутрішній реєстр для кластерів і використання нових тегів для виправлених образів. Для швидкої первинної перевірки автори радять запускати тест TLS саме з CI-джоби: стан ноутбука не показує, якому сховищу довіряє контейнер збірки.