Using NGINX and NGINX Plus with SELinux

NGINX | August 17, 2018

Editor – The blog post titled “NGINX: SELinux Changes when Upgrading to RHEL 6.6 / CentOS 6.6” redirects here. This article provides updated and generalized information.

The default settings for Security-Enhanced Linux (SELinux) on modern Red Hat Enterprise Linux (RHEL) and related distros can be very strict, erring on the side of security rather than convenience. Although the default settings do not limit the functioning of NGINX Open Source and NGINX Plus in their default configurations, other features you might configure can be blocked unless you explicitly allow them in SELinux. This article describes the possible issues and recommended ways to resolve them.

[Editor – This article applies to both NGINX Open Source and NGINX Plus. For ease of reading, the term “NGINX” is used throughout.

CentOS is a related distro originally derived from RHEL and is supported by NGINX and NGINX Plus. In addition, NGINX Plus supports the related Amazon Linux and Oracle Linux distros. Their default SELinux settings might differ from CentOS and RHEL; consult the vendor documentation.]

Overview of SELinux

SELinux is enabled by default on modern RHEL and CentOS servers. Each operating system object (process, file descriptor, file, etc.) is labeled with an SELinux context that defines the permissions and operations the object can perform. In RHEL 6.6/CentOS 6.6 and later, NGINX is labeled with the httpd_t context:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

The httpd_t context permits NGINX to listen on common web server ports, to access configuration files in /etc/nginx, and to access content in the standard docroot location (/usr/share/nginx). It does not permit many other operations, such as proxying to upstream locations or communicating with other processes through sockets.

Temporarily Disabling SELinux for NGINX

To temporarily disable SELinux restrictions for the httpd_t context, so that NGINX can perform all the same operations as in non‑SELinux OSs, assign the httpd_t context to the permissive domain. See the next section for details.

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

Changing SELinux Modes

SELinux can be run in enforcing, permissive, or disabled modes (also referred to as domains). Before you make an NGINX configuration change that might breach the default (strict) permissions, you can change SELinux from enforcing to permissive mode, in your test environment (if available) or production environment. In permissive mode, SELinux permits all operations, but logs operations that would have breached the security policy in enforcing mode.

To add httpd_t to the list of permissive domains, run this command:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To delete httpd_t from the list of permissive domains, run:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To set the mode globally to permissive, run:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To set the mode globally to enforcing, run:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

Resolving SELinux Security Exceptions

In permissive mode, security exceptions are logged to the default Linux audit log, /var/log/audit/audit.log. If you encounter a problem that occurs only when NGINX is running in enforcing mode, review the exceptions that are logged in permissive mode and update the security policy to permit them.

Issue 1: Proxy Connection is Forbidden

By default, the SELinux configuration does not allow NGINX to connect to remote HTTP, FastCGI, or other servers, as indicated by an audit log message like the following:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

The audit2why command interprets the message code (1415714880.156:29):

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

The output from audit2why indicates that you can allow NGINX to make proxy connections by enabling one or both of the httpd_can_network_relay and httpd_can_network_connect Boolean options. You can enable them either temporarily or permanently, the latter by adding the ‑P flag as shown in the output.

Understanding Boolean Options

The sesearch command provides more information about the Boolean options, and is available if you install the setools package (yum install setools). Here we show the output for the httpd_can_network_relay and httpd_can_network_connect options.

The httpd_can_network_relay Boolean Option

Here’s the output from the sesearch command about the httpd_can_network_relay option:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

This output indicates that httpd_can_network_relay allows processes labeled with the httpd_t context (such as NGINX) to connect to ports of various types, including type http_port_t:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To add more ports (here, 8082) to the set of ports permitted for http_port_t, run:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

If the output from this command says that a port is already defined, as in the following example, it means the port is included in another set. Do not reassign it to http_port_t, because other services might be negatively affected.

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

The httpd_can_network_connect Boolean Option

Here’s the output from the sesearch command about the httpd_can_network_connect option:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

This output indicates that httpd_can_network_connect allows processes labeled with the httpd_t context (such as NGINX) to connect to all TCP socket types that have the port_type attribute. To list them, run:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

Issue 2: File Access is Forbidden

By default, the SELinux configuration does not allow NGINX to access files outside of well‑known authorized locations, as indicated by an audit log message like the following:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

The audit2why command interprets the message code (1415715270.766:31):

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

When file access is forbidden, you have two options.

Option 1: Modify the File Label

Modify the file label so that NGINX (as a process labeled with the httpd_t context) can access the file:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

By default, this modification is deleted when the file system is relabeled. To make the change permanent, run:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To modify file labels for groups of files, run:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

Option 2: Extend the httpd_t Domain Permissions

Extend the policy for httpd_t to allow access to additional file locations:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To generate a compiled policy, include the -M option:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To load the policy, run semodule -i, then verify success with semodule -l:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

This change persists across reboots.

Issue 3: NGINX Cannot Bind to Additional Ports

By default, the SELinux configuration does not allow NGINX to listen (bind()) to TCP or UDP ports other than the default ones that are allowlisted in the http_port_t type:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

If you try to configure NGINX to listen on a non‑allowlisted port (with the listen directive in the http, stream, or mail context in the NGINX configuration), you get an error when you verify (nginx -t) or reload the NGINX configuration, as indicated by this NGINX log entry:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

You can use semanage to add the desired port (here, 8001) to the http_port_t type:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

Reload NGINX with the new configuration.

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

Issue 4: Too many files are open Error

When the limit on the number of open files (RLIMIT_NOFILE) is exceeded, the following message appears in the error log:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

When the NGINX Worker Process Generates the Error

In most cases, the NGINX worker process reports this error, but you cannot use the NGINX worker_rlimit_nofile directive to increase the limit because SELinux doesn’t allow the setrlimit() system call, as reported in the following messages in error and audit logs.

  • In /var/log/nginx/error.log for CentOS/RHEL 7.4+: [@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop
  • In /var/log/nginx/error.log for CentOS/RHEL 8.0+: [@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop
  • In /var/log/audit/audit.log for CentOS/RHEL 7.4+ and /var/log/messages for CentOS/RHEL 8.0+: [@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

To increase the limit, instead run this command as the root user:

[@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

When the NGINX Master Process Generates the Error

If the NGINX master process reports the error, you need to update the systemd unit file for NGINX. This sets the file descriptor limit for both master and worker processes.

  1. Create a directory for the nginx.service configuration: [@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop
  2. Add the following lines to /etc/systemd/system/nginx.service.d/nofile_limit.conf: [@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop
  3. Reload the systemd daemon configuration and restart NGINX: [@portabletext/react] Unknown block type "codeBlock", specify a component for it in the `components.types` prop

Additional Resources

SELinux is a complex and powerful facility for managing operating system permissions. Additional information is available in the following documents.


Share

About the Author

Owen Garrett
Owen GarrettSr. Director, Product Management

More blogs by Owen Garrett

Related Blog Posts

Automating Certificate Management in a Kubernetes Environment
NGINX | 10/05/2022

Automating Certificate Management in a Kubernetes Environment

Simplify cert management by providing unique, automatically renewed and updated certificates to your endpoints.

Secure Your API Gateway with NGINX App Protect WAF
NGINX | 05/26/2022

Secure Your API Gateway with NGINX App Protect WAF

As monoliths move to microservices, applications are developed faster than ever. Speed is necessary to stay competitive and APIs sit at the front of these rapid modernization efforts. But the popularity of APIs for application modernization has significant implications for app security.

How Do I Choose? API Gateway vs. Ingress Controller vs. Service Mesh
NGINX | 12/09/2021

How Do I Choose? API Gateway vs. Ingress Controller vs. Service Mesh

When you need an API gateway in Kubernetes, how do you choose among API gateway vs. Ingress controller vs. service mesh? We guide you through the decision, with sample scenarios for north-south and east-west API traffic, plus use cases where an API gateway is the right tool.

Deploying NGINX as an API Gateway, Part 2: Protecting Backend Services
NGINX | 01/20/2021

Deploying NGINX as an API Gateway, Part 2: Protecting Backend Services

In the second post in our API gateway series, Liam shows you how to batten down the hatches on your API services. You can use rate limiting, access restrictions, request size limits, and request body validation to frustrate illegitimate or overly burdensome requests.

New Joomla Exploit CVE-2015-8562
NGINX | 12/15/2015

New Joomla Exploit CVE-2015-8562

Read about the new zero day exploit in Joomla and see the NGINX configuration for how to apply a fix in NGINX or NGINX Plus.

Why Do I See “Welcome to nginx!” on My Favorite Website?
NGINX | 01/01/2014

Why Do I See “Welcome to nginx!” on My Favorite Website?

The ‘Welcome to NGINX!’ page is presented when NGINX web server software is installed on a computer but has not finished configuring

Deliver and Secure Every App
F5 application delivery and security solutions are built to ensure that every app and API deployed anywhere is fast, available, and secure. Learn how we can partner to deliver exceptional experiences every time.
Connect With Us
Using NGINX and NGINX Plus with SELinux | F5