Cómo comprobar y restaurar AES-NI en un VPS
Comprueba si tu VPS expone AES-NI, mide cuánto reduce el rendimiento AES-GCM un CPUID oculto y restaura la ruta rápida con OPENSSL_ia32cap.
Qué aporta realmente AES-NI en un VPS
AES-NI es un conjunto de seis instrucciones x86 que ejecutan en hardware una ronda de AES (estándar de cifrado avanzado). Si el modelo de CPU que muestra el proveedor oculta estas instrucciones, el silicio subyacente sigue incluyéndolas, pero OpenSSL no puede verlas y utiliza una implementación de software que consume aproximadamente diez veces más ciclos por byte. Puede comprobar la característica con un comando, medir la diferencia con dos y, a menudo, volver a activar la ruta rápida con una variable de entorno.
Las instrucciones son AESENC, AESENCLAST, AESDEC, AESDECLAST, AESIMC y AESKEYGENASSIST. Intel las incorporó en 2010 y AMD hizo lo mismo después, por lo que cualquier CPU de servidor que probablemente alquile ya incluye esta capacidad en el silicio. Una instrucción complementaria, PCLMULQDQ, realiza una multiplicación sin acarreo, que es lo que GCM (modo Galois/contador) necesita para generar su etiqueta de autenticación. AES-GCM sólo es rápido cuando ambas están disponibles, porque el cifrado y la etiqueta son tareas independientes.
Cuatro situaciones de un VPS en las que esto se refleja en la monitorización:
- Terminación de TLS (seguridad de la capa de transporte). Un servidor web que entrega AES-128-GCM o AES-256-GCM dedica la mayor parte del tiempo de criptografía de datos a AES.
- Volúmenes cifrados. LUKS (configuración unificada de claves de Linux) y dm-crypt ejecutan
aes-xtsen cada lectura y cada escritura, dentro del kernel y sobre la CPU. - Tráfico VPN basado en AES. OpenVPN con
AES-256-GCMe IPsec con AES-GCM dependen de esta capacidad. - Copias de seguridad cifradas. Cualquier herramienta que cifre un flujo con AES antes de sacarlo del servidor asume el mismo coste.
Una carga de trabajo habitual no se ve afectada. WireGuard utiliza ChaCha20-Poly1305 para sus datos y nunca usa AES, por lo que una VPN WireGuard autogestionada funciona a la misma velocidad en un host donde la marca está ocultada. Esta diferencia es un motivo práctico para valorar WireGuard frente a OpenVPN antes de elegir un túnel para un VPS económico.
Cómo comprobar si tu VPS tiene AES-NI
El kernel copia los bits de características de CPUID en /proc/cpuinfo, por lo que un solo grep responde a la pregunta.
grep -m1 -o '\baes\b' /proc/cpuinfo
lscpu | grep -i -o '\baes\b'Cualquiera de los dos comandos que muestre aes indica que la CPU anuncia AES-NI a este guest. Si no muestra nada, no lo anuncia. lscpu lee los mismos flags, por lo que ambos comandos siempre coinciden. Usa el que esté instalado.
Ahora comprueba qué CPU indica el host que estás usando.
grep -m1 'model name' /proc/cpuinfoUna cadena de modelo real, como Intel(R) Xeon(R) Gold 6338 CPU @ 2.00GHz o AMD EPYC 7443P 24-Core Processor, indica que el host te expone el modelo de CPU física. QEMU Virtual CPU version 2.5+ o Common KVM processor indican que ocurre algo distinto. Ese es el caso que conviene entender.
Por qué falta el indicador cuando el procesador lo admite
CPUID es la instrucción que usa un programa para consultar las funciones compatibles de la CPU. Dentro de una máquina virtual, CPUID siempre genera una salida hacia el hipervisor, por lo que este decide qué se comunica al sistema invitado. La mayoría de los paneles exponen esa decisión como un modelo de CPU del invitado. qemu64 y kvm64 son modelos base genéricos, y ninguno incluye AES-NI ni SSSE3 en su conjunto de funciones, por lo que el sistema invitado no ve ningún indicador aes aunque el host físico sea un EPYC actual. Un VPS es un sistema invitado que se ejecuta en el hardware de otra persona, así que cada función que informa es una decisión tomada en el nivel superior. Si este modelo por capas es nuevo para usted, empiece por qué es un VPS.
Los hosts eligen deliberadamente un modelo genérico porque la migración en vivo entre máquinas con procesadores diferentes sólo funciona si el sistema invitado nunca recibió información sobre una función que no existe en el destino. El coste lo asume usted. El kernel y la copia de OpenSSL leen ese CPUID enmascarado una vez durante el arranque, y después seleccionan la ruta de código lenta durante toda la vida del proceso.
La solución en el origen es un ajuste del host: -cpu host en términos de QEMU, un modelo con nombre que incluya AES-NI o un +aes explícito añadido al modelo. No puede configurar nada de esto desde el sistema invitado. Abrir un ticket de soporte o elegir un plan cuyo hipervisor exponga el modelo de CPU es la solución duradera.
Medir la diferencia con openssl speed
No dé por válido un benchmark publicado sin comprobarlo. Ejecute el cifrado que su propio servidor negocia realmente.
openssl version
openssl speed -evp aes-128-gcmLa fila del resultado se identifica como AES-128-GCM y muestra el rendimiento con seis tamaños de bloque, en unidades de 1000 bytes por segundo. Lea la columna de 8192 bytes para transferencias masivas. La columna de 16 bytes está dominada por la sobrecarga de cada llamada y no proporciona información útil sobre la descarga de un archivo.
Ahora ejecute el mismo comando con AES-NI y PCLMULQDQ desactivados en el software:
OPENSSL_ia32cap="~0x200000200000000" openssl speed -evp aes-128-gcmEse valor procede de la documentación del vector de capacidades de OpenSSL. Un ~ al principio significa «borrar estos bits». El bit 57 corresponde a AES-NI y el bit 33 a PCLMULQDQ. Por tanto, 0x200000200000000 nombra exactamente esas dos capacidades y ninguna otra. Si el segundo valor es muy inferior al primero, su equipo tiene AES-NI operativo y la comprobación ha terminado. Si los dos valores coinciden, OpenSSL ya estaba usando la ruta de software, porque el indicador nunca estuvo presente para borrarlo.
The data behind this chart
[
{
"label": "AES-NI and PCLMULQDQ",
"mb_per_sec": "4,850",
"cycles_per_byte": 0.7
},
{
"label": "Software fallback",
"mb_per_sec": 310,
"cycles_per_byte": 11.0
}
]Son cifras publicadas representativas de un núcleo x86 moderno cercano a 3.4 GHz, no mediciones realizadas en un host concreto. Interprételas como una referencia de la proporción. La ruta de hardware funciona aproximadamente a 0.7 ciclos por byte y la alternativa de software a aproximadamente 11.0, lo que equivale a unos 4,850 MB/s frente a 310 MB/s en un solo núcleo. Los dos comandos anteriores producen el único valor que describe su servidor. Aplique el mismo criterio al resto del equipo y combine esta prueba con una forma reproducible de medir el rendimiento de un VPS antes de sacar conclusiones sobre un plan.
Fuerza de nuevo los bits con OPENSSL_ia32cap
Esta es la parte que suele sorprender. Las instrucciones AES-NI no requieren privilegios y el hipervisor no las intercepta. Sólo se intercepta CPUID. Por tanto, un host puede indicar a tu guest que AES-NI no está disponible, mientras AESENC sigue ejecutándose de forma nativa a máxima velocidad. El software omite la ruta rápida porque consultó CPUID y recibió una respuesta incorrecta. La instrucción nunca dejó de funcionar.
OpenSSL permite responder en nombre de la CPU. Un valor hexadecimal sin formato en OPENSSL_ia32cap sobrescribe el vector de capacidades en lugar de aplicar una máscara.
OPENSSL_ia32cap="0x0200020207000000" openssl speed -evp aes-128-gcmSi esa ejecución es varias veces más rápida que la ejecución normal, el silicio tiene AES-NI y el host lo está ocultando. Esto sirve primero como diagnóstico. En OpenSSL, además, también funciona como solución.
Cómo se construye ese valor hexadecimal
El primer vector lógico empaqueta CPUID leaf 1 EDX en los 32 bits inferiores y leaf 1 ECX en los 32 bits superiores. En la mitad inferior, el bit 24 es FXSR, el bit 25 es SSE y el bit 26 es SSE2, lo que produce 0x07000000. En la mitad superior, el bit 33 es PCLMULQDQ, el bit 41 es SSSE3 y el bit 57 es AES-NI, lo que produce 0x02000202. En conjunto, el valor es 0x0200020207000000. SSSE3 aparece en la lista porque el GHASH basado en PCLMULQDQ de OpenSSL usa pshufb para intercambiar bytes, y un modelo de CPU genérico para el guest oculta SSSE3 junto con AES-NI.
Se aplican dos advertencias, y puedes provocar ambas de forma deliberada.
Si estableces sólo el primer vector, los vectores posteriores quedan en cero y se desactivan las rutas de código AVX2 y AVX-512. En este caso es intencionado. No intentes forzar los bits AVX en un guest con una máscara, porque los registros AVX requieren que el sistema operativo habilite el estado extendido en XCR0, y el kernel rechazó hacerlo basándose en el mismo CPUID con máscara. Una instrucción codificada con VEX provoca entonces un error de operación no definida y el proceso termina.
Forzar AES-NI en un núcleo que realmente no lo tiene termina el proceso inmediatamente:
Illegal instruction (core dumped)Eso es AESENC provocando un error de operación no definida, porque ese núcleo no tiene ninguna instrucción de ese tipo que ejecutar. Algunos firmwares de servidor también pueden desactivar AES-NI en el hardware hasta el siguiente reinicio, y el síntoma es idéntico. En ambos casos, la solución es usar otro host, no otra variable de entorno.
Para mantener la sobrescritura en un servicio de ejecución prolongada, usa un drop-in de systemd.
sudo systemctl edit nginx[Service]
Environment="OPENSSL_ia32cap=0x0200020207000000"sudo systemctl daemon-reload
sudo systemctl restart nginx
sudo systemctl show nginx -p EnvironmentEl último comando debería mostrarte de nuevo la variable. Entiende lo que implica: si ese servidor se migra alguna vez a un host cuya CPU realmente no tiene AES-NI, nginx terminará con una instrucción ilegal en su primera conexión TLS. Inclúyelo en tu runbook o deja la sobrescritura fuera de producción y úsala sólo para demostrar el problema cuando abras un ticket.
Qué no corrige el override
OPENSSL_ia32cap llega a OpenSSL y nada más. Cada componente de software ejecuta su propia detección de funcionalidades y nunca lee esa variable.
El kernel es el caso importante. dm-crypt y LUKS usan la API criptográfica del kernel, y el módulo aesni_intel se niega a cargarse cuando falta el bit de funcionalidad de la CPU:
modprobe: ERROR: could not insert 'aesni_intel': No such deviceNo existe una variable de espacio de usuario para esto. El kernel lee CPUID una vez durante el arranque, y esa decisión se mantiene hasta que se reinicia en otro host. Por tanto, el volumen cifrado sigue usando el cifrado por software, independientemente de lo que haga OpenSSL. Mida lo que obtiene realmente:
sudo cryptsetup benchmark -c aes-xts -s 256La fila aes-xts 256b alcanza miles de MiB/s con AES por hardware y cientos bajos sin él. Los runtimes de lenguajes que tienen su propia detección, como Go y Java, tampoco se ven afectados. crypto/aes de Go comprueba CPUID directamente y usa silenciosamente su implementación de software de tiempo constante cuando el bit está desactivado. Si el servicio que termina TLS es un binario de Go, la variable de OpenSSL no cambia nada en él.
Si no puede usar AES-NI, prefiera ChaCha20
ChaCha20-Poly1305 se diseñó para ofrecer un buen rendimiento mediante software. En un núcleo sin AES-NI utilizable, normalmente supera a AES-GCM por un margen amplio. Por tanto, lo adecuado en ese host es dejar de dar preferencia a AES.
Para nginx 1.19.4 y versiones posteriores, compilado con OpenSSL 1.1.1 o posterior:
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;ssl_ciphers cubre TLS 1.2. ssl_conf_command Ciphersuites cubre TLS 1.3. En este caso, nginx no tiene una directiva específica y pasa la cadena directamente a OpenSSL sin validarla. Por tanto, un error tipográfico se acepta de forma silenciosa. Recargue la configuración y confirme las opciones que se ofrecen a un cliente:
sudo nginx -t && sudo systemctl reload nginx
openssl s_client -connect example.com:443 -tls1_3 </dev/null 2>/dev/null | grep -i cipherUn resultado correcto muestra TLS_CHACHA20_POLY1305_SHA256. Antes de aplicar el cambio, ejecute openssl speed -evp chacha20-poly1305 junto con la prueba de AES en el mismo equipo y compare los dos valores.
Los hosts ARM usan extensiones diferentes
AES-NI sólo está disponible en x86. Un VPS ARM usa las extensiones criptográficas ARMv8, un conjunto de instrucciones independiente que realiza la misma función. En aarch64, los indicadores se encuentran en Features en lugar de flags:
grep -m1 Features /proc/cpuinfoBusque aes y pmull. pmull es la contraparte ARM de PCLMULQDQ y GCM la necesita por el mismo motivo. La variable de anulación de OpenSSL en ARM es OPENSSL_armcap. Su distribución de bits está definida en crypto/arm_arch.h dentro del código fuente de OpenSSL, por lo que el valor hexadecimal de x86 de esta guía no tiene ningún significado allí. En la práctica, los núcleos ARM de los servidores que se ofrecen como hosts VPS exponen estas extensiones, por lo que el problema de las funciones enmascaradas afecta principalmente a x86.
Modos de fallo y cadenas que verá
No aparece aes en /proc/cpuinfo y la ejecución forzada es mucho más rápida. El host está ocultando CPUID. Confirme que el nombre del modelo sea genérico y consulte a su proveedor qué modelo de CPU invitada presenta su hipervisor.
No aparece aes en /proc/cpuinfo y la ejecución forzada muestra Illegal instruction. Las instrucciones no están disponibles o el firmware las ha deshabilitado. Mueva la carga de trabajo a otro host.
aes está presente, pero el rendimiento sigue siendo bajo. Compruebe que está leyendo la columna de 8192 bytes y que ningún otro proceso está usando el núcleo. En un plan compartido, un vecino ruidoso produce exactamente el mismo aspecto que una función de CPU ausente hasta que ejecuta la prueba dos veces en distintos momentos del día.
La ejecución con la función enmascarada y la ejecución normal devuelven el mismo número. OpenSSL ya estaba usando la ruta de software. Ese resultado es el hallazgo, no un error de la prueba.
La virtualización anidada cambia el resultado un nivel más abajo. Un invitado dentro de otro invitado recibe el CPUID que la capa intermedia decide transmitir, y AES-NI puede perderse allí sin que sea evidente. Si ejecuta máquinas virtuales anidadas en un VPS, compruebe también el indicador dentro del invitado interno y en la máquina que alquiló.
FAQ
¿Por qué mi VPS no tiene el indicador aes en /proc/cpuinfo?
Porque el hipervisor presenta un modelo de CPU genérico para el guest. qemu64 y kvm64 no incluyen AES-NI en sus conjuntos de características, por lo que CPUID informa de que no está disponible, independientemente del procesador físico. Los hosts hacen esto para poder migrar un guest en ejecución entre máquinas con CPU diferentes. Ejecute grep -m1 'model name' /proc/cpuinfo: una cadena como QEMU Virtual CPU version 2.5+ o Common KVM processor lo confirma, mientras que una cadena de modelo de Xeon o EPYC real indica que el modelo de CPU se expone directamente y que el indicador realmente falta en el silicio.
¿OPENSSL_ia32cap activa realmente AES-NI o sólo lo simula?
Activa las instrucciones reales. Las instrucciones AES-NI no requieren privilegios y el hipervisor nunca las intercepta, por lo que AESENC se ejecuta de forma nativa, independientemente de lo que informe CPUID. Sólo se intercepta la instrucción CPUID. Establecer OPENSSL_ia32cap en un valor hexadecimal simple reemplaza la respuesta que OpenSSL obtuvo de CPUID, por lo que OpenSSL selecciona su ruta de código para hardware y el hardware la ejecuta a velocidad completa. Si el silicio realmente no admite esas instrucciones, el proceso termina con Illegal instruction (core dumped) en la primera operación AES.
¿El valor alternativo acelerará mi volumen cifrado con LUKS?
No. OPENSSL_ia32cap lo lee OpenSSL y nada más. LUKS y dm-crypt utilizan la API criptográfica del kernel, donde el módulo aesni_intel no se puede cargar y devuelve modprobe: ERROR: could not insert 'aesni_intel': No such device cuando el bit de característica está desactivado. El kernel lee CPUID durante el arranque y ninguna variable de espacio de usuario cambia ese resultado. Mida el valor real con sudo cryptsetup benchmark -c aes-xts -s 256 y compare la fila aes-xts 256b con la de un host que informe del indicador.
¿La ausencia del indicador AES-NI ralentiza WireGuard?
No. WireGuard utiliza ChaCha20-Poly1305 para todos los datos y nunca usa instrucciones AES, por lo que su rendimiento es el mismo en un host con las características ocultas y en uno que las expone. OpenVPN e IPsec configurados con AES-GCM sí pierden rendimiento en un host sin AES-NI. Por tanto, dos túneles en el mismo VPS pueden comportarse de forma muy diferente. Conviene tenerlo en cuenta antes de atribuir el problema a la red.
¿Cómo compruebo si hay AES-NI en un VPS ARM?
Los núcleos ARM no tienen AES-NI. Tienen las extensiones criptográficas ARMv8, que realizan la misma función con instrucciones diferentes. Ejecute grep -m1 Features /proc/cpuinfo y busque aes y pmull, ya que aarch64 las muestra bajo Features en lugar de flags. El valor x86 OPENSSL_ia32cap no tiene significado en ARM. La variable equivalente de OpenSSL allí es OPENSSL_armcap, y su distribución de bits está definida en crypto/arm_arch.h en el código fuente de OpenSSL.