Skip to content

Portal | Level: L2: Operations | Topics: Linux Hardening, Compliance & Audit, Audit Logging | Domain: Security

SELinux & Linux Hardening - Primer

Why This Matters

A default Linux installation is not secure. It is convenient. Every service runs with more permissions than it needs, every port is a potential entry point, and every misconfigured file permission is a privilege escalation waiting to happen. Hardening is the process of reducing the attack surface to only what the system actually needs to do its job.

Who made it: SELinux (Security-Enhanced Linux) was originally developed by the United States National Security Agency (NSA) and released as open source in 2000. It implements Mandatory Access Control (MAC) based on the Flask security architecture from the University of Utah. The NSA contributed it to the mainline Linux kernel in 2003 (kernel 2.6). Red Hat adopted it as the default security module for RHEL, Fedora, and CentOS.

SELinux is the most powerful — and most misunderstood — security tool in the Linux kernel. Most engineers disable it on day one because it "breaks things." What it actually does is prevent unauthorized access patterns, and the things it "breaks" are things that should not have been allowed in the first place. Understanding SELinux is the difference between a system that survives a compromised service and one that gives an attacker full root access.

Core Concepts

1. SELinux Modes

Enforcing   Policies are enforced. Violations are blocked AND logged.
Permissive  Policies are NOT enforced. Violations are logged only.
Disabled    SELinux is completely off. No logging, no enforcement.

Check current mode:
$ getenforce
Enforcing

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
# Temporarily switch to permissive (survives until reboot)
setenforce 0

# Switch back to enforcing
setenforce 1

# Persistent change: edit /etc/selinux/config
# SELINUX=enforcing

Warning: Going from Disabled to Enforcing requires a full filesystem relabel. This takes time and can brick a system if done wrong.

2. SELinux Contexts and Labels

Every file, process, port, and user has an SELinux context:

user:role:type:level

Example file context:
$ ls -Z /var/www/html/index.html
system_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html

Example process context:
$ ps -eZ | grep httpd
system_u:system_r:httpd_t:s0    1234 ?  00:00:01 httpd

Remember: SELinux context format mnemonic: URTLUser, Role, Type, Level. In targeted policy (the default on RHEL/CentOS), only the Type matters for enforcement. The type label on a process determines what files, ports, and resources it can access. Think of the type as a "security badge" — httpd_t can only enter rooms labeled httpd_sys_content_t.

The type field is what matters most in targeted policy:

Component Description Example
httpd_t Apache process type Can read httpd_sys_content_t files
httpd_sys_content_t Web content type Readable by httpd_t
httpd_sys_rw_content_t Writable web content Read/write by httpd_t
var_log_t Log files type Writable by logging processes
sshd_t SSH daemon type Can access SSH keys, PAM

3. SELinux Troubleshooting

# Check for recent denials
ausearch -m avc -ts recent

# Human-readable denial analysis
sealert -a /var/log/audit/audit.log

# Generate a policy module to allow a specific denial
ausearch -m avc -ts recent | audit2allow -M mypolicy

# Review the generated policy before applying
cat mypolicy.te

# Apply the policy module
semodule -i mypolicy.pp

# Check what booleans are available for a service
getsebool -a | grep httpd

# Enable a boolean (e.g., allow httpd to connect to network)
setsebool -P httpd_can_network_connect on

Common SELinux Denials and Fixes

Problem: Apache can't read files in /var/www/html/
  → Files have wrong context
  Fix: restorecon -Rv /var/www/html/

Problem: Nginx can't bind to port 8080
  → Port not labeled for http
  Fix: semanage port -a -t http_port_t -p tcp 8080

Problem: App can't write to /opt/myapp/data/
  → Directory has default_t context
  Fix: semanage fcontext -a -t httpd_sys_rw_content_t "/opt/myapp/data(/.*)?"
       restorecon -Rv /opt/myapp/data/

Problem: Service can't connect to database on network
  → Boolean not set
  Fix: setsebool -P httpd_can_network_connect_db on

4. CIS Benchmarks

The Center for Internet Security publishes hardening benchmarks for every major OS. These are the gold standard for compliance auditing.

CIS Benchmark Categories:
1. Filesystem Configuration (partitions, mount options, permissions)
2. Software Updates (package manager config, auto-updates)
3. Filesystem Integrity (AIDE, file integrity monitoring)
4. Boot Settings (GRUB password, single-user auth)
5. Process Hardening (core dumps, ASLR, ExecShield)
6. Mandatory Access Control (SELinux/AppArmor)
7. Command Line Warning Banners
8. Network Configuration (IP forwarding, ICMP, TCP wrappers)
9. Firewall (iptables/nftables/firewalld)
10. Logging and Auditing (rsyslog, auditd)
11. PAM and Password Policies
12. SSH Configuration
13. User Accounts and Environment

5. sysctl Hardening

# /etc/sysctl.d/99-hardening.conf

# Disable IP forwarding (unless this is a router)
net.ipv4.ip_forward = 0

# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1

# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0

# Log suspicious packets
net.ipv4.conf.all.log_martians = 1

# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1

# Restrict kernel pointer exposure
kernel.kptr_restrict = 2

# Restrict dmesg access
kernel.dmesg_restrict = 1

# Enable ASLR (Address Space Layout Randomization)
kernel.randomize_va_space = 2

# Restrict ptrace (prevent process tracing)
kernel.yama.ptrace_scope = 1

# Apply immediately
sysctl -p /etc/sysctl.d/99-hardening.conf

6. PAM Hardening

# /etc/pam.d/system-auth (or common-password on Debian)

# Enforce password complexity
password requisite pam_pwquality.so retry=3 \
    minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1

# Lock accounts after 5 failed attempts
auth required pam_faillock.so preauth silent audit deny=5 unlock_time=900
auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900

# Restrict su to wheel group
# /etc/pam.d/su
auth required pam_wheel.so use_uid

7. SSH Hardening

# /etc/ssh/sshd_config hardening

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers deploy ansible
Protocol 2
LogLevel VERBOSE

# Restrict ciphers and MACs
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512

8. File Permission Hardening

# Find world-writable files (should be minimal)
find / -type f -perm -0002 -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null

# Find SUID/SGID binaries (audit these)
find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -la {} \; 2>/dev/null

# Remove unnecessary SUID bits
chmod u-s /usr/bin/unnecessary-suid-binary

# Restrict home directory permissions
chmod 750 /home/*

# Secure cron directories
chmod 700 /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/cron.weekly /etc/cron.monthly
chown root:root /etc/crontab
chmod 600 /etc/crontab

# Restrict access to su
chown root:wheel /usr/bin/su
chmod 4750 /usr/bin/su

9. Auditd Rules

# /etc/audit/rules.d/hardening.rules

# Monitor file access to sensitive files
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k actions
-w /etc/ssh/sshd_config -p wa -k sshd

# Monitor login events
-w /var/log/lastlog -p wa -k logins
-w /var/log/faillog -p wa -k logins

# Monitor privilege escalation
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k privileged

# Monitor kernel module loading
-w /sbin/insmod -p x -k modules
-w /sbin/modprobe -p x -k modules

# Make audit config immutable (requires reboot to change)
-e 2

Common Pitfalls

Debug clue: When troubleshooting SELinux denials, always check /var/log/audit/audit.log for type=AVC messages first. The sealert -a command translates raw AVC messages into human-readable explanations with suggested fixes. If audit.log is empty but SELinux is blocking things, the denial might be in dontaudit rules — temporarily run semodule -DB to disable dontaudit rules and reveal hidden denials.

Analogy: Think of SELinux like airport security. Without SELinux (DAC only), anyone with a boarding pass (file permissions) can go anywhere in the airport. With SELinux (MAC), your boarding pass also has a specific gate number and zone — you can only access the areas matching your ticket type, regardless of what doors you can physically open.

  1. Disabling SELinux instead of fixing the policy — The single most common Linux hardening failure. Learn to read AVC denials and write targeted policy modules.
  2. Hardening a server but leaving default SSH keys — You locked every door but left the master key on the welcome mat.
  3. Not testing hardening changes in staging — A sysctl change that disables IP forwarding will break a server that is supposed to be a router.
  4. CIS compliance without understanding — Blindly applying every CIS recommendation without understanding your workload. Some benchmarks conflict with application requirements.
  5. Forgetting to persist changessetenforce 1 does not survive reboot. sysctl -w does not survive reboot. Always use the persistent config files.
  6. Auditing everything — An auditd configuration that logs every syscall will fill your disk and degrade performance. Be selective.
  7. Hardened AMIs that drift — You build a hardened AMI but never re-harden running instances. Configuration drift undoes your hardening within weeks.

Wiki Navigation

Prerequisites

Next Steps