Distribución segura de claves privadas SSL con NGINX

NGINX | 02 de abril de 2019

Esta entrada de blog describe varios métodos para distribuir de forma segura las claves privadas SSL que utiliza NGINX al alojar sitios web cifrados mediante SSL. En ella se explica:

Para muchas implementaciones, el enfoque estándar es suficiente. Los dos enfoques más sofisticados que se analizan en este artículo impiden que un atacante pueda obtener las claves privadas SSL por otros medios. También veremos un par de técnicas más en próximos artículos:

  • Uso de almacenes de secretos de terceros, como HashiCorp Vault, para distribuir contraseñas de forma segura
  • Automatización del aprovisionamiento de certificados desde Vault al almacén de pares clave-valor de NGINX Plus, para que el material de las claves privadas nunca se almacene en disco

Los enfoques presentados en este artículo están dirigidos a los usuarios que necesitan gestionar sus propias claves y crear su propia estrategia segura de distribución de claves. No son necesarios para los usuarios que ejecutan NGINX en entornos que ya están integrados con un almacén de secretos, como Kubernetes.

Esta publicación se aplica tanto a NGINX Open Source como a NGINX Plus. Para facilitar la lectura, nos referiremos a NGINX en todo el texto.

Nota del editor: Esta publicación es la primera de una serie sobre cómo proteger las claves privadas SSL en NGINX. Consulte también las demás publicaciones de la serie:

¿Por qué proteger la clave privada SSL?

SSL/TLS se utiliza para autenticar, cifrar y verificar la integridad de las transacciones de red. Los sitios web se autentican mediante un certificado público firmado por una autoridad de certificación (CA) y demuestran que son los propietarios del certificado realizando cálculos con la clave privada correspondiente (que debe mantenerse en secreto).

Si la clave privada se ve comprometida (se revela a otra entidad), existen dos riesgos principales.

  • Riesgo 1: suplantación de identidad. Un atacante que disponga de la clave privada puede interceptar el tráfico de red y llevar a cabo un ataque de intermediario (MITM). Este ataque captura y descifra todo el tráfico, e incluso puede modificarlo, sin que los clientes ni el sitio web sean conscientes de ello.
  • Riesgo 2: descifrado. Un atacante que disponga de la clave privada y haya registrado el tráfico de red podrá descifrarlo sin conexión. Tenga en cuenta que este ataque no puede utilizarse contra conexiones que empleen un cifrado con secreto perfecto hacia adelante (PFS).

Si la clave privada se ve comprometida, la única opción es ponerse en contacto con la autoridad de certificación y solicitar la revocación del certificado; después, deberá confiar en que los clientes comprueben y respeten el estado de revocación.

Además, es recomendable utilizar certificados con periodos de validez cortos (por ejemplo, los certificados de «Let’s Encrypt» caducan a los 90 días). Poco antes de que caduque un certificado, debe generar una nueva clave privada y obtener un nuevo certificado de la autoridad de certificación. Esto reduce su exposición en caso de que la clave privada se vea comprometida.

El perímetro de seguridad de NGINX

¿Qué personas y procesos pueden acceder a las claves privadas SSL en NGINX?

En primer lugar, cualquier usuario que obtenga acceso de root al servidor en el que se ejecuta NGINX podrá leer y utilizar todos los recursos que utiliza el propio NGINX. Por ejemplo, existen métodos conocidos para extraer la clave privada SSL de la memoria de un proceso en ejecución.

Por lo tanto, independientemente de cómo se almacene y distribuya la clave privada, no es posible protegerla de un atacante con privilegios de root en el servidor host.

Además, cualquier usuario que pueda modificar y confirmar cambios en la configuración de NGINX puede aprovechar esa capacidad de muchas formas: para habilitar el acceso mediante proxy a servicios internos, eludir las medidas de autenticación, etc. También puede modificar la configuración de NGINX para obtener acceso de tipo root (o equivalente) al servidor, aunque herramientas como SELinux y AppArmor ayudan a reducir esa posibilidad.

Por lo tanto, por lo general no es posible proteger la clave privada frente a un atacante que pueda modificar y confirmar la configuración de NGINX.

Afortunadamente, cualquier organización competente cuenta con procesos de seguridad sólidos que dificultan que un atacante obtenga privilegios de root o modifique la configuración de NGINX.

Sin embargo, hay otras dos formas en las que un atacante con menos privilegios podría obtener acceso a la clave privada:

  • Un usuario podría tener un motivo legítimo para consultar la configuración de NGINX, o podría obtener acceso a una base de datos de configuración o a una copia de seguridad. Las claves privadas de NGINX suelen almacenarse en la configuración.
  • Un usuario podría obtener acceso al sistema de archivos del servidor NGINX, quizá a través de un hipervisor o una copia de seguridad del sistema. Cualquier dato almacenado en el sistema de archivos, incluido el material de las claves privadas, podría quedar accesible.

Los procesos descritos en este documento bloquean estos dos métodos de ataque.

Configuración estándar de NGINX

Comenzamos revisando cómo es una configuración típica de NGINX con SSL/TLS:

server {
    listen 443 ssl;

    server_name a.dev0; 

    ssl_certificate ssl/a.dev0.crt;
    ssl_certificate_key ssl/a.dev0.key;

    location / {
        return 200 "Hello from service A\n";
    }
}

El certificado público SSL (a.dev0.crt) y la clave privada (a.dev0.key) se almacenan en el sistema de archivos, en /etc/nginx/ssl/. La clave privada solo la lee el proceso maestro de NGINX, que normalmente se ejecuta como root, por lo que puede asignarle los permisos de acceso más restrictivos posibles:

root@web1:/etc/nginx/ssl# ls -l a.dev0.key-r-------- 1 root root 1766 Aug 15 16:32 a.dev0.key

La clave privada debe estar disponible en todo momento; el proceso maestro de NGINX la lee cada vez que se inicia el software NGINX, se vuelve a cargar la configuración o se realiza una comprobación de sintaxis (nginx -t).

Para obtener más información sobre la configuración de SSL/TLS, consulte la Guía de administración de NGINX Plus.

Implicaciones de seguridad de la configuración estándar

Como se ha indicado anteriormente, un atacante que obtenga acceso root al contenedor, la máquina virtual o el servidor en ejecución donde se ejecuta el software NGINX puede leer la clave privada SSL.

Cifrado de claves privadas SSL

NGINX admite claves privadas cifradas mediante algoritmos seguros como AES256:

root@web1:/etc/nginx/ssl# mv a.dev0.key a.dev0.key.plainroot@web1:/etc/nginx/ssl# openssl rsa -aes256 -in a.dev0.key.plain -out a.dev0.key
writing RSA key
Enter PEM pass phrase: secure password
Verifying - Enter PEM pass phrase: secure password again

A continuación, al iniciar NGINX, o al recargar o probar su configuración, NGINX solicita de forma interactiva la contraseña de descifrado:

root@web1:/etc/nginx# nginx -tEnter PEM pass phrase: secure password
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Uso de un archivo de contraseñas SSL

Introducir contraseñas de forma interactiva resulta incómodo y difícil de automatizar, pero puede configurar NGINX para que utilice una lista de contraseñas almacenadas en un archivo independiente especificado mediante la directiva ssl_password_file. Cuando NGINX necesita leer una clave privada, intenta descifrarla probando sucesivamente cada una de las contraseñas del archivo. Si ninguna es válida, NGINX se niega a iniciarse.

ssl_password_file /var/lib/nginx/ssl_passwords.txt;

El archivo ssl_password_file debe distribuirse por separado de la configuración y solo debe poder leerlo el usuario root. Puede considerarse un token de autorización que se instala en servidores de confianza. NGINX solo puede descifrar las claves privadas cuando se ejecuta en un servidor que dispone del token de autorización.

Implicaciones de seguridad de almacenar las claves cifradas en un archivo independiente

Este método reduce la superficie de ataque, ya que la configuración de NGINX por sí sola no le sirve de nada a un atacante. El atacante también debe obtener el contenido de ssl_password_file.

Si un atacante consigue acceso de tipo root al sistema de archivos donde se almacena ssl_password_file (por ejemplo, a partir de una copia de seguridad o a través del sistema anfitrión), podrá leer el archivo y utilizar las contraseñas para descifrar las claves privadas SSL.

Puede reducir este riesgo almacenando el archivo ssl_password_file en un disco RAM o en un sistema de archivos tmpfs. Por lo general, un atacante externo tiene más dificultades para acceder a este tipo de almacenamiento (por ejemplo, se borra al reiniciar el servidor) y puede excluirse de las copias de seguridad del sistema. Debe asegurarse de que el archivo de contraseñas se inicialice al arrancar el sistema.

Distribución más segura de listas de contraseñas SSL

El proceso que se describe a continuación ofrece una forma más segura de distribuir listas de contraseñas SSL desde un punto central de distribución.

Cada vez que NGINX necesita descifrar una clave SSL, consulta el punto de distribución central y utiliza las contraseñas sin almacenarlas en ningún momento en el disco local. Para autenticarse en el servidor central de contraseñas, la instancia de NGINX utiliza un token que puede revocar en cualquier momento para impedir el acceso a las contraseñas.

Creación de un punto central de distribución de contraseñas

Empieza creando un punto de distribución de contraseñas (PDP). Para esta implementación sencilla, utilizamos un servicio HTTPS para proporcionar la lista de contraseñas, con autenticación mediante nombre de usuario y contraseña:

$ curl -u dev0:mypassword https://pdpserver.local/ssl_passwords.txt
password1
password2
...

A continuación, puede habilitar o revocar el acceso añadiendo o eliminando tokens de autenticación en el PDP según sea necesario. Puede implementar el servidor de distribución de contraseñas mediante un servidor web como NGINX y utilizar el tipo de tokens de autenticación que resulte adecuado.

A continuación, debemos configurar NGINX para que recupere las contraseñas del PDP. Para empezar, creamos un script de shell llamado connector.sh con el siguiente contenido:

#!/bin/sh
# Usage: connector.sh   

CONNECTOR=$1
CREDS=$2
PDP_URL=$3

[ -e $CONNECTOR ] && /bin/rm -f $CONNECTOR

mkfifo $CONNECTOR; chmod 600 $CONNECTOR

while true; do
    curl -s -u $CREDS -k $PDP_URL -o $CONNECTOR
done

El script debe ejecutarse como un proceso en segundo plano, invocado de la siguiente manera:

root@web1:~# ./connector.sh /var/run/nginx/ssl_passwords \dev0:mypassword https://pdpserver.local/ssl_passwords.txt &

El conector se conecta a la ruta local especificada (/var/run/nginx/ssl_passwords), y se utiliza la directiva ssl_password_file para configurar NGINX de modo que acceda a esa ruta:

ssl_password_file /var/run/nginx/ssl_passwords;

Prueba el conector leyendo desde la ruta del conector:

root@web1:~# cat /var/run/nginx/ssl_passwords
password1
password2
...

Compruebe que NGINX puede leer la contraseña y descifrar las claves SSL:

root@web1:~# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Puede utilizar el enfoque de PDP centralizado para distribuir de forma segura cualquier recurso que NGINX lea normalmente del disco, como claves privadas individuales u otros datos confidenciales.

Implicaciones de seguridad de un PDP

Esta solución ofrece varias ventajas frente al almacenamiento de contraseñas SSL en disco:

  • Las contraseñas SSL nunca se almacenan en el sistema de archivos del servidor, por lo que un atacante que tenga acceso al sistema de archivos no podrá acceder directamente a ellas.
  • Las contraseñas se distribuyen desde un punto de acceso central, lo que facilita la supervisión y la auditoría.
  • El acceso de cada servidor se puede controlar de forma centralizada. Por ejemplo, cuando se retira un servidor, se revoca su token de acceso.

Tenga en cuenta que un usuario con acceso al sistema de archivos podría extraer las credenciales utilizadas para acceder al PDP. Es importante revocar estas credenciales cuando ya no sean necesarias.

Resumen

Hay muchas formas de proteger las claves privadas SSL para evitar su divulgación, con niveles crecientes de seguridad y complejidad:

  • Para la gran mayoría de las organizaciones, basta con restringir el acceso a los entornos en los que se ejecuta NGINX para que los usuarios no autorizados no puedan obtener acceso root ni consultar la configuración de NGINX.
  • En algunos entornos, puede que no sea posible restringir por completo el acceso a la configuración de NGINX, por lo que se puede utilizar un archivo de contraseñas SSL.
  • En determinados casos, las organizaciones pueden querer asegurarse de que las claves y las contraseñas nunca se almacenen en disco. El proceso de punto de distribución de contraseñas constituye una prueba de concepto de esta solución.

Las demás publicaciones de esta serie describen otras medidas que puede adoptar para proteger las claves SSL:

Pruebe NGINX Plus – comience hoy mismo su prueba gratuita de 30 días o póngase en contacto con nosotros para hablar sobre sus casos de uso.


Compartir

Sobre el autor

Owen Garrett
Owen GarrettDirector sénior de Gestión de Producto

Más artículos de Owen Garrett

Artículos relacionados del blog

Únete a F5 NGINX en AppWorld 2024
NGINX | 04/01/2024

Únete a F5 NGINX en AppWorld 2024

Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
NGINX | 26/09/2023

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source

La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.

Exposición de APIs en Kubernetes
NGINX | 10/03/2022

Exposición de APIs en Kubernetes

La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
NGINX | 23/08/2021

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto

Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.

Presentamos NGINX Plus R22
NGINX | 09/06/2020

Presentamos NGINX Plus R22

NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.

Presentamos NGINX Plus R17
NGINX | 11/12/2018

Presentamos NGINX Plus R17

NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.