Linux Kernel TLS y Nginx

En este artículo hablaré sobre la historia del desarrollo y el estado actual de la tecnología para acelerar la distribución de contenido en conexiones TLS mediante la transferencia de cifrado al núcleo del sistema operativo, así como sobre mi contribución al desarrollo de esta dirección.

Antecedentes


En 2015, Randall Stewart y Scott Long de Netflix hicieron una presentación en la conferencia AsiaBSDCon2015 sobre la optimización de la distribución de contenido encriptado. El mensaje principal del informe es transferir el cifrado de datos al kernel del sistema operativo para reducir la cantidad de copias de datos entre kernel-space y user-space y utilizar la llamada optimizada del sistema sendfile () sin bloqueo. El tema resultó ser muy prometedor y ya en la conferencia Netdev 1.2 2016, Dave Watson de Facebook hizo una presentación sobre la necesidad de crear sockets TLS en el kernel de Linux, y Boris Pismenny, Ilya Lesokhin y Liran Liss de Mellanox hicieron una presentación.sobre la capacidad de usar la aceleración de hardware TLS en tarjetas de red. El tema también fue discutido en HighLoad ++ 2017 por un orador de Tempesta Technologies.

Soporte de kernel de Linux


El resultado de todas estas conversaciones fue la aparición de Kernel TLS en el kernel Linux 4.13 (2017) con soporte para TLSv1.2 y el cifrado AES128-GCM. Inicialmente, solo se admitía el cifrado del tráfico saliente, el soporte de descifrado apareció más tarde en el kernel de Linux 4.17 (2018). En la versión 5.1, agregaron soporte para TLSv1.3 y AES256-GCM, y en la versión 5.2 también agregaron el cifrado AES128-CCM (2019).

Apoyo en espacio de usuario


En todos los informes mencionados anteriormente, se dijo que solo el cifrado de datos útiles se puede colocar en el núcleo, y todas las aprobaciones de TLS y los mensajes de control deben procesarse de la misma manera en el espacio del usuario. Y para esto, se utilizó una versión modificada de OpenSSL. Sin embargo, en el momento de la publicación de los informes en el dominio público, no había información sobre qué modificaciones a esta conocida biblioteca debían realizarse para admitir la funcionalidad. Quizás el único ejemplo disponible del uso de Linux Kernel TLS fue el artículo del blog Filippo Valsorda Playing with kernel TLS en Linux 4.13 y Go, que apareció inmediatamente después del lanzamiento del núcleo Linux 4.13. Y, aunque mostró un ejemplo válido del uso de la tecnología, no trajo una comprensión de cómo usar la tecnología en proyectos reales. Después de todo, muy pocas personas escriben un servidor WEB para su proyecto por su cuenta, generalmente todos usan herramientas conocidas y probadas.

Soporte en OpenSSL


Las primeras discusiones sobre la tecnología en OpenSSL aparecieron en el verano de 2017, poco antes del lanzamiento del kernel Linux 4.13 ( PR 3631 ), sin embargo, el proceso de discusión fue muy, muy lento, los primeros comentarios reales aparecieron en octubre (después del lanzamiento del kernel 4.13), y en realidad la versión de trabajocomenzó a debatir en febrero de 2018. Para cuando se acordaron todas las correcciones, se cerró la ventana para agregar nuevas funciones en OpenSSL 1.1.1 y el soporte para Kernel TLS se trasladó a la próxima versión. Desde ese momento, se ha agregado el soporte Kernel TLS RX, y SSL_sendfile () es una llamada a la llamada al sistema correspondiente con un pequeño procesamiento de posibles situaciones en el protocolo TLS. Pero ahora en 2020, OpenSSL 3.0 aún no se ha lanzado, TLSv1.3 es compatible con la gran mayoría de los navegadores, y el cifrado AES128-GCM se reemplaza activamente por el AES256-GCM más resistente. Así que me tomé la libertad y envié una solicitud de extracción para admitir nuevos cifrados y TLSv1.3 con la esperanza de que lo aceptaran antes del nuevo lanzamiento de la biblioteca.

Soporte en servidores WEB


Pero soportar Kernel TLS en la biblioteca TLS no es suficiente. Los informes sobre la tecnología dicen que se puede obtener la máxima eficiencia utilizando el envío sin copiar datos al espacio del usuario, utilizando la llamada al sistema sendfile (). Y la aplicación del servidor debe poder distinguir entre situaciones en las que puede usar sendfile () en un socket con TLS, y cuando necesita hacer "read the old way" read () / SSL_write (). En abril de 2019 apareció un cierto progreso hacia la adición de funcionalidad a Nginx, pero no se aceptaron cambios en el código principal. La posición de los desarrolladores es que la API para estas funciones aún no está aprobada en OpenSSL, y el código real propuesto en el parche no parece ser lo suficientemente portátil para diferentes plataformas. Para ser sincero, el código no solo no se ve muy bien, sino que también contiene errores que impiden que Nginx se cree sin correcciones adicionales.No pude encontrar el soporte de Kernel TLS en otros servidores web (tal vez alguien lo vio, dígame en los comentarios).

¿Y que hacer?


Mientras la comunidad está esperando el lanzamiento de OpenSSL 3.0, para comenzar a desarrollar el soporte para Kernel TLS en Nginx con una API estable, yo fui en sentido contrario. En mi rincón acogedor de GitHub, hice 2 cosas:

  1. Creé una bifurcación OpenSSL y exporté todo lo relacionado con Kernel TLS a la versión estable de OpenSSL 1.1.1 (rama OpenSSL_1_1_1-ktls). Especialmente para poder verificar la funcionalidad en condiciones de funcionamiento estable del resto de la biblioteca. A medida que las versiones estables están disponibles, trato de cambiar la base para que el fork esté actualizado.
  2. Creé una bifurcación de Nginx, en la que agregué (basado en un parche de Mellanox) soporte para llamar a SSL_sendfile () en condiciones cuando es realmente posible y con las comprobaciones de socket SSL necesarias, y la capacidad de habilitar / deshabilitar la funcionalidad a través de la variable de configuración. Además de esta característica, en mi bifurcación también hay varios parches que optimizan un poco el trabajo de Nginx y corrigen algunos errores (rama de característica maestra). En la medida de lo posible, trato de volver a crear una base basada en la rama maestra del repositorio principal de Nginx, para mantener la bifurcación actualizada.

Invito a todos a participar en las pruebas. Se pueden enviar comentarios y correcciones al código en Issues on GitHub. Para construir este Nginx con este OpenSSL y el soporte Kernel TLS incluido, agregue parámetros al script de configuración:

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

Por el momento, no tengo la oportunidad de probar este paquete Nginx + OpenSSL bajo una gran carga para confirmar el rendimiento del comentario en el parche Nginx, por lo que si de repente alguien puede medir la diferencia en la carga de la CPU a altas velocidades de carga de archivos, sería genial obtener gráficos y agregar ellos en un artículo para una comprensión visual del efecto.

All Articles