- Регистрация
- 12.04.17
- Сообщения
- 19.095
- Реакции
- 107
- Репутация
- 0
В этой статье я расскажу об истории развития и текущем состоянии технологии ускорения раздачи контента в TLS соединениях путем переноса шифрования в ядро операционной системы, а так же о своём вкладе в развитие этого направления.
Предыстория
В далеком 2015 году Randall Stewart и Scott Long из компании Netflix выступили на конференции AsiaBSDCon2015 c
Поддержка в ядре Linux
Итогом всех этих разговоров стало появление Kernel TLS в ядре Linux 4.13 (2017 год) c поддержкой TLSv1.2 и шифра AES128-GCM. Первоначально поддерживалось шифрование только исходящего трафика, поддержка дешифрования появилась позже в ядре Linux 4.17 (2018 год). В версии 5.1 добавили поддержку TLSv1.3 и AES256-GCM, а в версии 5.2 еще и шифр AES128-CCM (2019 год).
Поддержка в user-space
Во всех указанных выше докладах рассказывалось, что в ядро можно поместить только шифрование полезных данных, а все согласования и контрольные сообщения TLS необходимо обрабатывать всё так же в user-space. И для этого использовалась модифицированная версия OpenSSL. Однако на момент публикации докладов в открытом доступе не было информации о том, какие именно модификации в эту широкоизвестную библиотеку надо сделать, чтобы поддержать функционал. Пожалуй, единственным доступным примером использования Linux Kernel TLS была статья в блоге Filippo Valsorda
Поддержка в OpenSSL
Первые обсуждения технологии в OpenSSL появились летом 2017 года незадолго до выхода ядра Linux 4.13 (
Поддержка в WEB-серверах
Но поддержать Kernel TLS в TLS библиотеке мало. В докладах про технологию говорилось, что максимальную эффективность можно получить используя отправку без копирования данных в user-space — используя сискол sendfile(). И серверное приложение должно уметь различать ситуации, когда можно использовать sendfile() на сокете с TLS, а когда необходимо «по-старинке» делать read()/SSL_write(). Некоторые подвижки в сторону добавления функционала в Nginx появились в апреле 2019 года, но в основной код изменения приняты не были. Позиция разработчиков в том, что API для этих функиций в OpenSSL еще не утвержден, а собственно сам код, предложенный в патче, не выглядит достаточно портируемым на разные платформы. Скажу честно, код не только выглядит не очень красиво, но и содержит ошибки, которые не позволяют собрать Nginx без дополнительных исправлений. Поддержки Kernel TLS в других веб-серверах я вообще не смог найти (может быть кто-то видел — подскажите в комментах).
И что же делать?
Пока сообщество ожидает выхода релиза OpenSSL 3.0, чтобы начать разработку поддержки Kernel TLS в Nginx в условиях стабильного API, я пошел иным путём. В своёмуютном уголочке GitHub я сделал 2 вещи:
Предлагаю присоединиться к тестированию всех желающих. Замечания и исправления к коду можно кидать в Issues в GitHub. Собрать этот Nginx с этим OpenSSL и включенной поддержкой Kernel TLS можно добавив параметры к скрипту configure:
./configure --with-openssl= --with-openssl-opt="enable-ktls"
В настоящий момент у меня нет возможности протестировать эту связку Nginx + OpenSSL под серьезной нагрузкой, чтобы подтвердить показатели из коммента к патчу Nginx, поэтому если вдруг кто сможет замерить разницу в нагрузке на CPU на больших скоростях отдачи файлов — было бы здорово получить графики и добавить их в статью для визуального понимания эффекта.
Предыстория
В далеком 2015 году Randall Stewart и Scott Long из компании Netflix выступили на конференции AsiaBSDCon2015 c
You must be registered for see links
об оптимизации раздачи шифрованного контена. Основной посыл доклада — необходимо переносить шифрование данных в ядро операционной системы для уменьшения количества копирований данных между kernel-space и user-space и использовать оптимизированный неблокирующий сискол sendfile(). Тема оказалась очень перспективной и уже в 2016 году на конференции
You must be registered for see links
Dave Watson из Facebook выступил с
You must be registered for see links
о необходимости создания TLS сокетов в ядре Linux, а Boris Pismenny, Ilya Lesokhin и Liran Liss из Mellanox — с
You must be registered for see links
о возможности использовать аппаратное ускорение TLS в сетевых картах. Так же тема обсуждалась на HighLoad++ 2017 докладчиком от Tempesta Technologies.Поддержка в ядре Linux
Итогом всех этих разговоров стало появление Kernel TLS в ядре Linux 4.13 (2017 год) c поддержкой TLSv1.2 и шифра AES128-GCM. Первоначально поддерживалось шифрование только исходящего трафика, поддержка дешифрования появилась позже в ядре Linux 4.17 (2018 год). В версии 5.1 добавили поддержку TLSv1.3 и AES256-GCM, а в версии 5.2 еще и шифр AES128-CCM (2019 год).
Поддержка в user-space
Во всех указанных выше докладах рассказывалось, что в ядро можно поместить только шифрование полезных данных, а все согласования и контрольные сообщения TLS необходимо обрабатывать всё так же в user-space. И для этого использовалась модифицированная версия OpenSSL. Однако на момент публикации докладов в открытом доступе не было информации о том, какие именно модификации в эту широкоизвестную библиотеку надо сделать, чтобы поддержать функционал. Пожалуй, единственным доступным примером использования Linux Kernel TLS была статья в блоге Filippo Valsorda
You must be registered for see links
, появившаяся сразу после выхода ядра Linux 4.13. И, хотя она показывала действительный пример использования технологии, это не принесло понимания в то, как же использовать технологию в реальных проектах. Ведь очень мало кто самостоятельно пишет WEB-сервер для своего проекта, обычно все используют известные и проверенные временем инструменты.Поддержка в OpenSSL
Первые обсуждения технологии в OpenSSL появились летом 2017 года незадолго до выхода ядра Linux 4.13 (
You must be registered for see links
), однако процесс обсуждения шел очень и очень медленно, первые реальные замечания появились в октябре (уже после выхода ядра 4.13), а собственно
You must be registered for see links
начали обсуждать в феврале 2018. К моменту согласования всех исправлений, окно добавления нового функционала в OpenSSL 1.1.1 было закрыто, и поддержку Kernel TLS перенесли в следующий релиз. С того времени добавили поддежку Kernel TLS RX, и SSL_sendfile() — вызов соответствующего syscall с небольшой обработкой возможных ситуаций в протоколе TLS. Но сейчас на дворе 2020 год, OpenSSL 3.0 еще не вышел, TLSv1.3 поддерживается подавляющим большинством браузеров, а шифр AES128-GCM активно вытесняется более стойким AES256-GCM. Поэтому я взял на себя смелость и отправил
You must be registered for see links
на поддержку новых шифров и TLSv1.3 в надежде, что его примут до нового релиза библиотеки.Поддержка в WEB-серверах
Но поддержать Kernel TLS в TLS библиотеке мало. В докладах про технологию говорилось, что максимальную эффективность можно получить используя отправку без копирования данных в user-space — используя сискол sendfile(). И серверное приложение должно уметь различать ситуации, когда можно использовать sendfile() на сокете с TLS, а когда необходимо «по-старинке» делать read()/SSL_write(). Некоторые подвижки в сторону добавления функционала в Nginx появились в апреле 2019 года, но в основной код изменения приняты не были. Позиция разработчиков в том, что API для этих функиций в OpenSSL еще не утвержден, а собственно сам код, предложенный в патче, не выглядит достаточно портируемым на разные платформы. Скажу честно, код не только выглядит не очень красиво, но и содержит ошибки, которые не позволяют собрать Nginx без дополнительных исправлений. Поддержки Kernel TLS в других веб-серверах я вообще не смог найти (может быть кто-то видел — подскажите в комментах).
И что же делать?
Пока сообщество ожидает выхода релиза OpenSSL 3.0, чтобы начать разработку поддержки Kernel TLS в Nginx в условиях стабильного API, я пошел иным путём. В своём
- Создал
You must be registered for see linksOpenSSL и бэкпортировал всё связанное с Kernel TLS в стабильную версию OpenSSL 1.1.1 (ветка OpenSSL_1_1_1-ktls). Специально для того, чтобы иметь возможность проверять функционал в условиях стабильной работы остальной части библиотеки. По мере выхода стабильных версий стараюсь делать rebase, чтобы форк был актуальным.
- Создал
You must be registered for see linksNginx, в который добавил (на основе патча от Mellanox) поддержку вызова SSL_sendfile() в условиях, когда это действительно возможно и с необходимыми проверками SSL сокета, и возможность включения/выключения функционала через конфигурационную переменную. Помимо этой фичи в моем форке так же есть несколько патчей, немного оптимизирующих работу Nginx, и исправляющих некоторые баги (ветка master-feature). По мере возможностей я стараюсь делать rebase на основе master-ветки основного репо Nginx, чтобы поддерживать форк в условно-актуальном состоянии.
Предлагаю присоединиться к тестированию всех желающих. Замечания и исправления к коду можно кидать в Issues в GitHub. Собрать этот Nginx с этим OpenSSL и включенной поддержкой Kernel TLS можно добавив параметры к скрипту configure:
./configure --with-openssl= --with-openssl-opt="enable-ktls"
В настоящий момент у меня нет возможности протестировать эту связку Nginx + OpenSSL под серьезной нагрузкой, чтобы подтвердить показатели из коммента к патчу Nginx, поэтому если вдруг кто сможет замерить разницу в нагрузке на CPU на больших скоростях отдачи файлов — было бы здорово получить графики и добавить их в статью для визуального понимания эффекта.