Linux Kernel TLS и Nginx

    В этой статье я расскажу об истории развития и текущем состоянии технологии ускорения раздачи контента в TLS соединениях путем переноса шифрования в ядро операционной системы, а так же о своём вкладе в развитие этого направления.

    Предыстория


    В далеком 2015 году Randall Stewart и Scott Long из компании Netflix выступили на конференции AsiaBSDCon2015 c докладом об оптимизации раздачи шифрованного контента. Основной посыл доклада — необходимо переносить шифрование данных в ядро операционной системы для уменьшения количества копирований данных между kernel-space и user-space и использовать оптимизированный неблокирующий системный вызов sendfile(). Тема оказалась очень перспективной и уже в 2016 году на конференции Netdev 1.2 Dave Watson из Facebook выступил с докладом о необходимости создания TLS сокетов в ядре Linux, а Boris Pismenny, Ilya Lesokhin и Liran Liss из Mellanox — с докладом о возможности использовать аппаратное ускорение 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 Playing with kernel TLS in Linux 4.13 and Go, появившаяся сразу после выхода ядра Linux 4.13. И, хотя она показывала действительный пример использования технологии, это не принесло понимания в то, как же использовать технологию в реальных проектах. Ведь очень мало кто самостоятельно пишет WEB-сервер для своего проекта, обычно все используют известные и проверенные временем инструменты.

    Поддержка в OpenSSL


    Первые обсуждения технологии в OpenSSL появились летом 2017 года незадолго до выхода ядра Linux 4.13 (PR 3631), однако процесс обсуждения шел очень и очень медленно, первые реальные замечания появились в октябре (уже после выхода ядра 4.13), а собственно рабочий вариант начали обсуждать в феврале 2018. К моменту согласования всех исправлений, окно добавления нового функционала в OpenSSL 1.1.1 было закрыто, и поддержку Kernel TLS перенесли в следующий релиз. С того времени добавили поддежку Kernel TLS RX, и SSL_sendfile() — вызов соответствующего syscall с небольшой обработкой возможных ситуаций в протоколе TLS. Но сейчас на дворе 2020 год, OpenSSL 3.0 еще не вышел, TLSv1.3 поддерживается подавляющим большинством браузеров, а шифр AES128-GCM активно вытесняется более стойким AES256-GCM. Поэтому я взял на себя смелость и отправил Pull Request на поддержку новых шифров и 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, я пошел иным путём. В своём уютном уголочке GitHub я сделал 2 вещи:

    1. Создал форк OpenSSL и бэкпортировал всё связанное с Kernel TLS в стабильную версию OpenSSL 1.1.1 (ветка OpenSSL_1_1_1-ktls). Специально для того, чтобы иметь возможность проверять функционал в условиях стабильной работы остальной части библиотеки. По мере выхода стабильных версий стараюсь делать rebase, чтобы форк был актуальным.
    2. Создал форк Nginx, в который добавил (на основе патча от Mellanox) поддержку вызова SSL_sendfile() в условиях, когда это действительно возможно и с необходимыми проверками SSL сокета, и возможность включения/выключения функционала через конфигурационную переменную. Помимо этой фичи в моем форке так же есть несколько патчей, немного оптимизирующих работу Nginx, и исправляющих некоторые баги (ветка master-feature). По мере возможностей я стараюсь делать rebase на основе master-ветки основного репо Nginx, чтобы поддерживать форк в условно-актуальном состоянии.

    Предлагаю всем желающим принять участие в тестировании. Замечания и исправления к коду можно кидать в Issues в GitHub. Собрать этот Nginx с этим OpenSSL и включенной поддержкой Kernel TLS можно добавив параметры к скрипту configure:

    ./configure --with-openssl=<OpenSSL-fork-dir> --with-openssl-opt="enable-ktls"
    

    В настоящий момент у меня нет возможности протестировать эту связку Nginx + OpenSSL под серьезной нагрузкой, чтобы подтвердить показатели из коммента к патчу Nginx, поэтому если вдруг кто сможет замерить разницу в нагрузке на CPU на больших скоростях отдачи файлов — было бы здорово получить графики и добавить их в статью для визуального понимания эффекта.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 20

      +2

      На данный момент много проектов смотрят на kernel TLS. Он может сильно изменить имеющиеся стандарты. Например, nfs over tls, который активно развивается, может вытеснить керберос на СХД.

        0
        Теоретически, выгоду могут получить любые проекты, использующие TLS. вот сразу в голову пришло — тот же Postfix MTA, всё пересылку ведет через файлы, умеет использовать sendfile, но в режиме TLS такое не поддерживает.
        Но меня больше интересуют проекты, в которых уже была реализована поддержка. Правда, я больше искал в направлении WEB-серверов, возможно проекты в других направлениях используют.
        +1

        а в чём выгода от переноса шифрования в kernel-space?
        избавиться от копирования в userspace? так (кроме отдачи статики) данные обычно из userspace приходят.
        использовать аппаратное шифрование? а насколько оно хорошо будет работать с 100500 одновременными сессиями?

          +2
          Выгода действительно в том, чтобы избавиться от копирования при отдаче статичного контента. В основном это раздача on-line видео. В этой заметке Netfilx довольно глубоко описывают профит.
          Использование аппаратного шифрования в сетевой карте — это достаточно новая тема. Mellanox предлагает такое только в своих ConnectX-6 DX, которые имеют интерфейсы 2х100 Gbit или 1х200 Gbit. На таких скоростях даже «дешевое» шифрование с использованием AES-NI будет потреблять значительную количество CPU, которое можно было бы использовать в более нужных вещах. Насколько оно хорошо работает — это, конечно, вопрос. Но не думаю, что в этом проблема будет, потому что офлоадить IPSec с множеством соединений научились еще в Intel 82599, а шифрование потока в TLS не сильно отличается.
            –1
            Выгода действительно в том, чтобы избавиться от копирования при отдаче статичного контента.

            ну это лишь один из возможных сценариев использования nginx, мне кажется, что далеко не самый распространённый.
            в случае «nginx проксирует и обеспечивает tls» выигрыша, думаю, ждать не стоит.


            На таких скоростях даже «дешевое» шифрование с использованием AES-NI будет потреблять значительную количество CPU, которое можно было бы использовать в более нужных вещах. Насколько оно хорошо работает — это, конечно, вопрос.

            имелось в виду не "будет ли работать", а "будет ли профит в случае множества относительно медленных клиентов", очевидно, что хранить состояние всех сессий в сетевой карте невозможно, не убьёт ли производительность то, что контекст придётся постоянно передавать в сетевую карту/из сетевой (что-то вроде context switch в OS).


            хотя… сетевая карта имеет же доступ к памяти, наверное, эта проблема решаема (и даже уже решена).


            Update: прочитал pdf от мелланокса


            • NIC holds the crypto state
            • NIC encrypts / decrypts packets on the fly
            • Cipher text is never held in RAM

            всё-таки непонятно сколько одновременных соединений «вытянет» сетевая карта.


            и да, в той статье есть таблица, где у kTLS без аппаратного ускорения производительность оказалась ниже, чем в userspace (это я возвращаюсь к вопросу "будет ли выигрыш если исходные данные в userspace")

              0
              имелось в виду не «будет ли работать», а «будет ли профит в случае множества относительно медленных клиентов», очевидно, что хранить состояние всех сессий в сетевой карте невозможно, не убьёт ли производительность то, что контекст придётся постоянно передавать в сетевую карту/из сетевой (что-то вроде context switch в OS).

              Конкретно у Mellanox в их Crypto-enabled BlueField воткнут «64-bit Armv8 A72» на 16 ядер и 16GB оперативки. Всё это с отдельным интерконнектом в собственно сетевой чип, поэтому вполне можно держать все сессии. Быстро перепрограммировать сетевой чип из BlueField точно умеют, а про передавать контекст в карту/из карты — это в общем случае надо делать только на старте сессии. Карта умеет трекать TCP Seq Number, и TLS Record Number. Соответственно от ядра нужно только получать данные на отправку.
              Тут, кстати, нашел доку по картам Chelsio. У них указывается «The typical T6 adapter supports 32K simultaneous TLS/SSLsessions.» — вполне неплохая цифра одновременных TLS соединений.
              в случае «nginx проксирует и обеспечивает tls» выигрыша, думаю, ждать не стоит.

              По первым тестам использование шифрования в ядре без использования sendfile() давало несколько процентов производительности, но сейчас подтвердить или опровергнуть эти данные не могу — не получается быстро найти статью с картинками сравнения.
              А можно ссылочку на статью, где производительность Kernel TLS просела относительно user-space?
                0
                А можно ссылочку на статью, где производительность Kernel TLS просела относительно user-space?

                так из вашей статьи и взял — доклад mellanox

                  0

                  Ну вы учитывайте что Mellanox-у нужно продавать свое железо с offload.
                  Поэтому сейлы Mellanox будут "накручивать" цифры всеми приемлемыми способами.
                  Например, выбирать для тестов версии ядра, комбинации опций и софта показывающие что без offload "жить нельзя".

                    0

                    Да, точно. Но тут сравнение с Gnu TLS c малым размером TLS Record, который умещается в один TCP пакет. Такое поведение не самое распространенное, и не позволяет использовать механизмы GSO и TSO в ядре. Ну и версия kTLS там правда очень древняя. Была еще статья, в которой сравнивался OpenSSL (кажется 1.1.0) в более честных условиях, там были изменения в обратную сторону, но незначительные

                  0
                  и да, в той статье есть таблица, где у kTLS без аппаратного ускорения производительность оказалась ниже, чем в userspace (это я возвращаюсь к вопросу «будет ли выигрыш если исходные данные в userspace»)

                  Это одна из первых статей, после этого в ядре было несколько итераций оптимизации кода AES. Но я не берусь утверждать, что стало сильно лучше, вероятнее всего при проксировании действительно профита видно не будет

                0

                Бонусов несколько.


                Во-первых это развитие, приведение в порядок и оптимизация механизмов off-load. AES относительно дешево реализуется в железе, а перенос шифрования с CPU на NIC позволяет увеличить производительность отдачи контента в разы. На всякий стоит пояснить:


                • Когда шифрованием занимается CPU, то ему нужно (как минимум) прочитать данные из памяти, затем зашифровать и записать в память, а потом снова прочитать через DMA сетевой картой.
                • Если же шифрованием занимает NIC, то можно обойтись однократным чтением из памяти.
                • Т.е. утилизация RAM bandwidth получается в три раза меньше, и это не считая затрат CPU на само шифрование и управление буферами для зашифрованных данных. Соответственно, условный Netflix сможет раздавать со своих блейдов в три раза больше, и/или использовать менее мощные, более холодные и дешевые процессоры (ARM).

                Без AES-offload в NIC выигрыш скромнее, но всё же есть. В основном за счет уменьшения кол-ва переключений между ядром и userspace — примерно также как при использовании "обычного" системного вызова sendfile.


                Возможно vadimfedorenko стоит добавить эту инфу в статью.

                  0
                  Т.е. утилизация RAM bandwidth получается в три раза меньше, и это не считая затрат CPU на само шифрование и управление буферами для зашифрованных данных. Соответственно, условный Netflix сможет раздавать со своих блейдов в три раза больше, и/или использовать менее мощные, более холодные и дешевые процессоры (ARM)

                  ну тут вы утрируете, конечно, если бы скорость отдачи была равна (memory bandwidth)/3, все были бы счастливы )


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


                  Без AES-offload в NIC выигрыш скромнее, но всё же есть. В основном за счет уменьшения кол-ва переключений между ядром и userspace — примерно также как при использовании "обычного" системного вызова sendfile.

                  это только в том случае, если данные не проходят через userspace, а они зачастую таки проходят.


                  так-то понятно, что связка (sendfile/sockmap/etc) + ktls выглядит интересно с точки зрения производительности. и аппаратное шифрование тут будет актуально.


                  P.S. речь про то, что после прочтения статьи возникает ощущение «у меня есть nginx и есть tls — значит оно мне надо». а может оказаться, что не надо )

                    +2
                    ну тут вы утрируете, конечно, если бы скорость отдачи была равна (memory bandwidth)/3, все были бы счастливы )

                    Есть разные сценарии.


                    К примеру, если у вас CDN большого масштаба, то ваша целевое состояние = минимальное кол-во работающих серверов с загрузкой ~95%.
                    Соответственно, в целевом (эффективном) состоянии, на таких серверах вы будите упираться либо в disk i/o (для "холодного" контента), либо в memory bandwidth (для "горячего" контента).


                    Конечно это не массовый сценарий, но в любом случае нормальный offload для AES действительно поднимает верхний предел отдачи в три раза. Это позволяет не только увидеть другие узкие места, но и делает осмысленным их устранение.

                      +1
                      Зависит от CDN, но могу сказать, что CPU остается достаточно много. Больше баланс сетевой нагрузки и размера диска. Offload в NIC как таковой не нужен, потому что CPU именно и занимается шифрованием как раз.
                        0

                        Сильно зависит от количества обслуживающих серверов в PoP. Речь же идет о том, чтобы максимально раздавать с одного сервера, а не закатывать полные стойки серверов в IX.

                          0
                          Все правильно, естественно ресурсы должны максимально использоваться. Но ресурсов много. Память была упомянута выше. Я упомянул диски как одну из реальных проблем для большого CDN с большим количеством клиентов. Диски — не очень дешевое удовольствие тоже. Если разгрузить CPU, то придется другие вещи расширять. Но реально те же диски большего размера стоят дороже, к примеру.
                          0

                          Не хочу вступать в дискуссию, но если у вас чего-то остается много, то вы за это переплатили.


                          И на всякий уточню:


                          • понятно, что далеко не всегда есть возможность не покупать лишнего, просто исходя из доступного спектра моделей и других обстоятельств.
                          • в перспективе Mellanox (или еще кто-нибудь) смогут пустить offload в серию и снизить цены, соответственно блейды на ARM-ах станут дешевле и будут ближе к оптимуму (без лишних мощностей и холоднее).
                          • чтобы это было возможно инфраструктуру offload в ядре нужно допиливать, что понемногу и происходит.
                            0
                            Я говорил к тому, что CPU на CDN особо ни для чего не используется. Поэтому смысл покупать CPU чтобы он простаивал. Там 80 ядер или сколько в сервере, почему бы им не заняться шифрованием?
                            Но абсолютно ясно, что не хочется доплачивать за что-то, что не используется. Но в реальности есть куча переменных, таких как размер дисков, количество клиентов, региональная нагрузка на определенном PoP-е, стратегия кэширования (например, стратегия кэширования видео сильно сказывается на вытеснении кэша). К этому добавляется неидеальность софта тоже.
                  0
                  Интересно, надо вам статью так же в англоязычный интеренет закинуть
                    +1
                    да, надеюсь будет время перевести

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое