TLS e Nginx do kernel do Linux

Neste artigo, falarei sobre a história do desenvolvimento e o estado atual da tecnologia para acelerar a distribuição de conteúdo nas conexões TLS, transferindo a criptografia para o núcleo do sistema operacional, bem como sobre minha contribuição para o desenvolvimento dessa direção.

fundo


Em 2015, Randall Stewart e Scott Long, da Netflix, fizeram uma apresentação na conferência AsiaBSDCon2015 sobre a otimização da distribuição de conteúdo criptografado. A principal mensagem do relatório é transferir a criptografia de dados para o kernel do sistema operacional para reduzir o número de cópias de dados entre o espaço do kernel e o espaço do usuário e usar a chamada do sistema sendfile () otimizada e sem bloqueio. O tópico acabou sendo muito promissor e já na conferência Netdev 1.2 de 2016, Dave Watson, do Facebook, fez uma apresentação sobre a necessidade de criar soquetes TLS no kernel do Linux, e Boris Pismenny, Ilya Lesokhin e Liran Liss, da Mellanox, fizeram uma apresentaçãosobre a capacidade de usar a aceleração de hardware TLS em placas de rede. O tópico também foi discutido no HighLoad ++ 2017 por um palestrante da Tempesta Technologies.

Suporte ao kernel Linux


O resultado de todas essas conversas foi o surgimento do Kernel TLS no kernel Linux 4.13 (2017) com suporte para TLSv1.2 e a cifra AES128-GCM. Inicialmente, a criptografia apenas do tráfego de saída era suportada; o suporte à descriptografia apareceu mais tarde no kernel do Linux 4.17 (2018). Na versão 5.1, eles adicionaram suporte ao TLSv1.3 e AES256-GCM e na versão 5.2 também adicionaram a cifra AES128-CCM (2019).

Suporte no espaço do usuário


Em todos os relatórios mencionados acima, foi dito que apenas a criptografia de dados úteis pode ser colocada no kernel, e todas as aprovações e mensagens de controle TLS devem ser processadas da mesma forma no espaço do usuário. E para isso, uma versão modificada do OpenSSL foi usada. No entanto, no momento da publicação dos relatórios em domínio público, não havia informações sobre quais modificações nessa conhecida biblioteca precisavam ser feitas para dar suporte à funcionalidade. Talvez o único exemplo disponível de uso do Linux Kernel TLS tenha sido o artigo do blog Filippo Valsorda Jogando com o kernel TLS no Linux 4.13 e Go, que apareceu imediatamente após o lançamento do kernel Linux 4.13. E, embora tenha mostrado um exemplo válido do uso da tecnologia, não trouxe uma compreensão de como usar a tecnologia em projetos reais. Afinal, poucas pessoas escrevem um servidor WEB para seu projeto por conta própria, geralmente todo mundo usa ferramentas conhecidas e testadas pelo tempo.

Suporte no OpenSSL


As primeiras discussões sobre a tecnologia no OpenSSL apareceram no verão de 2017, pouco antes do lançamento do kernel Linux 4.13 ( PR 3631 ), mas o processo de discussão foi muito, muito lento, os primeiros comentários reais apareceram em outubro (após o lançamento do kernel 4.13) e a versão de trabalho realcomeçou a discutir em fevereiro de 2018. Quando todas as correções foram acordadas, a janela para adicionar novas funcionalidades no OpenSSL 1.1.1 foi fechada, e o suporte ao Kernel TLS foi movido para a próxima versão. Desde então, o suporte ao Kernel TLS RX foi adicionado, e SSL_sendfile () é uma chamada para o syscall correspondente com um pequeno processamento de possíveis situações no protocolo TLS. Mas agora em 2020, o OpenSSL 3.0 ainda não foi lançado, o TLSv1.3 é suportado pela grande maioria dos navegadores e a cifra AES128-GCM é ativamente substituída pelo AES256-GCM mais resistente. Então, tomei a liberdade e enviei uma solicitação de solicitação para dar suporte a novas cifras e ao TLSv1.3, na esperança de que elas a aceitassem antes do novo lançamento da biblioteca.

Suporte em servidores WEB


Mas o suporte ao TLS do Kernel na biblioteca TLS não é suficiente. Relatórios sobre a tecnologia disseram que é possível obter a máxima eficiência usando o envio sem copiar dados para o espaço do usuário - usando a chamada do sistema sendfile (). E o aplicativo do servidor deve ser capaz de distinguir entre as situações em que você pode usar o sendfile () em um soquete com o TLS e quando precisar fazer a “leitura da maneira antiga”, read () / SSL_write (). Algum progresso para adicionar funcionalidade ao Nginx apareceu em abril de 2019, mas nenhuma alteração foi aceita no código principal. A posição dos desenvolvedores é que a API para essas funções ainda não foi aprovada no OpenSSL, e o código real proposto no patch não parece ser portátil o suficiente para diferentes plataformas. Para ser sincero, o código não apenas não parece muito bom, mas também contém erros que impedem a criação do Nginx sem correções adicionais.Não consegui encontrar o suporte ao Kernel TLS em outros servidores da Web (talvez alguém tenha visto - me diga nos comentários).

E o que fazer?


Enquanto a comunidade aguarda o lançamento do OpenSSL 3.0, para começar a desenvolver o suporte ao TLS no Kernel no Nginx com uma API estável, segui o caminho contrário. No meu aconchegante canto do GitHub, fiz duas coisas:

  1. Criei um fork do OpenSSL e transportei tudo relacionado ao Kernel TLS para a versão estável do OpenSSL 1.1.1 (filial do OpenSSL_1_1_1-ktls). Especialmente para poder verificar a funcionalidade em condições de operação estável do restante da biblioteca. À medida que versões estáveis ​​se tornam disponíveis, tento fazer uma nova reformulação para que o garfo fique atualizado.
  2. Criei um fork do Nginx, no qual adicionei (com base em um patch da Mellanox) suporte para chamar SSL_sendfile () em condições em que isso é realmente possível e com as verificações de soquete SSL necessárias, e a capacidade de ativar / desativar a funcionalidade por meio da variável de configuração. Além desse recurso, no meu fork também existem vários patches que otimizam um pouco o trabalho do Nginx e corrigem alguns bugs (ramificação do recurso mestre). Na medida do possível, tento fazer uma nova recuperação com base na ramificação principal do repositório principal do Nginx, a fim de manter a bifurcação atualizada.

Convido todos a participarem dos testes. Comentários e correções no código podem ser lançados em Problemas no GitHub. Para construir este Nginx com este OpenSSL e o suporte ao TLS do Kernel incluído, adicione parâmetros ao script de configuração:

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

No momento, não tenho a oportunidade de testar esse pacote Nginx + OpenSSL sob carga pesada para confirmar o desempenho do comentário no patch Nginx; portanto, se de repente alguém puder medir a diferença na carga da CPU em altas velocidades de upload de arquivos, seria ótimo obter gráficos e adicionar em um artigo para uma compreensão visual do efeito.

All Articles