ADG Оставить заявку
Блог Информационная безопасность 4 мин чтения

OpenSSL 1.1.0: обновляем managed-сервисы и разбираемся с ABI

OpenSSL 1.1.0 вышел с ChaCha20-Poly1305 и курсом на TLS 1.3. Обновили все публичные сервисы, споткнулись об изменённый ABI и поправили Ansible-роли.

Контекст момента

OpenSSL 1.1.0 вышел в августе 2016 года с поддержкой ChaCha20-Poly1305 и подготовкой к TLS 1.3

OpenSSL 1.1.0 вышел в конце августа. По меркам OpenSSL это заметный релиз: новая ветка, сломанный ABI, ChaCha20-Poly1305 в стандартной поставке и работа в направлении TLS 1.3 - пока в виде черновика IETF, но структура кода уже учитывает предстоящий протокол. Мы взяли несколько дней на то чтобы разобраться что именно изменилось, и прогнали обновление по всем публичным сервисам на managed-сопровождении.

Что изменилось в 1.1.0

Главное для нас - три вещи.

ChaCha20-Poly1305 теперь в основной поставке. Раньше нужен был патч или сторонняя сборка. Теперь это штатный шифр, который nginx и другие приложения могут использовать без плясок. Для мобильных клиентов это хорошая новость: ChaCha20 работает быстрее AES на процессорах без аппаратного AES-NI, а это большинство ARM-устройств.

ABI изменился. Это ключевой момент и главный источник боли при обновлении. Внутренние структуры OpenSSL - SSL_CTX, X509, EVP_CIPHER_CTX и другие - стали непрозрачными (opaque). Код, который обращался к полям этих структур напрямую, больше не компилируется. Для чистых пользователей публичного API это прозрачно. Для тех, кто тянул внутренности - сюрприз.

Версионирование библиотек изменилось. libssl.so.1.0.0 превратился в libssl.so.1.1. Приложения, слинкованные со старой версией, не подхватят новую автоматически. Нужно либо пересобирать, либо держать обе версии параллельно.

Как это выглядело на практике

На большинстве хостов OpenSSL 1.1.0 из репозитория дистрибутива пока не пришёл - Ubuntu 16.04 держит 1.0.2, RHEL 7 тоже. Так что обновление касалось прежде всего тех хостов, где мы собираем nginx из исходников или используем сторонние репозитории для получения свежих версий.

На хостах с nginx, собранным с --with-openssl=..., пришлось пересобрать nginx против новой OpenSSL. Штатный nginx -V показывает с какой версией OpenSSL он слинкован - это первый чекпоинт. На нескольких хостах после обновления системной OpenSSL nginx всё ещё использовал старую версию, потому что был слинкован статически. Именно так и должно быть при статической линковке, но важно это осознавать, а не надеяться что «само обновилось».

Второй сюрприз пришёл с Python-приложениями, использующими pyOpenSSL. Пакет pyOpenSSL до версии 16.2 опирается на cffi-биндинги, которые при сломанном ABI могут вести себя непредсказуемо. Пришлось проверить версии pyOpenSSL на каждом хосте и обновить там, где это возможно без риска для приложений.

Что делали в Ansible-ролях

У нас есть несколько ролей, которые устанавливают и настраивают nginx, Postfix, stunnel. Все они явно указывают пакеты в apt/yum задачах. После выхода 1.1.0 мы прошлись по ролям и добавили несколько вещей.

Проверка версии OpenSSL в задаче preflight. Короткий openssl version с проверкой вывода - чтобы плейбук явно знал с чем работает, а не угадывал.

Переменная openssl_version в defaults. Раньше версия нигде явно не фигурировала - пакетный менеджер ставил что есть. Теперь мы можем явно прописать ожидаемую ветку и сверять с фактом.

Отдельная задача для ldconfig. При параллельном существовании 1.0.2 и 1.1.0 важно контролировать какая версия найдётся по умолчанию через ld.so. Без явного ldconfig и правильного порядка в /etc/ld.so.conf.d/ ситуация непредсказуема.

Ролей не так много, обход занял несколько часов. Но именно в таких случаях понимаешь ценность того, что вся инфраструктура описана в Ansible: не нужно вспоминать что где стоит, достаточно пройтись по ролям и инвентарю.

Что с TLS 1.3

В 1.1.0 поддержка TLS 1.3 присутствует в виде черновой реализации draft-18. Это не production-ready: спецификация ещё не финализирована, черновик меняется. Включать в production сейчас не стоит - не потому что опасно, а потому что клиенты TLS 1.3 draft-18 пока единичны и протокол может измениться до финальной версии RFC.

Полезно другое: сама архитектура кода OpenSSL 1.1.0 готовилась с учётом предстоящего протокола. Когда TLS 1.3 RFC выйдет, путь к поддержке будет короче.

Что в итоге

ChaCha20-Poly1305 включили на всех nginx-хостах где это имело смысл - в первую очередь там, где много мобильного трафика. Порядок шифров в конфиге пересмотрели: ChaCha20-Poly1305 поставили перед AES-128-GCM для клиентов без AES-NI, AES-128-GCM оставили приоритетным для тех у кого аппаратное ускорение есть. Это стандартная рекомендация Google для nginx и она имеет смысл.

Обновление прошло без инцидентов, но потребовало ручной проверки на каждом хосте где nginx или другой сервис собирался с нестандартной OpenSSL. Автоматически «всё само обновилось» - не тот случай, когда ABI сломан.

Let's Encrypt и nginx мы уже подружили раньше - подробности в постах про certbot и nginx 1.11. OpenSSL 1.1.0 ложится в ту же линию: держать TLS-стек актуальным, не откладывая до момента когда что-то сломается само.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.