← Back to DevBytes

Securing RHEL Servers: A Practical Checklist

Introduction to Securing RHEL Servers

Red Hat Enterprise Linux (RHEL) is a popular choice for enterprise server deployments due to its stability, long-term support, and robust security features. However, a default installation is not secure by itself — it requires deliberate hardening to protect against modern threats. This tutorial provides a practical, hands-on checklist for securing RHEL servers, covering everything from initial installation hardening to ongoing monitoring.

Why Server Hardening Matters

Unsecured servers are prime targets for attackers. A single misconfiguration can expose sensitive data, allow lateral movement across your network, or result in a full system compromise. Hardening your RHEL servers reduces the attack surface, limits the blast radius of any breach, and helps you meet compliance requirements such as PCI-DSS, HIPAA, and FedRAMP.

1. Initial System Updates and Package Management

The first step in securing any RHEL server is ensuring all installed packages are up to date. Red Hat regularly releases security patches for vulnerabilities, and applying them promptly is one of the most effective defenses available.

Updating the System

Use the following commands to update your system and verify the installed RHEL version:

# Check the current RHEL version
cat /etc/redhat-release

# Update all packages to the latest versions
sudo dnf update -y

# Reboot if a kernel update was applied
sudo reboot

Enabling Automatic Security Updates

For production servers, consider enabling automatic security updates using dnf-automatic. This ensures critical patches are applied without manual intervention:

# Install the dnf-automatic package
sudo dnf install -y dnf-automatic

# Edit the configuration to apply security updates only
sudo sed -i 's/upgrade_type = default/upgrade_type = security/' /etc/dnf/automatic.conf
sudo sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf

# Enable and start the timer
sudo systemctl enable --now dnf-automatic.timer

2. User Account Management and Access Control

Proper user management is foundational to server security. The principle of least privilege should guide every decision about who can access the system and what they can do.

Disabling Root Login Over SSH

Direct root login over SSH is a major security risk. Instead, administrators should log in with individual accounts and escalate privileges using sudo. Edit the SSH daemon configuration to disable root login:

# Edit the SSH configuration
sudo vi /etc/ssh/sshd_config

# Set the following directives
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

# Restart the SSH service
sudo systemctl restart sshd

Creating Administrative Users

Create individual accounts for each administrator and add them to the wheel group for sudo access:

# Create a new user with a home directory
sudo useradd -m -c "Jane Admin" jane

# Set a strong password
sudo passwd jane

# Add the user to the wheel group for sudo access
sudo usermod -aG wheel jane

# Verify group membership
groups jane

Configuring Sudo Policies

Use granular sudo policies to limit what each administrator can do. Create a dedicated sudoers file for custom rules:

# Create a custom sudoers file
sudo visudo -f /etc/sudoers.d/admins

# Add the following rules
# Allow wheel group full sudo access with password
%wheel ALL=(ALL) ALL

# Allow a specific user to restart only the web service
jane ALL=(root) /usr/bin/systemctl restart httpd

# Log all sudo commands to a separate file
Defaults logfile=/var/log/sudo.log
Defaults log_year, log_input, log_output

Setting Up SSH Key-Based Authentication

SSH keys are far more secure than passwords. Generate a key pair on your local machine and copy the public key to the server:

# On the local machine, generate an ed25519 key pair
ssh-keygen -t ed25519 -C "jane@workstation"

# Copy the public key to the server
ssh-copy-id jane@server.example.com

# Test the login
ssh jane@server.example.com

3. Firewall Configuration with firewalld

RHEL includes firewalld as the default firewall management tool. It provides a zone-based approach to network security, allowing you to define different trust levels for different network interfaces.

Basic Firewall Setup

Start by enabling firewalld and reviewing the current configuration:

# Enable and start firewalld
sudo systemctl enable --now firewalld

# Check the firewall state
sudo firewall-cmd --state

# List all active zones
sudo firewall-cmd --get-active-zones

# List all services in the public zone
sudo firewall-cmd --zone=public --list-all

Allowing Specific Services

Only open ports that are absolutely necessary. For example, if the server is a web server, allow HTTP and HTTPS traffic:

# Allow HTTP and HTTPS permanently
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# Allow SSH (if not already allowed)
sudo firewall-cmd --permanent --add-service=ssh

# Reload the firewall to apply changes
sudo firewall-cmd --reload

# Verify the configuration
sudo firewall-cmd --zone=public --list-all

Restricting SSH to Specific IP Addresses

For additional security, restrict SSH access to specific IP addresses or ranges using rich rules:

# Remove the default SSH service
sudo firewall-cmd --permanent --remove-service=ssh

# Allow SSH only from a specific IP address
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" accept'

# Allow SSH from a specific subnet
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" service name="ssh" accept'

# Reload the firewall
sudo firewall-cmd --reload

4. SELinux Configuration

Security-Enhanced Linux (SELinux) is a mandatory access control system built into RHEL. It provides fine-grained control over what processes can access, significantly reducing the impact of security vulnerabilities.

Checking SELinux Status

Always verify that SELinux is enabled and running in enforcing mode:

# Check the current SELinux mode
getenforce

# Get detailed SELinux status
sestatus

# Check SELinux booleans
sudo semanage boolean -l

Setting SELinux to Enforcing Mode

If SELinux is disabled or in permissive mode, enable enforcing mode. Note that changing from disabled to enforcing requires a relabel and reboot:

# Edit the SELinux configuration
sudo vi /etc/selinux/config

# Set SELINUX to enforcing
SELINUX=enforcing

# If transitioning from disabled, relabel the filesystem
sudo touch /.autorelabel
sudo reboot

Troubleshooting SELinux Denials

When SELinux blocks an action, it logs an AVC denial. Use the following tools to identify and resolve issues:

# Install troubleshooting tools
sudo dnf install -y setroubleshoot-server setools-console

# View recent SELinux denials
sudo ausearch -m AVC,USER_AVC -ts recent

# Get human-readable explanations of denials
sudo sealert -a /var/log/audit/audit.log

# List all SELinux denials with details
sudo audit2why -a

Managing SELinux Contexts for Custom Paths

If you move web content to a non-standard directory, you must update the SELinux context:

# Change the context of a custom web directory
sudo semanage fcontext -a -t httpd_sys_content_t '/custom/web(/.*)?'

# Apply the new context
sudo restorecon -Rv /custom/web

# Verify the context
ls -Z /custom/web

5. Securing Network Services

Beyond the firewall, individual services must be configured securely. This section covers hardening common services found on RHEL servers.

Hardening the SSH Daemon

SSH is one of the most targeted services. Apply these additional hardening measures:

# Edit the SSH daemon configuration
sudo vi /etc/ssh/sshd_config

# Apply the following hardening settings
Port 2222                    # Change the default port
Protocol 2                   # Use only SSH protocol 2
MaxAuthTries 3               # Limit authentication attempts
LoginGraceTime 30            # Reduce login grace period
AllowUsers jane bob          # Allow only specific users
X11Forwarding no             # Disable X11 forwarding
ClientAliveInterval 300      # Set idle timeout
ClientAliveCountMax 0        # Disconnect after timeout
AllowTcpForwarding no        # Disable TCP forwarding
PermitTunnel no              # Disable tunneling

# Restart SSH to apply changes
sudo systemctl restart sshd

Securing the Web Server (Apache/httpd)

If running Apache, apply security headers and disable unnecessary modules:

# Install the headers module
sudo dnf install -y mod_ssl

# Edit the Apache configuration
sudo vi /etc/httpd/conf/httpd.conf

# Add security headers
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

# Hide Apache version information
ServerTokens Prod
ServerSignature Off

# Test the configuration and restart
sudo httpd -t
sudo systemctl restart httpd

Disabling Unused Services

Reduce the attack surface by disabling services that are not needed:

# List all enabled services
sudo systemctl list-unit-files --type=service --state=enabled

# Disable unnecessary services
sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now cups
sudo systemctl disable --now bluetooth

# Mask services to prevent them from being started
sudo systemctl mask avahi-daemon

6. File System and Kernel Hardening

Kernel parameters and file system mount options provide additional layers of security. The sysctl interface allows you to tune kernel behavior at runtime.

Applying Kernel Security Parameters

Create a dedicated sysctl configuration file for security settings:

# Create a custom sysctl configuration
sudo vi /etc/sysctl.d/99-security.conf

# Add the following security parameters

# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

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

# Ignore ICMP redirect messages
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

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

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

# Enable TCP SYN cookies
net.ipv4.tcp_syncookies = 1

# Disable core dumps for SUID programs
fs.suid_dumpable = 0

# Apply the changes
sudo sysctl --system

Securing /tmp with Mount Options

The /tmp directory is world-writable and a common target for attacks. Mount it with security-enhancing options:

# Add a tmpfs entry for /tmp in fstab
sudo vi /etc/fstab

# Add the following line
tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec,mode=1777 0 0

# Remount /tmp
sudo mount -o remount /tmp

# Verify the mount options
mount | grep /tmp

Setting Secure Permissions on Key Files

Ensure critical system files have appropriate permissions:

# Restrict permissions on cron directories
sudo chmod 700 /etc/cron.d
sudo chmod 700 /etc/cron.daily
sudo chmod 700 /etc/cron.hourly
sudo chmod 700 /etc/cron.weekly
sudo chmod 700 /etc/cron.monthly

# Restrict permissions on SSH configuration
sudo chmod 600 /etc/ssh/sshd_config
sudo chmod 700 /etc/ssh

# Restrict access to the hosts file
sudo chmod 644 /etc/hosts

7. Auditing and Logging

Comprehensive logging and auditing are essential for detecting security incidents and conducting forensic investigations. RHEL includes the Linux Audit daemon (auditd) for system auditing.

Configuring the Audit Daemon

Install and configure auditd to monitor critical system events:

# Install auditd
sudo dnf install -y audit

# Enable and start the audit daemon
sudo systemctl enable --now auditd

# Edit the audit configuration
sudo vi /etc/audit/auditd.conf

# Set the following parameters
log_file = /var/log/audit/audit.log
max_log_file = 100
max_log_file_action = ROTATE
space_left = 75
space_left_action = EMAIL
action_mail_acct = root
admin_space_left = 50
admin_space_left_action = HALT
disk_full_action = HALT

# Restart auditd to apply changes
sudo service auditd restart

Adding Audit Rules

Create custom audit rules to monitor important files and activities:

# Create a custom rules file
sudo vi /etc/audit/rules.d/custom.rules

# Monitor changes to the passwd file
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/gshadow -p wa -k identity

# Monitor sudoers files
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d/ -p wa -k scope

# Monitor SSH configuration changes
-w /etc/ssh/sshd_config -p wa -k ssh_config

# Monitor login and logout events
-w /var/log/lastlog -p wa -k logins
-w /var/run/faillock/ -p wa -k logins

# Monitor system time changes
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change

# Load the new rules
sudo augenrules --load

# Verify the rules are loaded
sudo auditctl -l

Reviewing Audit Logs

Use the ausearch and aureport tools to analyze audit logs:

# Search for identity-related events
sudo ausearch -k identity

# Generate a summary report of all audit events
sudo aureport --summary

# Generate a report of failed login attempts
sudo aureport --auth --failed

# Search for events within a specific time range
sudo ausearch --start today --end now -k ssh_config

Configuring Log Rotation and Remote Logging

For production environments, forward logs to a central logging server to prevent tampering:

# Install rsyslog (usually pre-installed)
sudo dnf install -y rsyslog

# Configure remote logging
sudo vi /etc/rsyslog.conf

# Add the following to forward all logs to a remote server
*.* @@logserver.example.com:6514

# Ensure TLS is used for secure transmission
# (requires certificate configuration - see rsyslog documentation)

# Restart rsyslog
sudo systemctl restart rsyslog

8. Intrusion Detection with AIDE

Advanced Intrusion Detection Environment (AIDE) is a file integrity checker that creates a database of file attributes and alerts you when changes occur. It is essential for detecting unauthorized modifications.

Installing and Initializing AIDE

# Install AIDE
sudo dnf install -y aide

# Initialize the AIDE database (this may take several minutes)
sudo aide --init

# Move the initialized database to the production location
sudo cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

# Verify the database was created
ls -la /var/lib/aide/

Running Integrity Checks

Schedule regular integrity checks using cron:

# Create a cron job for daily AIDE checks
sudo crontab -e

# Add the following line to run a check every day at 2 AM
0 2 * * * /usr/sbin/aide --check | mail -s "AIDE Daily Report" root@localhost

# Run a manual check
sudo aide --check

Updating the AIDE Database After Legitimate Changes

After making legitimate system changes (such as package updates), update the AIDE database:

# Run a check and update the database
sudo aide --update

# Replace the old database with the updated one
sudo cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

9. Using OpenSCAP for Compliance Scanning

OpenSCAP is a framework for compliance scanning and vulnerability assessment. RHEL includes SCAP Security Guide (SSG) profiles that map to various security standards.

Installing and Running a Scan

# Install OpenSCAP and the SCAP Security Guide
sudo dnf install -y openscap-scanner scap-security-guide

# List available profiles
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

# Run a scan against the PCI-DSS profile
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_pci-dss \
  --results scan-results.xml \
  --report scan-report.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

# View the HTML report
sudo cp scan-report.html /var/www/html/

Generating a Remediation Script

OpenSCAP can generate a bash script that automatically remediates failed checks:

# Generate a remediation script
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_pci-dss \
  --results scan-results.xml \
  --remediate \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Review the remediation script carefully before running it, as some changes may affect application functionality.

10. Best Practices and Ongoing Maintenance

Security is not a one-time task but an ongoing process. The following best practices will help you maintain a secure RHEL environment over time.

Regular Security Tasks

Implementing Fail2Ban for Brute Force Protection

While not included by default, Fail2Ban provides additional protection against brute force attacks:

# Enable the EPEL repository
sudo dnf install -y epel-release

# Install Fail2Ban
sudo dnf install -y fail2ban

# Create a local configuration file
sudo vi /etc/fail2ban/jail.local

# Add the following configuration
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = firewallcmd-rich-rules[actiontype=]

[sshd]
enabled = true
port = 2222
logpath = %(sshd_log)s

# Enable and start Fail2Ban
sudo systemctl enable --now fail2ban

# Check the status
sudo fail2ban-client status
sudo fail2ban-client status sshd

Documenting Your Configuration

Maintain detailed documentation of all security configurations, including:

Automating with Ansible

For managing multiple servers, use Ansible to automate security configurations. Here is a simple playbook example:

# secure-rhel.yml
---
- name: Secure RHEL Server
  hosts: all
  become: yes
  tasks:
    - name: Update all packages
      dnf:
        name: "*"
        state: latest

    - name: Ensure firewalld is enabled and running
      systemd:
        name: firewalld
        enabled: yes
        state: started

    - name: Allow only SSH and HTTP/HTTPS through the firewall
      ansible.posix.firewalld:
        service: "{{ item }}"
        permanent: yes
        state: enabled
      loop:
        - ssh
        - http
        - https
      notify: reload firewalld

    - name: Disable root login over SSH
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: restart sshd

    - name: Ensure SELinux is in enforcing mode
      selinux:
        policy: targeted
        state: enforcing

  handlers:
    - name: reload firewalld
      systemd:
        name: firewalld
        state: reloaded

    - name: restart sshd
      systemd:
        name: sshd
        state: restarted

Run the playbook with:

ansible-playbook -i inventory secure-rhel.yml

Conclusion

Securing a RHEL server requires a multi-layered approach that addresses user access, network exposure, service configuration, kernel parameters, file integrity, and continuous monitoring. By following this practical checklist, you establish a strong security baseline that significantly reduces your server's attack surface. Remember that security is an ongoing process — regularly review your configurations, apply updates promptly, monitor audit logs, and adapt your defenses to emerging threats. Combining the built-in RHEL security tools like SELinux, firewalld, and auditd with additional measures such as AIDE, OpenSCAP, and Fail2Ban creates a defense-in-depth strategy that protects your infrastructure against both opportunistic and targeted attacks. Always test changes in a staging environment before applying them to production, and maintain thorough documentation to support both operational efficiency and compliance audits.

— Ad —

Google AdSense will appear here after approval

← Back to all articles