Melhorando o desempenho do NGINX com Kernel TLS e SSL_sendfile( )

NGINX | 11 de novembro de 2021

O Transport Layer Security (TLS) é um protocolo criptográfico extremamente popular. A implementação do TLS no kernel (kTLS) melhora o desempenho ao reduzir significativamente a necessidade de operações de cópia entre o espaço do usuário e o kernel.

A combinação do kTLS com sendfile() faz com que os dados sejam criptografados diretamente no espaço do kernel antes de serem encaminhados à pilha de rede para transmissão. Isso elimina a necessidade de copiar os dados para o espaço do usuário para que sejam criptografados por bibliotecas TLS e, em seguida, copiá-los de volta para o espaço do kernel para transmissão. O kTLS também permite transferir o processamento TLS para o hardware, incluindo a transferência do processamento criptográfico simétrico do TLS para dispositivos de rede.

Os kernels modernos do Linux e do FreeBSD permitem transferir o processamento de TLS para o kernel, e agora o NGINX Open Source também! O NGINX 1.21.4 introduz suporte a kTLS ao fornecer arquivos estáticos e respostas armazenadas em cache com SSL_sendfile(), o que pode melhorar significativamente o desempenho. Conforme detalhado abaixo, tanto o kernel quanto o OpenSSL devem ser compilados com kTLS para que o NGINX possa usar SSL_sendfile().

Neste blog, detalhamos quais versões de sistemas operacionais e do OpenSSL são compatíveis com kTLS e mostramos como compilar e configurar o kernel e o NGINX para usar kTLS. Para dar uma ideia da melhoria de desempenho que você pode esperar com kTLS, também compartilhamos as especificações e os resultados dos nossos testes no FreeBSD e no Ubuntu.

Observação: as implementações de kTLS são bastante recentes e estão evoluindo rapidamente. Este blog descreve a compatibilidade com kTLS em novembro de 2021, mas fique atento aos anúncios no nginx.org e no blog da NGINX<.htmla> sobre alterações nas informações e instruções fornecidas aqui.

Requisitos gerais

  • Sistema operacional – qualquer um dos seguintes:
    • FreeBSD 13.0+. Desde novembro de 2021, o FreeBSD 13.0+ é o único sistema operacional compatível com kTLS no NGINX sem a necessidade de compilar manualmente o NGINX para incorporar o OpenSSL 3.0.0+. Consulte Como habilitar o NGINX com kTLS no FreeBSD.
    • Uma distribuição Linux baseada na versão 4.17 ou posterior do kernel Linux, embora recomendemos usar, sempre que possível, distribuições baseadas na versão 5.2 ou posterior. (Na verdade, o suporte a kTLS está disponível desde a versão 4.13, mas o OpenSSL 3.0.0 requer a versão 4.17 ou posterior dos cabeçalhos do kernel.)
  • OpenSSL – Versão 3.0.0 ou posterior
  • NGINX – Versão 1.21.4 ou posterior (mainline)[Editor – NGINX Plus R27 e versões posteriores oferecem suporte a kTLS em versões qualificadas de sistemas operacionais baseados em Linux; NGINX Plus R26 e versões posteriores oferecem esse suporte em versões qualificadas do FreeBSD. Para obter detalhes sobre os sistemas operacionais compatíveis, consulte a página de Versões do NGINX Plus.]

Suporte a sistemas operacionais

Sistemas operacionais compatíveis com kTLS

Em novembro de 2021, entre os sistemas operacionais compatíveis com o NGINX Open Source, os seguintes eram compatíveis com kTLS e com as cifras indicadas. Para obter detalhes sobre a compatibilidade com cifras, consulte Compatibilidade com cifras e o protocolo TLS.

 Cifras TLSv1.2Conjuntos de
cifras TLSv1.3
Cifra TLS_CHACHA20_POLY1305_SHA256Versão do kernel Linux
Amazon Linux 2*✅✅❌5.10
CentOS 8**✅❌❌4.18
FreeBSD 13.x✅✅❌ ***N/D
RHEL 8✅❌❌4.18
SLES 15 SP2✅✅✅5.3
Ubuntu 20.04 LTS✅❌​​❌5.4
Ubuntu 21.04✅✅✅5.11
Ubuntu 21.10✅✅✅5.13

* A versão do kernel deve ser a 5.10, e não a 4.14; consulte Sistemas operacionais que não oferecem suporte a kTLS e as Perguntas frequentes sobre o Amazon Linux 2
** Herda o status de suporte a kTLS do RHEL 8, no qual se baseia
*** Consulte o registro de commits do FreeBSD

Sistemas operacionais que não oferecem suporte a kTLS

Os sistemas operacionais a seguir não oferecem suporte a kTLS, pelo motivo indicado:

  • Alpine Linux 3.11–3.14 – O kernel é compilado com a opção CONFIG_TLS=n, o que impede a compilação do kTLS como um módulo ou como parte do kernel.
  • Amazon Linux 2 – a versão do kernel Linux é a 4.14 para a AMI padrão do Amazon Linux 2 (consulte as Perguntas frequentes sobre o Amazon Linux 2).
  • CentOS 7.4+ – A versão do kernel Linux é 3.10. Herda o status de suporte a kTLS do RHEL 7.4+, que é sua fonte upstream.
  • Debian 10 e 11 – O kernel é compilado com a opção CONFIG_TLS=n (consulte os logs do relatório de bug do Debian).
  • RHEL 7.4+ – A versão do kernel Linux é 3.10.
  • SLES 12 SP5+ – a versão do kernel Linux é 4.12.
  • Ubuntu 18.04 LTS – a versão do kernel Linux é 4.15.

Suporte a protocolos e cifras TLS

Conforme detalhado acima, os sistemas operacionais compatíveis com kTLS variam quanto ao suporte a protocolos TLS e conjuntos de cifras.

Com o TLSv1.2, o módulo kTLS oferece suporte às seguintes cifras:

  • AES128-GCM-SHA256
  • AES256-GCM-SHA384
  • ECDHE-RSA-AES128-GCM-SHA256
  • ECDHE-RSA-AES256-GCM-SHA384

Com o TLSv1.3, o módulo kTLS oferece suporte aos seguintes conjuntos de cifras:

Para verificar quais cifras TLS compatíveis com o OpenSSL estão habilitadas no seu binário do NGINX, execute o comando openssl-3.0.0/.openssl/bin/openssl ciphers no diretório em que você compilou o NGINX (por exemplo, seu diretório pessoal).

Habilitando o kTLS no NGINX

Como mencionado na introdução, o kTLS melhora o desempenho do NGINX porque toda a criptografia e descriptografia ocorrem no kernel. Os dados são criptografados diretamente no espaço do kernel – antes de serem encaminhados à pilha de rede para transmissão –, eliminando a necessidade de copiá-los para o espaço do usuário a fim de serem criptografados por bibliotecas TLS e, em seguida, copiá-los de volta para o espaço do kernel para transmissão.

Diagrama do TLS no kernel (kTLS) com o NGINX

Carregando o kTLS no kernel

Nas distribuições modernas do FreeBSD e do Linux, o kTLS geralmente é compilado como um módulo (com a opção CONFIG_TLS=m). É necessário carregar explicitamente o módulo kTLS no kernel antes de iniciar o NGINX.

  • No FreeBSD, execute estes comandos como o usuário root:
# kldload ktls_ocf.ko# sysctl kern.ipc.tls.enable=1
  • Para obter detalhes sobre as opções de comando do FreeBSD, consulte a página do manual de ktls(4).
  • Em distribuições Linux, execute este comando como usuário root:
# modprobe tls

Habilitando o NGINX com kTLS no FreeBSD

Para habilitar o suporte a kTLS no NGINX no FreeBSD, você pode seguir as mesmas instruções usadas para distribuições Linux. No entanto, recomendamos que você execute as etapas a seguir para aproveitar a compilação do NGINX com kTLS disponível no port security/openssl-devel da Coleção de Ports do FreeBSD. Para obter mais informações, incluindo uma visão geral do kTLS, consulte Descarregamento de TLS no kernel no site do FreeBSD.

  1. Compile o OpenSSL 3.0 com suporte a kTLS, selecionando as opções apropriadas no menu de configuração:
# cd /usr/ports/security/openssl-devel && make config && make install
  1. Modifique /etc/make.conf para usar openssl-devel como a biblioteca SSL padrão:
# echo "DEFAULT_VERSIONS+=ssl=openssl-devel" >> /etc/make.conf
  1. Compile o NGINX:
# cd /usr/ports/www/nginx-devel && make install

Compilando o NGINX com kTLS em distribuições Linux

A maioria das distribuições Linux atuais inclui uma versão do OpenSSL anterior à 3.0.0 (geralmente, a versão 1.1). Portanto, é necessário compilar o NGINX a partir do código-fonte com o OpenSSL 3.0.0.

As duas opções essenciais do comando configure que habilitam o suporte a kTLS são:

  • --with-openssl=../openssl-3.0.0
  • --with-openssl-opt=enable-ktls

As outras opções de configure são destinadas aos módulos incluídos nos pacotes binários oficiais do NGINX disponíveis em nginx.org. Como alternativa, você pode especificar um conjunto personalizado de módulos. Para ver as opções de compilação usadas no seu binário atual do NGINX, execute nginx -V.

Para compilar o NGINX com o OpenSSL 3.0.0, execute os seguintes comandos:

$ wget https://nginx.org/download/nginx-1.21.4.tar.gz$ wget https://www.openssl.org/source/openssl-3.0.0.tar.gz$ tar xzf openssl-3.0.0.tar.gz$ cd nginx-1.21.4$ ./configure --with-debug --prefix=/usr/local --conf-path=/usr/local/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-openssl=../openssl-3.0.0 --with-openssl-opt=enable-ktls --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' -with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'$ make –j4$ make install

Observação: O binário do NGINX resultante é vinculado estaticamente às bibliotecas do OpenSSL 3.0.0. Se posteriormente você precisar aplicar uma correção ao OpenSSL, deverá baixar e descompactar o novo arquivo de código-fonte do OpenSSL e, em seguida, executar os comandos acima para recompilar o binário do NGINX.

Configurando o NGINX

Para habilitar o kTLS, inclua a diretiva ssl_conf_command com o parâmetro Options KTLS no contexto server{}, como nesta configuração de exemplo usada em nossos testes:

worker_processes auto;error_log /var/log/nginx/error.log debug;events {}http {    sendfile on;    server {        listen 443 ssl;        ssl_certificate ssl/example.crt;        ssl_certificate_key ssl/example.key;        ssl_conf_command Options KTLS;        ssl_protocols TLSv1.3;        location / {            root /data;    	}    }}

Verificando se o kTLS está habilitado

Para verificar se o NGINX está usando kTLS, ative o modo de depuração e verifique se há ocorrências de BIO_get_ktls_send() e SSL_sendfile() no log de erros.

$ grep BIO /var/log/nginx/error.log2021/11/10 16:02:46 [debug] 274550#274550: *2 BIO_get_ktls_send(): 12021/11/10 16:02:49 [debug] 274550#274550: *3 BIO_get_ktls_send(): 1 $ grep SSL_sendfile /var/log/nginx/error.log2021/11/10 16:02:46 [debug] 274550#274550: *2 SSL_sendfile: 10485762021/11/10 16:02:49 [debug] 274550#274550: *3 SSL_sendfile: 1048576

Observação: Recomendamos desativar o modo de depuração após realizar essas verificações, especialmente em ambientes de produção. O registro em log de depuração causa perda de desempenho devido ao grande volume de operações de gravação. Além disso, os logs de depuração podem ser enormes e esgotar rapidamente o espaço disponível na partição do disco.

Melhoria de desempenho com kTLS

Ao disponibilizar arquivos estáticos e respostas em cache sob carga intensa, SSL_sendfile() pode aumentar a taxa de transferência em até 2x em comparação com o TLS no espaço do usuário, mas o ganho de desempenho depende significativamente de vários fatores (desempenho do disco, carga do sistema etc.). Também é possível reduzir o uso da CPU se a sua placa de rede for compatível com o descarregamento de TLS.

Testando o desempenho

Para medir o ganho de desempenho na sua configuração, siga as instruções abaixo para executar um teste simples com uma única thread. Conforme detalhado a seguir, os resultados dos nossos testes indicam um ganho de desempenho de quase 30%, sem nenhum ajuste específico.

Hardware e software utilizados:

  • Instância t3.medium da AWS com:
    • 4 GB de RAM
    • SSD de uso geral de 20 GB
    • CPU Intel® Xeon® Platinum 8259CL de 2,50 GHz com 2 núcleos
  • FreeBSD 13.0 e Ubuntu 21.10
  • TLSv1.3 com o conjunto de cifras TLS_AES_256_GCM_SHA384 cipher suite
  • NGINX 1.21.4, compilado e configurado conforme especificado em Como habilitar o kTLS no NGINX.

Para realizar o teste:

  1. Crie um arquivo grande que caiba completamente no cache de disco:
# truncate -s 1g /data/1G
  1. Execute este comando para verificar a taxa de transferência; o comando base é repetido várias vezes para obter resultados mais precisos. Redirecione a saída para o utilitário ministat[FreeBSD][Ubuntu] para realizar uma análise estatística básica.
# for i in 'seq 1 100'; do curl -k -s -o /dev/null -w '%{speed_download}n' https://localhost/1G | ministat

Resultados dos testes de desempenho

Nos resultados dos nossos testes a seguir, apresentados como saída do ministat, cada valor representa a velocidade de download em kBytes/segundo. A saída foi dividida em duas linhas para facilitar a leitura.

Taxa de transferência do FreeBSD 13.0 sem kTLS:

    N           Min           Max        Median     ...x  10        532225        573348        555616     ...     ...      Avg        Stddev     ... 555155.6     10239.137

Taxa de transferência do FreeBSD 13.0 com kTLS:

    N           Min           Max        Median     ...x  10        629379        723164        717349     ...         ...      Avg        Stddev   ... 708600.4     28304.766

Taxa de transferência no Ubuntu 21.10 sem kTLS:

    N           Min           Max        Median     ...x  10        529199        705720        662354     ...         ...      Avg        Stddev   ... 654321.6     48025.103

Taxa de transferência no Ubuntu 21.10 com kTLS:

    N           Min           Max        Median     ...x  10        619105        760208        756278     ...         ...      Avg        Stddev   ... 741848.3     43255.246

Em nossos testes, o kTLS melhorou mais o desempenho no FreeBSD do que no Ubuntu. O aumento percentual foi o seguinte:

 Mín.Máx.MedianaMédia
FreeBSD 13.018%26%29%28%
Ubuntu 21.1016%8%14%13%

Resumo

O NGINX 1.21.4 introduz suporte a kTLS ao fornecer arquivos estáticos e respostas armazenadas em cache com SSL_sendfile(). Nossos testes mostram que o desempenho melhora entre 8% e 29%, dependendo do sistema operacional.

Queremos saber mais sobre suas experiências com o kTLS e o NGINX, especialmente os resultados dos seus testes em outros sistemas operacionais! Compartilhe-os na seção de comentários abaixo.


Compartilhar

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade

Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
NGINX | 17/06/2024

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa

Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
NGINX | 14/07/2021

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor

Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
NGINX | 02/04/2019

Distribuição segura de chaves privadas SSL com o NGINX

Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
NGINX | 24/05/2018

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX

O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
NGINX | 19/04/2016

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus

Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.