SELinux’s security context labels can be directly applied to network packets using iptables, enabling fine-grained network access control beyond simple port and IP rules.
Let’s see this in action. Imagine we have two services, webserver and database, running in separate SELinux contexts. We want to restrict the webserver to only connect to the database on port 5432.
First, we need to identify the SELinux context of the processes.
ps auxZ | grep httpd
# Output might look like:
# system_u:system_r:httpd_t:s0 1234 0.0 1.2 123456 7890 ? Ss 10:00 0:00 /usr/sbin/httpd -DFOREGROUND
ps auxZ | grep postgres
# Output might look like:
# system_u:system_r:postgresql_t:s0 5678 0.1 2.0 234567 9876 ? Ss 10:05 0:01 /usr/libexec/postgresql/postgres -D /var/lib/pgsql/data
Here, httpd_t is the context for the web server and postgresql_t is for the database.
Now, we can use iptables with the SELinux match module (-m selinux) to inspect and manipulate the security context.
# Allow traffic from httpd_t to postgresql_t on port 5432
iptables -A OUTPUT -p tcp --dport 5432 -m owner --uid-owner apache -m selinux --selinux-source httpd_t -j ACCEPT
# Drop all other traffic from httpd_t to port 5432
iptables -A OUTPUT -p tcp --dport 5432 -m owner --uid-owner apache -m selinux --selinux-source httpd_t -j DROP
# Allow established connections for other traffic originating from httpd_t (optional but good practice)
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -m owner --uid-owner apache -j ACCEPT
# Drop all other outbound traffic from httpd_t
iptables -A OUTPUT -m owner --uid-owner apache -j DROP
Let’s break this down.
-A OUTPUT: We’re appending this rule to theOUTPUTchain, meaning it applies to packets originating from this host.-p tcp: We’re specifying the TCP protocol.--dport 5432: We’re targeting destination port 5432, which is the default for PostgreSQL.-m owner --uid-owner apache: This is a common way to identify traffic originating from the web server process. Assuming yourhttpdruns as theapacheuser.-m selinux --selinux-source httpd_t: This is the core of it. We’re using theselinuxmatch module to check if the source security context of the packet (which is derived from the originating process) ishttpd_t.-j ACCEPT: If all conditions match, the packet is allowed.-j DROP: If the packet is fromhttpd_tto port 5432 but doesn’t meet theACCEPTcriteria (or if we want to be explicit about dropping other traffic to that port), it’s dropped.
This setup ensures that only processes running with the httpd_t SELinux context can send traffic to port 5432. Even if you were to run another application as the apache user, if it doesn’t have the httpd_t SELinux context, it won’t be able to communicate with the database.
The iptables SELinux module can also inspect the destination security context. This is particularly useful for ingress filtering. For example, to ensure only httpd_t traffic can reach the postgresql_t context on port 5432:
# Allow traffic from httpd_t to postgresql_t on port 5432
iptables -A INPUT -p tcp --dport 5432 -m selinux --selinux-dest postgresql_t -m selinux --selinux-source httpd_t -j ACCEPT
# Drop all other traffic to port 5432
iptables -A INPUT -p tcp --dport 5432 -j DROP
Here, --selinux-dest postgresql_t verifies that the destination security context of the packet (which iptables can infer for locally bound ports) is indeed postgresql_t.
The key is that iptables can’t assign an SELinux context to a packet; it can only match against the context that the kernel has already associated with the packet, derived from the originating process. SELinux policies then dictate which contexts are allowed to communicate with which other contexts. iptables provides an additional layer of enforcement at the network packet level, complementing the system-wide SELinux policy.
You might also encounter situations where you need to explicitly allow specific network interfaces for certain SELinux contexts. For instance, if your httpd_t should only be allowed to bind to interfaces tagged with a specific network interface SELinux context:
# Example: Allow httpd_t to use an interface with context public_iface_t
iptables -A OUTPUT -o eth0 -m selinux --selinux-source httpd_t -j ACCEPT
This rule, combined with SELinux policy rules that allow httpd_t to use public_iface_t labeled network interfaces, provides a robust security posture.
When you’re troubleshooting, remember that SELinux context is derived from the process. If a process doesn’t have the expected context, iptables rules based on that context will fail. Use sealert -a /var/log/audit/audit.log to check for SELinux denials.
The next hurdle you’ll face is understanding how to manage the SELinux policy itself, which dictates what security contexts are allowed to interact, rather than just relying on iptables to enforce those decisions at the network layer.