Nota del editor: La entrada del blog titulada «NGINX: cambios en SELinux al actualizar a RHEL 6.6/CentOS 6.6» redirige aquí. Este artículo ofrece información actualizada y de carácter general.
La configuración predeterminada de Security-Enhanced Linux (SELinux) en las versiones modernas de Red Hat Enterprise Linux (RHEL) y las distribuciones relacionadas puede ser muy estricta, ya que prioriza la seguridad frente a la comodidad. Aunque la configuración predeterminada no limita el funcionamiento de NGINX Open Source ni de NGINX Plus con sus configuraciones predeterminadas, otras funciones que configure pueden quedar bloqueadas a menos que las permita explícitamente en SELinux. En este artículo se describen los posibles problemas y las formas recomendadas de resolverlos.
[Editor – Este artículo se aplica tanto a NGINX Open Source como a NGINX Plus. Para facilitar la lectura, se utiliza el término «NGINX» en todo el artículo.
CentOS es una distribución relacionada, derivada originalmente de RHEL, y es compatible con NGINX y NGINX Plus. Además, NGINX Plus es compatible con las distribuciones relacionadas Amazon Linux y Oracle Linux. Su configuración predeterminada de SELinux puede diferir de la de CentOS y RHEL; consulte la documentación del proveedor.]
Descripción general de SELinux
SELinux está habilitado de forma predeterminada en los servidores RHEL y CentOS modernos. Cada objeto del sistema operativo (proceso, descriptor de archivo, archivo, etc.) está etiquetado con un contexto de SELinux que define los permisos y las operaciones que puede realizar el objeto. En RHEL 6.6/CentOS 6.6 y versiones posteriores, NGINX está etiquetado con el contexto httpd_t:
# ps auZ | grep nginxunconfined_u:system_r:httpd_t:s0 3234 ? Ss 0:00 nginx: master process /usr/sbin/nginx \
-c /etc/nginx/nginx.conf
unconfined_u:system_r:httpd_t:s0 3236 ? Ss 0:00 nginx: worker processEl contexto httpd_t permite a NGINX escuchar en los puertos habituales de los servidores web, acceder a los archivos de configuración de /etc/nginx y acceder al contenido de la ubicación raíz de documentos estándar (/usr/share/nginx). No permite muchas otras operaciones, como actuar de proxy para ubicaciones ascendentes o comunicarse con otros procesos mediante sockets.
Deshabilitar temporalmente SELinux para NGINX
Para deshabilitar temporalmente las restricciones de SELinux para el contexto httpd_t, de modo que NGINX pueda realizar las mismas operaciones que en los sistemas operativos sin SELinux, asigne el contexto httpd_t al dominio permissive. Consulte la siguiente sección para obtener más información.
# semanage permissive -a httpd_tCambiar los modos de SELinux
SELinux puede ejecutarse en los modos «obligatorio», «permisivo» o «deshabilitado» (también denominados «dominios»). Antes de realizar un cambio en la configuración de NGINX que pueda infringir los permisos predeterminados (estrictos), puede cambiar SELinux del modo «obligatorio» al modo «permisivo», ya sea en su entorno de pruebas (si dispone de uno) o en el entorno de producción. En el modo «permisivo», SELinux permite todas las operaciones, pero registra aquellas que habrían infringido la política de seguridad en el modo «obligatorio».
Para añadir httpd_t a la lista de dominios permisivos, ejecute este comando:
# semanage permissive -a httpd_tPara eliminar httpd_t de la lista de dominios permisivos, ejecute:
# semanage permissive -d httpd_tPara establecer globalmente el modo en «permisivo», ejecuta:
# setenforce 0Para establecer globalmente el modo en enforcing, ejecuta:
# setenforce 1Resolución de excepciones de seguridad de SELinux
En el modo permisivo, las excepciones de seguridad se registran en el registro de auditoría predeterminado de Linux, /var/log/audit/audit.log. Si detecta un problema que solo se produce cuando NGINX se ejecuta en el modo obligatorio, revise las excepciones registradas en el modo permisivo y actualice la política de seguridad para permitirlas.
Problema 1: la conexión al proxy está prohibida
De forma predeterminada, la configuración de SELinux no permite que NGINX se conecte a servidores HTTP, FastCGI u otros servidores remotos, tal como indica un mensaje del registro de auditoría como el siguiente:
type=AVC msg=audit(1415714880.156:29): avc: denied { name_connect } for pid=1349 \
comm="nginx" dest=8080 scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=system_u:object_r:http_cache_port_t:s0 tclass=tcp_socket
type=SYSCALL msg=audit(1415714880.156:29): arch=c000003e syscall=42 success=no \
exit=-115 a0=b \a1=16125f8 a2=10 a3=7fffc2bab440 items=0 ppid=1347 pid=1349 \
auid=1000 uid=497 gid=496 euid=497 suid=497 fsuid=497 egid=496 sgid=496 fsgid=496 \
tty=(none) ses=1 comm="nginx" exe="/usr/sbin/nginx" \
subj=unconfined_u:system_r:httpd_t:s0 key=(null)El comando «audit2why» interpreta el código del mensaje (1415714880.156:29):
# grep 1415714880.156:29 /var/log/audit/audit.log | audit2whytype=AVC msg=audit(1415714880.156:29): avc: denied { name_connect } for pid=1349 \
comm="nginx" dest=8080 scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=system_u:object_r:http_cache_port_t:s0 tclass=tcp_socket
Was caused by:
One of the following booleans was set incorrectly.
Description:
Allow httpd to act as a relay
Allow access by executing:
# setsebool -P httpd_can_network_relay 1
Description:
Allow HTTPD scripts and modules to connect to the network using TCP.
Allow access by executing:
# setsebool -P httpd_can_network_connect 1La salida de audit2why indica que puede permitir que NGINX establezca conexiones de proxy habilitando una o ambas opciones booleanas httpd_can_network_relay y httpd_can_network_connect. Puede habilitarlas de forma temporal o permanente; para hacerlo de forma permanente, añada la opción ‑P tal como se muestra en la salida.
Comprender las opciones booleanas
El comando sesearch proporciona más información sobre las opciones booleanas y está disponible si instala el paquete setools (yum install setools). Aquí mostramos la salida de las opciones httpd_can_network_relay y httpd_can_network_connect.
La opción booleana httpd_can_network_relay Boolean Option
Esta es la salida del comando sesearch relativa a la opción httpd_can_network_relay:
# sesearch -A -s httpd_t -b httpd_can_network_relayFound 10 semantic av rules:
allow httpd_t gopher_port_t : tcp_socket name_connect ;
allow httpd_t http_cache_client_packet_t : packet { send recv } ;
allow httpd_t ftp_port_t : tcp_socket name_connect ;
allow httpd_t ftp_client_packet_t : packet { send recv } ;
allow httpd_t http_client_packet_t : packet { send recv } ;
allow httpd_t squid_port_t : tcp_socket name_connect ;
allow httpd_t http_cache_port_t : tcp_socket name_connect ;
allow httpd_t http_port_t : tcp_socket name_connect ;
allow httpd_t gopher_client_packet_t : packet { send recv } ;
allow httpd_t memcache_port_t : tcp_socket name_connect ;Esta salida indica que httpd_can_network_relay permite que los procesos etiquetados con el contexto httpd_t (como NGINX) se conecten a puertos de varios tipos, incluido el tipo http_port_t:
# semanage port -l | grep http_port_thttp_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000Para añadir más puertos (en este caso, 8082) al conjunto de puertos permitidos para http_port_t, ejecuta:
# semanage port -a -t http_port_t -p tcp 8082Si la salida de este comando indica que un puerto ya está definido, como en el siguiente ejemplo, significa que el puerto está incluido en otro conjunto. No lo reasigne a http_port_t, ya que podría afectar negativamente a otros servicios.
# semanage port -a -t http_port_t -p tcp 8080
/usr/sbin/semanage: Port tcp/8080 already defined
# semanage port -l | grep 8080
http_cache_port_t tcp 3128, 8080, 8118, 8123, 10001-10010La opción booleana httpd_can_network_connect Boolean Option
Esta es la salida del comando sesearch relativa a la opción httpd_can_network_connect:
# sesearch -A -s httpd_t -b httpd_can_network_connectFound 1 semantic av rules:
allow httpd_t port_type : tcp_socket name_connect ;Este resultado indica que httpd_can_network_connect permite que los procesos etiquetados con el contexto httpd_t (como NGINX) se conecten a todos los tipos de sockets TCP que tengan el atributo port_type. Para enumerarlos, ejecute:
# seinfo -aport_type -xProblema 2: El acceso al archivo está prohibido
De forma predeterminada, la configuración de SELinux no permite que NGINX acceda a archivos ubicados fuera de las ubicaciones autorizadas conocidas, tal como indica un mensaje del registro de auditoría como el siguiente:
type=AVC msg=audit(1415715270.766:31): avc: denied { getattr } for pid=1380 \
comm="nginx" path="/www/t.txt" dev=vda1 ino=1084 \
scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=unconfined_u:object_r:default_t:s0 tclass=fileEl comando audit2why interpreta el código del mensaje (1415715270.766:31):
# grep 1415715270.766:31 /var/log/audit/audit.log | audit2whytype=AVC msg=audit(1415715270.766:31): avc: denied { getattr } for pid=1380 \
comm="nginx" path="/www/t.txt" dev=vda1 ino=1084 \
scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=unconfined_u:object_r:default_t:s0 tclass=file
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.Cuando el acceso a los archivos está prohibido, tiene dos opciones.
Opción 1: Modificar la etiqueta del archivo
Modifique la etiqueta del archivo para que NGINX (como proceso etiquetado con el contexto httpd_t pueda acceder al archivo:
# chcon -v --type=httpd_sys_content_t /www/t.txtDe forma predeterminada, esta modificación se elimina cuando se vuelve a etiquetar el sistema de archivos. Para que el cambio sea permanente, ejecute:
# semanage fcontext -a -t httpd_sys_content_t /www/t.txt
# restorecon -v /www/t.txtPara modificar las etiquetas de grupos de archivos, ejecuta:
# semanage fcontext -a -t httpd_sys_content_t '/www(/.*)?'# restorecon -Rv /wwwOpción 2: Ampliar los permisos del dominio httpd_t Domain Permissions
Amplíe la política de httpd_t para permitir el acceso a ubicaciones de archivos adicionales:
# grep nginx /var/log/audit/audit.log | audit2allow -m nginx > nginx.te# cat nginx.te
module nginx 1.0;
require {
type httpd_t;
type default_t;
type http_cache_port_t;
class tcp_socket name_connect;
class file { read getattr open };
}
#============= httpd_t ==============
allow httpd_t default_t:file { read getattr open };
#!!!! This avc can be allowed using one of these booleans:
# httpd_can_network_relay, httpd_can_network_connect
allow httpd_t http_cache_port_t:tcp_socket name_connect;Para generar una política compilada, incluye la opción «-M»:
# grep nginx /var/log/audit/audit.log | audit2allow -M nginxPara cargar la política, ejecute semodule -i, y luego compruebe que se haya cargado correctamente con semodule -l:
# semodule -i nginx.pp
# semodule -l | grep nginx
nginx 1.0Este cambio se mantiene después de reiniciar el sistema.
Problema 3: NGINX no puede vincularse a puertos adicionales
De forma predeterminada, la configuración de SELinux no permite que NGINX escuche (bind()) en puertos TCP o UDP distintos de los predeterminados incluidos en la lista de permitidos del tipo http_port_t:
# semanage port -l | grep http_port_thttp_port_t tcp 80, 443, 488, 8008, 8009, 8443Si intenta configurar NGINX para que escuche en un puerto que no está en la lista de permitidos (con la directiva listen en el contexto http, stream o mail de la configuración de NGINX), se producirá un error al verificar (nginx -t) o volver a cargar la configuración de NGINX, tal como indica esta entrada del registro de NGINX:
YYYY/MM/DD hh:mm:ss [emerg] 46123#0: bind() to 0.0.0.0:8001 failed (13: Permission denied)Puede utilizar semanage para añadir el puerto deseado (en este caso, el 8001) al tipo http_port_t:
# semanage port -a -t http_port_t -p tcp 8001Recarga NGINX con la nueva configuración.
# nginx -s reloadProblema 4: Hay demasiados archivos abiertos Error
Cuando se supera el límite del número de archivos abiertos (RLIMIT_NOFILE), aparece el siguiente mensaje en el registro de errores:
Too many files are openCuando el proceso de trabajo de NGINX genera el error
En la mayoría de los casos, el proceso de trabajo de NGINX notifica este error, pero no se puede utilizar la directiva worker_rlimit_nofile de NGINX para aumentar el límite porque SELinux no permite la llamada al sistema setrlimit(); así se indica en los siguientes mensajes de los registros de errores y auditoría.
- En /var/log/nginx/error.log para CentOS/RHEL 7.4+:
YYYY/MM/DD hh:mm:ss [alert] 12066#0: setrlimit(RLIMIT_NOFILE, 2342) failed (13: Permission denied)- En /var/log/nginx/error.log para CentOS/RHEL 8.0+:
YYYY/MM/DD hh:mm:ss [alert] 3327#0: setrlimit(RLIMIT_NOFILE, 65535) failed (1: Operation not permitted)- En /var/log/audit/audit.log para CentOS/RHEL 7.4+ y /var/log/messages para CentOS/RHEL 8.0+:
type=AVC msg=audit(1437731200.211:366): avc: denied { setrlimit } for pid=12066 \ comm="nginx" scontext=system_u:system_r:httpd_t:s0 \
tcontext=system_u:system_r:httpd_t:s0 tclass=processPara aumentar el límite, ejecuta este comando como usuario root:
$ setsebool -P httpd_setrlimit 1Cuando el proceso maestro de NGINX genera el error
Si el proceso maestro de NGINX notifica el error, debe actualizar el archivo systemd unit de NGINX. Esto establece el límite de descriptores de archivo tanto para el proceso maestro como para los procesos de trabajo.
- Cree un directorio para la configuración de
nginx.service:
$ mkdir /etc/systemd/system/nginx.service.d- Añade las siguientes líneas a /etc/systemd/system/nginx.service.d/nofile_limit.conf:
[Service]LimitNOFILE=65535- Recarga la configuración del demonio systemd y reinicia NGINX:
$ systemctl daemon-reload$ systemctl restart nginx.serviceRecursos adicionales
SELinux es una herramienta compleja y potente para gestionar los permisos del sistema operativo. Puede encontrar más información en los siguientes documentos.
- Linux con seguridad mejorada, RHEL 6 o RHEL 7
- SELinux (guía práctica de CentOS)
- Guía del usuario de Security-Enhanced Linux (proyecto Fedora)
- Página de inicio del proyecto SELinux
- Linux con seguridad mejorada (Agencia de Seguridad Nacional de los Estados Unidos)
Sobre el autor

Artículos relacionados del blog
Ú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
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
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
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 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 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.