Nota do editor – A publicação do blog intitulada “NGINX: alterações no SELinux ao atualizar para o RHEL 6.6 / CentOS 6.6” redireciona para esta página. Este artigo apresenta informações atualizadas e mais abrangentes.
As configurações padrão do Security-Enhanced Linux (SELinux) nas versões modernas do Red Hat Enterprise Linux (RHEL) e em distribuições relacionadas podem ser muito rigorosas, priorizando a segurança em vez da conveniência. Embora as configurações padrão não limitem o funcionamento do NGINX Open Source e do NGINX Plus em suas configurações padrão, outros recursos que você configurar poderão ser bloqueados, a menos que sejam explicitamente permitidos no SELinux. Este artigo descreve os possíveis problemas e as formas recomendadas de resolvê-los.
[Editor – Este artigo se aplica tanto ao NGINX Open Source quanto ao NGINX Plus. Para facilitar a leitura, o termo “NGINX” é usado em todo o texto.
O CentOS é uma distribuição relacionada, originalmente derivada do RHEL, e é compatível com o NGINX e o NGINX Plus. Além disso, o NGINX Plus é compatível com as distribuições relacionadas Amazon Linux e Oracle Linux. As configurações padrão do SELinux nessas distribuições podem ser diferentes das configurações do CentOS e do RHEL; consulte a documentação do fornecedor.]
Visão geral do SELinux
O SELinux é habilitado por padrão em servidores RHEL e CentOS modernos. Cada objeto do sistema operacional (processo, descritor de arquivo, arquivo etc.) é rotulado com um contexto do SELinux que define as permissões e operações que o objeto pode executar. No RHEL 6.6/CentOS 6.6 e versões posteriores, o NGINX é rotulado com o 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 processO contexto httpd_t permite que o NGINX escute nas portas comuns de servidores web, acesse os arquivos de configuração em /etc/nginx e acesse o conteúdo no diretório raiz padrão (/usr/share/nginx). Ele não permite muitas outras operações, como encaminhar solicitações por proxy para servidores upstream ou se comunicar com outros processos por meio de sockets.
Desabilitando temporariamente o SELinux para o NGINX
Para desabilitar temporariamente as restrições do SELinux para o contexto httpd_t, permitindo que o NGINX execute as mesmas operações que em sistemas operacionais sem SELinux, atribua o contexto httpd_t ao domínio permissive. Consulte a próxima seção para obter detalhes.
# semanage permissive -a httpd_tAlterando os modos do SELinux
O SELinux pode ser executado nos modos enforcing, permissive ou disabled (também chamados de domínios). Antes de fazer uma alteração na configuração do NGINX que possa violar as permissões padrão (estritas), você pode mudar o SELinux do modo enforcing para o modo permissive, no seu ambiente de teste (se disponível) ou de produção. No modo permissive, o SELinux permite todas as operações, mas registra aquelas que violariam a política de segurança no modo enforcing.
Para adicionar httpd_t à lista de domínios permissivos, execute este comando:
# semanage permissive -a httpd_tPara remover httpd_t da lista de domínios permissivos, execute:
# semanage permissive -d httpd_tPara definir globalmente o modo como permissive, execute:
# setenforce 0Para definir globalmente o modo como enforcing, execute:
# setenforce 1Resolvendo exceções de segurança do SELinux
No modo permissivo, as exceções de segurança são registradas no log de auditoria padrão do Linux, /var/log/audit/audit.log. Se você encontrar um problema que ocorre somente quando o NGINX está sendo executado no modo impositivo, analise as exceções registradas no modo permissivo e atualize a política de segurança para permiti-las.
Problema 1: a conexão com o proxy é proibida
Por padrão, a configuração do SELinux não permite que o NGINX se conecte a servidores HTTP, FastCGI ou outros servidores remotos, conforme indicado por uma mensagem de log de auditoria como a seguinte:
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)O comando audit2why interpreta o código da mensagem (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 1A saída de audit2why indica que você pode permitir que o NGINX faça conexões de proxy habilitando uma ou ambas as opções booleanas httpd_can_network_relay e httpd_can_network_connect. Você pode habilitá-las temporária ou permanentemente; neste último caso, adicione a opção ‑P, conforme mostrado na saída.
Entendendo as opções booleanas
O comando sesearch fornece mais informações sobre as opções booleanas e fica disponível após a instalação do pacote setools (yum install setools). Aqui, mostramos a saída das opções httpd_can_network_relay e httpd_can_network_connect.
A opção booleana httpd_can_network_relay Boolean Option
Veja a saída do comando sesearch referente à opção 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 ;Essa saída indica que httpd_can_network_relay permite que processos rotulados com o contexto httpd_t (como o NGINX) se conectem a portas de vários tipos, incluindo o tipo http_port_t:
# semanage port -l | grep http_port_thttp_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000Para adicionar mais portas (neste caso, 8082) ao conjunto de portas permitidas para http_port_t, execute:
# semanage port -a -t http_port_t -p tcp 8082Se a saída desse comando informar que uma porta já está definida, como no exemplo a seguir, isso significa que a porta está incluída em outro conjunto. Não a reatribua a http_port_t, pois isso pode afetar negativamente outros serviços.
# 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-10010A opção booleana httpd_can_network_connect Boolean Option
Veja a saída do comando sesearch referente à opção 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 ;Essa saída indica que httpd_can_network_connect permite que processos rotulados com o contexto httpd_t (como o NGINX) se conectem a todos os tipos de soquete TCP que tenham o atributo port_type. Para listá-los, execute:
# seinfo -aport_type -xProblema 2: o acesso ao arquivo é proibido
Por padrão, a configuração do SELinux não permite que o NGINX acesse arquivos fora de locais autorizados conhecidos, conforme indicado por uma mensagem de log de auditoria como a seguinte:
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=fileO comando audit2why interpreta o código da mensagem (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.Quando o acesso ao arquivo é proibido, você tem duas opções.
Opção 1: Modificar o rótulo do arquivo
Modifique o rótulo do arquivo para que o NGINX (como um processo rotulado com o contexto httpd_t ) possa acessar o arquivo:
# chcon -v --type=httpd_sys_content_t /www/t.txtPor padrão, essa modificação é excluída quando o sistema de arquivos é rotulado novamente. Para tornar a alteração permanente, execute:
# semanage fcontext -a -t httpd_sys_content_t /www/t.txt
# restorecon -v /www/t.txtPara modificar os rótulos de grupos de arquivos, execute:
# semanage fcontext -a -t httpd_sys_content_t '/www(/.*)?'# restorecon -Rv /wwwOpção 2: Estenda as permissões do domínio httpd_t Domain Permissions
Estenda a política para httpd_t a fim de permitir o acesso a outros locais de arquivos:
# 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 gerar uma política compilada, inclua a opção -M:
# grep nginx /var/log/audit/audit.log | audit2allow -M nginxPara carregar a política, execute semodule -i, depois verifique se a operação foi bem-sucedida com semodule -l:
# semodule -i nginx.pp
# semodule -l | grep nginx
nginx 1.0Essa alteração persiste após reinicializações.
Problema 3: o NGINX não consegue se vincular a portas adicionais
Por padrão, a configuração do SELinux não permite que o NGINX escute (bind()) em portas TCP ou UDP diferentes das portas padrão permitidas no tipo http_port_t:
# semanage port -l | grep http_port_thttp_port_t tcp 80, 443, 488, 8008, 8009, 8443Se você tentar configurar o NGINX para escutar em uma porta que não está na lista de permissões (com a diretiva listen no contexto http, stream ou mail da configuração do NGINX), ocorrerá um erro ao verificar (nginx -t) ou recarregar a configuração do NGINX, conforme indicado por esta entrada de log do NGINX:
YYYY/MM/DD hh:mm:ss [emerg] 46123#0: bind() to 0.0.0.0:8001 failed (13: Permission denied)Você pode usar o comando semanage para adicionar a porta desejada (neste caso, 8001) ao tipo http_port_t:
# semanage port -a -t http_port_t -p tcp 8001Recarregue o NGINX com a nova configuração.
# nginx -s reloadProblema 4: Há muitos arquivos abertos — Erro
Quando o limite do número de arquivos abertos (RLIMIT_NOFILE) é excedido, a seguinte mensagem aparece no log de erros:
Too many files are openQuando o processo de trabalho do NGINX gera o erro
Na maioria dos casos, o processo de trabalho do NGINX relata esse erro, mas não é possível usar a diretiva worker_rlimit_nofile do NGINX para aumentar o limite, pois o SELinux não permite a chamada de sistema setrlimit() conforme relatado nas mensagens a seguir dos logs de erros e de auditoria.
- Em /var/log/nginx/error.log no CentOS/RHEL 7.4+:
YYYY/MM/DD hh:mm:ss [alert] 12066#0: setrlimit(RLIMIT_NOFILE, 2342) failed (13: Permission denied)- Em /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)- Em /var/log/audit/audit.log para CentOS/RHEL 7.4+ e /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 o limite, execute este comando como o usuário root:
$ setsebool -P httpd_setrlimit 1Quando o processo mestre do NGINX gera o erro
Se o processo mestre do NGINX relatar o erro, você precisará atualizar o arquivo systemd unit do NGINX. Isso define o limite de descritores de arquivo para os processos mestre e de trabalho.
- Crie um diretório para a configuração do
nginx.service:
$ mkdir /etc/systemd/system/nginx.service.d- Adicione as seguintes linhas a /etc/systemd/system/nginx.service.d/nofile_limit.conf:
[Service]LimitNOFILE=65535- Recarregue a configuração do daemon systemd e reinicie o NGINX:
$ systemctl daemon-reload$ systemctl restart nginx.serviceRecursos adicionais
O SELinux é um recurso complexo e poderoso para gerenciar permissões do sistema operacional. Informações adicionais estão disponíveis nos documentos a seguir.
- Linux com Segurança Aprimorada, RHEL 6 ou RHEL 7
- SELinux (Guia do CentOS)
- Guia do Usuário do Security-Enhanced Linux (projeto Fedora)
- Página inicial do projeto SELinux
- Linux com Segurança Aprimorada (Agência de Segurança Nacional dos Estados Unidos)
Sobre o autor

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.
Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.
Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.