BLOG | NGINX

Tutorial de NGINX: Proteja las aplicaciones de Kubernetes de la inyección de SQL

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Daniele Polencic
Daniele Polencic
Publicado el 22 de marzo de 2022

Este tutorial es uno de los cuatro que ponen en práctica los conceptos de Microservicios de marzo de 2022: Redes de Kubernetes :

¿Quieres orientación detallada sobre el uso de NGINX para aún más casos de uso de redes Kubernetes? Descargue nuestro libro electrónico gratuito, Gestión del tráfico de Kubernetes con NGINX: Una guía práctica .

Trabaja en el departamento de TI de una popular tienda local que vende una variedad de productos, desde almohadas hasta bicicletas. Están a punto de lanzar su primera tienda en línea, pero le pidieron a un experto en seguridad que realizara una prueba de penetración en el sitio antes de hacerlo público. ¡Desafortunadamente, el experto en seguridad encontró un problema! La tienda en línea es vulnerable a la inyección SQL . El experto en seguridad pudo explotar el sitio para obtener información confidencial de su base de datos, incluidos nombres de usuario y contraseñas.

Su equipo ha recurrido a usted –el ingeniero de Kubernetes– para salvar el día. Afortunadamente, sabes que la inyección de SQL (así como otras vulnerabilidades) se pueden mitigar utilizando herramientas de gestión de tráfico de Kubernetes. Ya implementó un controlador Ingress para exponer la aplicación y, en una única configuración, puede garantizar que la vulnerabilidad no pueda explotarse. Ahora la tienda en línea podrá lanzarse a tiempo. ¡Bien hecho!

Descripción general del laboratorio y del tutorial

Este blog acompaña al laboratorio de la Unidad 3 de Microservicios de marzo de 2022: Patrón de seguridad de microservicios en Kubernetes , que demuestra cómo usar NGINX y el controlador de ingreso NGINX para bloquear la inyección de SQL.

Para ejecutar el tutorial, necesitas una máquina con:

  • 2 CPU o más
  • 2 GB de memoria libre
  • 20 GB de espacio libre en disco
  • Conexión a Internet
  • Administrador de contenedores o máquina virtual , como Docker, Hyperkit, Hyper-V, KVM, Parallels, Podman, VirtualBox o VMware Fusion/Workstation
  • minikube instalado
  • Timón instalado
  • Una configuración que le permite iniciar una ventana del navegador. Si eso no es posible, deberá averiguar cómo acceder a los servicios relevantes a través de un navegador.

Para aprovechar al máximo el laboratorio y el tutorial, le recomendamos que antes de comenzar:

Este tutorial utiliza estas tecnologías:

Las instrucciones para cada desafío incluyen el texto completo de los archivos YAML utilizados para configurar las aplicaciones. También puedes copiar el texto de nuestro repositorio de GitHub . Se proporciona un enlace a GitHub junto con el texto de cada archivo YAML.

Este tutorial incluye cuatro desafíos:

  1. Implementar un clúster y una aplicación vulnerable
  2. Hackear la aplicación
  3. Utilice un contenedor sidecar NGINX para bloquear ciertas solicitudes
  4. Configurar el controlador de ingreso NGINX para filtrar solicitudes

Desafío 1: Implementar un clúster y una aplicación vulnerable

En este desafío, implementa un clúster de minikube e instala Podinfo como una aplicación de muestra que tiene vulnerabilidades de seguridad.

Crear un clúster de Minikube

Implementar un clúster de minikube . Después de unos segundos, un mensaje confirma que la implementación fue exitosa.

$ minikube start 🏄 ¡Listo! kubectl ahora está configurado para usar el clúster "minikube" y el espacio de nombres "default" de forma predeterminada. 

Instalar la aplicación vulnerable

Aquí se implementa una aplicación de comercio electrónico simple que consta de dos microservicios:

  • Una base de datos MariaDB
  • Un microservicio PHP que se conecta a la base de datos y recupera datos.

Realice estos pasos:

  1. Usando el editor de texto de su elección, cree un archivo YAML llamado 1-app.yaml con el siguiente contenido (o cópielo desde GitHub ).

    apiVersion: apps/v1 tipo: Implementación
    Metadatos:
    Nombre: app
    Especificación:
    Selector:
    Etiquetas de coincidencia:
    app: app
    Plantilla:
    Metadatos:
    Etiquetas:
    app: app
    Especificación:
    Contenedores:
    - Nombre: app
    Imagen: f5devcentral/microservicesmarch:1.0.3
    Puertos:
    - PuertoContenedor: 80 
    env: 
    - nombre: MYSQL_USER
    valor: dan
    - nombre: MYSQL_PASSWORD
    valor: dan
    - nombre: MYSQL_DATABASE
    valor: sqlitraining
    - nombre: NOMBRE_DEL_HOST_DE_BASE_DE_DATOS
    valor: db.default.svc.cluster.local
    ---
    Versión_de_API: v1
    tipo: Servicio
    Metadatos:
    Nombre: app
    Especificaciones:
    Puertos:
    - Puerto: 80
    Puerto de destino: 80 
    nodePort: 30001 
    Selector: 
    Aplicación: aplicación 
    Tipo: NodePort
    --- 
    apiVersion: apps/v1 
    kind: Implementación
    Metadatos:
    Nombre: BD
    Especificación:
    Selector:
    Etiquetas de coincidencia:
    Aplicación: BD
    Plantilla:
    Metadatos:
    Etiquetas:
    Aplicación: BD
    Especificación:
    Contenedores:
    - Nombre: BD
    Imagen: MariaDB:10.3.32-Focal
    Puertos:
    - PuertoContenedor: 3306 
    env: 
    - nombre: MYSQL_ROOT_PASSWORD
    valor: raíz
    - nombre: MYSQL_USER
    valor: dan
    - nombre: MYSQL_PASSWORD
    valor: dan
    - nombre: MYSQL_DATABASE
    valor: sqlitraining
    
    ---
    apiVersion: v1
    tipo: Servicio
    Metadatos:
    Nombre: BD
    Especificación:
    Puertos:
    - Puerto: 3306
    Puerto de destino: 3306
    selector: 
    aplicación: db 
    
  2. Implementar la aplicación y la API:

    $ kubectl apply -f 1-app.yaml implementación.apps/app creada servicio/app creada implementación.apps/db creada servicio/db creada 
    
  3. Confirme que los pods Podinfo se implementaron, como lo indica el valor En ejecución en la columna ESTADO . Puede tomar entre 30 y 40 segundos para que se implementen por completo, así que espere hasta que el estado de ambos pods sea En ejecución antes de continuar con el siguiente paso (reemitir el comando según sea necesario).

    $ kubectl get pods NOMBRE LISTO ESTADO REINICIO EDAD app-d65d9b879-b65f2 1/1 En ejecución 0 37 s db-7bbcdc75c-q2kt5 1/1 En ejecución 0 37 s 
    
  4. Abra la aplicación en su navegador:

    $ minikube service app |-----------|------|-------------|--------------| | ESPACIO DE NOMBRES | NOMBRE | PUERTO DE DESTINO | URL | |-----------|------|-------------|--------------| | predeterminado | aplicación | | Sin puerto de nodo | |-----------|------|-------------|--------------| 😿 El servicio predeterminado/aplicación no tiene puerto de nodo 🏃 Iniciando túnel para la aplicación de servicio. |-----------|------|-------------|------------------------| | ESPACIO DE NOMBRES | NOMBRE | PUERTO DE DESTINO | URL | |-----------|------|-------------|------------------------| | predeterminado | aplicación | | http://127.0.0.1:55446 | |-----------|------|-------------|------------------------| 🎉 Abriendo el servicio predeterminado/aplicación en el navegador predeterminado... 
    

Desafío 2: Hackear la aplicación

La aplicação de muestra es bastante básica. Incluye una página de inicio con una lista de artículos (por ejemplo, almohadas) y un conjunto de páginas de productos con detalles como una descripción y el precio. Los datos se almacenan en la base de datos MariaDB. Cada vez que se solicita una página, se emite una consulta SQL contra la base de datos.

  • Para la página de inicio, se recuperan todos los elementos de la base de datos.
  • Para una página de producto, el artículo se obtiene por ID.

Cuando abres la página del producto de almohadas , es posible que notes que la URL termina en /product/1 . El1 Es el ID del producto. Para evitar la inserción directa de código malicioso en la consulta SQL, se recomienda depurar la entrada del usuario antes de reenviar las solicitudes a los servicios de backend. ¿Pero qué pasa si la aplicación no está configurada correctamente y la entrada no se escapa antes de insertarla en la consulta SQL contra la base de datos?

Exploit 1

Para saber si la aplicación está escapando la entrada correctamente, ejecute un experimento simple cambiando el ID por uno que no exista en la base de datos.

Cambiar manualmente el último elemento de la URL desde1 a-1 . El mensaje de error Id. de producto no válido "-1" indica que no se está escapando el ID del producto; en su lugar, la cadena se inserta directamente en la consulta. ¡Eso no es bueno a menos que seas un hacker!

Supongamos que la consulta de la base de datos es algo como:

SELECCIONAR * DE alguna_tabla DONDE id = "1"

Para explotar la vulnerabilidad causada por no escapar la entrada, reemplace 1 con -1" <consulta_maliciosa> -- // tal que:

  • Las comillas ( " ) después de-1 Completa la primera consulta.
  • Puedes agregar tu propia consulta maliciosa después de las comillas.
  • La secuencia -- // descarta el resto de la consulta.

Entonces, por ejemplo, si cambia el elemento final en la URL a -1" o 1-- // , la consulta se compila a:

SELECCIONAR * DE alguna_tabla DONDE id = "-1" O 1 -- //" -------------- ^ inyectado ^ 

Esto selecciona todas las filas de la base de datos, lo que resulta útil en un truco. Para saber si este es el caso, cambie la terminación de la URL a -1" . El mensaje de error resultante le brinda información más útil sobre la base de datos:

Error fatal: Excepción mysqli_sql_exception no detectada: Tiene un error en su sintaxis SQL; consulte el manual que corresponde a la versión de su servidor MariaDB para conocer la sintaxis correcta a utilizar cerca de '"-1""' en la línea 1 en /var/www/html/product.php:23 Rastreo de pila: #0 /var/www/html/product.php(23): mysqli->query('SELECT * FROM p...') #1 {main} arrojado en /var/www/html/product.php en la línea 23

Ahora, puedes comenzar a manipular el código inyectado en un intento de ordenar los resultados de la base de datos por ID:

-1" O 1 ORDEN POR id DESC -- //

El resultado es la página del producto del último artículo en la base de datos.

Exploit 2

Forzar la base de datos a ordenar los resultados es interesante, pero no especialmente útil si el objetivo es hackear. Intentar extraer nombres de usuario y contraseñas de la base de datos vale mucho más la pena.

Es seguro asumir que hay una tabla de usuarios en la base de datos con nombres de usuario y contraseñas. Pero ¿cómo ampliar el acceso desde la tabla de productos a la tabla de usuarios?

La respuesta es inyectando código como este:

-1" UNION SELECT * FROM usuarios -- //

dónde

  • -1" fuerza el retorno de un conjunto vacío de la primera consulta.
  • UNION fuerza la unión de dos tablas de base de datos (en este caso, productos y usuarios ), lo que permite obtener información (contraseñas) que no está en la tabla original ( productos ).
  • SELECT * FROM users selecciona todas las filas de la tabla de usuarios .
  • La secuencia -- // descarta todo lo que esté después de la consulta maliciosa.

Cuando modificas la URL para que termine en el código inyectado, aparece un nuevo mensaje de error:

Error fatal: Excepción mysqli_sql_exception no detectada: Las instrucciones SELECT utilizadas tienen un número diferente de columnas en /var/www/html/product.php:23 Rastreo de pila: #0 /var/www/html/product.php(23): mysqli->query('SELECT * FROM p...') #1 {main} agregado en /var/www/html/product.php en la línea 23

Este mensaje revela que las tablas de productos y usuarios no tienen el mismo número de columnas, por lo que no se puede ejecutar la instrucción UNION . Pero puede descubrir la cantidad de columnas mediante prueba y error, agregando columnas (nombres de campo) una a la vez como parámetros a la instrucción SELECT . Una buena suposición para un nombre de campo en una tabla de usuarios es contraseña , así que intente esto:

# seleccionar 1 columna -1" UNION SELECT contraseña FROM usuarios; -- // # seleccionar 2 columnas -1" UNION SELECT contraseña,contraseña FROM usuarios; -- // # seleccionar 3 columnas -1" UNION SELECT contraseña,contraseña,contraseña FROM usuarios; -- / # seleccionar 4 columnas -1" UNION SELECT contraseña,contraseña,contraseña,contraseña FROM usuarios; -- // # seleccionar 5 columnas -1" UNION SELECT contraseña,contraseña,contraseña,contraseña,contraseña FROM usuarios; -- //

La última consulta tiene éxito (le indica que hay cinco columnas en la tabla de usuarios ) y ve una contraseña de usuario:

En este momento no sabes el nombre de usuario que corresponde a esta contraseña. Pero al conocer el número de columnas de la tabla de usuarios , puede utilizar los mismos tipos de consulta que antes para exponer esa información. Supongamos que el nombre del campo relevante es nombre de usuario . Y eso resulta ser correcto: la siguiente consulta expone tanto el nombre de usuario como la contraseña de la tabla de usuarios . ¡Lo cual es genial, a menos que esta aplicación esté alojada en tu infraestructura!

-1" UNION SELECT nombredeusuario,nombredeusuario,contraseña,contraseña,nombredeusuario FROM usuarios donde id=1 -- //

Desafío 3: Utilice un contenedor sidecar NGINX para bloquear ciertas solicitudes

El desarrollador de la aplicación de la tienda online obviamente debe prestar más atención a la limpieza de la entrada del usuario (como el uso de consultas parametrizadas), pero como ingeniero de Kubernetes también puede ayudar a prevenir la inyección de SQL bloqueando el ataque para que no llegue a la aplicación. De esta forma, no importa tanto que la aplicación sea vulnerable.

Hay muchas formas de proteger tus aplicaciones. Durante el resto de este laboratorio, nos centraremos en dos:

  • En este desafío, inyecta un contenedor sidecar en el pod para representar todo el tráfico y denegar cualquier solicitud que tenga UNION en la URL.

    Primero implemente NGINX Open Source como sidecar y luego pruebe si filtra consultas maliciosas .

    Nota:  Utilizamos esta técnica únicamente con fines ilustrativos. En realidad, implementar manualmente servidores proxy como sidecars no es la mejor solución (hablaremos más sobre esto más adelante).

  • En el desafío 4 , utilizamos el controlador de ingreso NGINX para filtrar todo el tráfico que ingresa al clúster.

Implementar NGINX de código abierto como sidecar

  1. Crea un archivo YAML llamado 2-app-sidecar.yaml con el siguiente contenido (o cópialo desde GitHub ). Los aspectos importantes de la configuración incluyen:

    • Se inicia un contenedor sidecar que ejecuta NGINX Open Source en el puerto 8080.
    • NGINX reenvía todo el tráfico a la aplicación.
    • Se rechaza cualquier solicitud que incluya (entre otras cadenas de caracteres) SELECT o UNION (consulte el primer bloque de ubicación en la sección ConfigMap ).
    • El servicio de la aplicación enruta primero todo el tráfico al contenedor NGINX.
    apiVersion: apps/v1 
    tipo: Implementación
    Metadatos:
    Nombre: app
    Especificación:
    Selector:
    Etiquetas de coincidencia:
    app: app
    Plantilla:
    Metadatos:
    Etiquetas:
    app: app
    Especificación:
    Contenedores:
    - Nombre: app
    Imagen: f5devcentral/microservicesmarch:1.0.3
    Puertos:
    - PuertoContenedor: 80 
    env: 
    - nombre: MYSQL_USER
    valor: dan
    - nombre: MYSQL_PASSWORD
    valor: dan
    - nombre: MYSQL_DATABASE
    valor: sqlitraining
    - nombre: NOMBRE_DEL_HOST_DE_BASE_DE_DATOS
    valor: db.default.svc.cluster.local
    - nombre: proxy # <-- sidecar
    imagen: "nginx"
    puertos:
    - puerto_del_contenedor: 8080
    volumenMontajes:
    - Ruta de montaje: /etc/nginx
    nombre: nginx-config
    volumenes:
    - nombre: nginx-config
    mapa de configuración:
    nombre: sidecar
    ---
    apiVersion: v1
    tipo: Servicio
    Metadatos:
    Nombre: app
    Especificaciones:
    Puertos:
    - Puerto: 80
    Puerto de destino: 8080 # <-- el tráfico se enruta al proxy
    nodePort: 30001 
    Selector: 
    Aplicación: aplicación 
    Tipo: NodePort
    --- 
    APIVersion: v1 
    Tipo: Mapa de configuración
    Metadatos:
    Nombre: Sidecar
    Datos:
    Nginx.conf: |-
    Eventos {}
    http {
    Servidor {
    Listen 8080 Servidor_predeterminado;
    Listen [::]:8080 Servidor_predeterminado;
    
    Ubicación ~* "(\'|\")(.*)(drop|insert|md5|select|union)" {
    Denegar todo;
    }
    
    Ubicación / {
    Proxy_pass http://localhost:80/;
    }
    }
    }
    }
    ---
    Versión de API: apps/v1
    Tipo: Implementación
    Metadatos:
    Nombre: BD
    Especificación:
    Selector:
    Etiquetas de coincidencia:
    Aplicación: BD
    Plantilla:
    Metadatos:
    Etiquetas:
    Aplicación: BD
    Especificación:
    Contenedores:
    - Nombre: BD
    Imagen: MariaDB:10.3.32-Focal
    Puertos:
    - PuertoContenedor: 3306 
    env: 
    - nombre: MYSQL_ROOT_PASSWORD
    valor: raíz
    - nombre: MYSQL_USER
    valor: dan
    - nombre: MYSQL_PASSWORD
    valor: dan
    - nombre: MYSQL_DATABASE
    valor: sqlitraining
    
    ---
    apiVersion: v1
    tipo: Servicio
    Metadatos:
    Nombre: BD
    Especificación:
    Puertos:
    - Puerto: 3306
    Puerto de destino: 3306
    selector: 
    aplicación: db
    
  2. Implementar el sidecar:

    $ kubectl apply -f 2-app-sidecar.yaml despliegue.apps/app configurado servicio/app configurado configmap/sidecar creado despliegue.apps/db sin cambios servicio/db sin cambios 
    

Pruebe el Sidecar como filtro

Pruebe si el sidecar está filtrando el tráfico volviendo a la aplicación e intentando la inyección SQL nuevamente. ¡NGINX bloquea la solicitud antes de que llegue a la aplicación!

-1" UNION SELECT nombredeusuario,nombredeusuario,contraseña,contraseña,nombredeusuario FROM usuarios donde id=1 -- //

Desafío 4: Configurar el controlador de ingreso NGINX para filtrar solicitudes

Proteger tu aplicación como en el Desafío 3 es interesante como experiencia educativa, pero no lo recomendamos para producción porque:

  • No es una solución de seguridad completa.
  • No es escalable (no se puede aplicar fácilmente esta protección a múltiples aplicaciones).
  • Actualizarlo es complicado e ineficiente.

¡Una solución mucho mejor es usar NGINX Ingress Controller para extender la misma protección a todas tus aplicaciones! Los controladores de ingreso se pueden utilizar para centralizar todo tipo de funciones de seguridad, desde el bloqueo de solicitudes como lo hace un firewall de aplicação web (WAF) hasta la autenticación y la autorización.

En este desafío, implementa NGINX Ingress Controller , configura el enrutamiento de tráfico y verifica que el filtro bloquee la inyección de SQL .

Implementar el controlador de ingreso NGINX 

La forma más rápida de instalar NGINX Ingress Controller es con Helm .  

  1. Agregue el repositorio NGINX a Helm: 

    $ helm repo agregar nginx-stable https://helm.nginx.com/stable  
    
  2. Descargue e instale el controlador de entrada NGINX de código abierto, mantenido por F5 NGINX. Tenga en cuenta el parámetro enableSnippets=true : los fragmentos de código se utilizan para configurar NGINX y bloquear la inyección SQL. La última línea de salida confirma la instalación exitosa.

    NOMBRE: main ÚLTIMA IMPLEMENTACIÓN: Día Lun DD hh:mm:ss AAAA ESPACIO DE NOMBRES: predeterminado ESTADO: implementado REVISIÓN: 1 CONJUNTO DE PRUEBAS: Ninguna NOTAS: Se ha instalado el controlador de ingreso NGINX.  
    
  3. Confirme que el pod del controlador de ingreso NGINX se haya implementado, como lo indica el valor En ejecución en la columna ESTADO . 

    $ kubectl get pods NOMBRE LISTO ESTADO ... main-nginx-ingress-779b74bb8b-mtdkr 1/1 En ejecución ... ... REINICIO EDAD... 0 18s
    

Dirigir el tráfico a su aplicación

  1. Cree un archivo YAML llamado 3-ingress.yaml con el siguiente contenido (o cópielo desde GitHub ). Define el manifiesto de ingreso necesario para enrutar el tráfico a la aplicación (no a través del proxy sidecar esta vez). Tenga en cuenta las anotaciones: bloque donde se utiliza un fragmento para personalizar la configuración del controlador de ingreso NGINX con el mismo bloque de ubicación que en la definición de ConfigMap en el desafío 3: rechaza cualquier solicitud que incluya (entre otras cadenas de caracteres) SELECT o UNION .

    apiVersion: v1 tipo: Servicio
    Metadatos:
    Nombre: app-without-sidecar
    Especificación:
    Puertos:
    - Puerto: 80
    Puerto de destino: 80
    selector:
    aplicación: aplicación
    ---
    apiVersion: networking.k8s.io/v1
    tipo: Entrada
    Metadatos:
    Nombre: entrada
    Anotaciones:
    nginx.org/server-snippets: |
    Ubicación ~* "(\'|\")(.*)(drop|insert|md5|select|union)" {
    Denegar todo;
    }
    Especificación:
    IngressClassName: nginx
    Reglas:
    - host: "example.com"
    http:
    Rutas:
    - backend:
    Servicio:
    Nombre: app-without-sidecar
    Puerto:
    Número: 80 
    ruta: / 
    tipoDeRuta: Prefijo 
    
  2. Implementar el recurso Ingress: 
  3. $ kubectl apply -f 3-ingress.yaml servicio/aplicación-sin-sidecar creado ingress.networking.k8s.io/entry creado 
    

Verificar el funcionamiento del filtro

  1. Inicie un contenedor BusyBox desechable para emitir una solicitud al pod del controlador de ingreso NGINX con el nombre de host correcto.

    $ kubectl run -ti --rm=true busybox --image=busybox $ wget --header="Host: ejemplo.com" -qO- main-nginx-ingress    # ...
    
  2. Intente la inyección SQL. El403 ¡El código de estado prohibido confirma que NGINX bloquea el ataque!

     

    $ wget --header="Host: ejemplo.com" -qO- 'main-nginx-ingress/producto/-1"%20UNION%20SELECT%20nombreusuario,nombreusuario,contraseña,contraseña,nombreusuario%20FROM%20usuarios%20donde%2 0id=1%20--%20//' wget: el servidor devolvió un error: HTTP/1.1 403 Prohibido 
    

Próximos pasos

Kubernetes no es seguro de forma predeterminada. Un controlador de Ingress puede mitigar las vulnerabilidades de inyección de SQL (y muchas otras). Pero tenga en cuenta que el tipo de funcionalidad similar a WAF que acaba de implementar con NGINX Ingress Controller no reemplaza un WAF real ni es un reemplazo para la arquitectura segura de aplicaciones. Un hacker inteligente aún puede hacer que el hack de UNION funcione con algunos pequeños cambios en el código. Para obtener más información sobre este tema, consulte A Pentester's Guide to SQL Injection (SQLi) .

Dicho esto, un controlador de Ingress sigue siendo una herramienta poderosa para centralizar la mayor parte de su seguridad, lo que genera una mayor eficiencia y seguridad, incluidos casos de uso de autenticación y autorización centralizados (mTLS, inicio de sesión único) e incluso un WAF robusto como F5 NGINX App Protect WAF .

La complejidad de sus aplicaciones y arquitectura podrían requerir un control más detallado. Si su organización requiere Zero Trust y cifrado de extremo a extremo , considere una malla de servicios como F5 NGINX Service Mesh siempre gratuita para controlar la comunicación entre los servicios en el clúster de Kubernetes (tráfico de este a oeste). Exploramos las mallas de servicios en la Unidad 4, Estrategias avanzadas de implementación de Kubernetes .

Para obtener detalles sobre cómo obtener e implementar NGINX Open Source, visita nginx.org .

Para probar el controlador de ingreso NGINX basado en NGINX Plus con NGINX App Protect, comience hoy su prueba gratuita de 30 días o contáctenos para analizar sus casos de uso . 

Para probar el controlador de ingreso NGINX basado en NGINX de código abierto, consulte las versiones del controlador de ingreso NGINX en nuestro repositorio de GitHub o descargue un contenedor prediseñado de DockerHub . 


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.