🔒 Linux Security Basics

Security Series: Part 1 — Security Basics  |  Part 2 — SSH Hardening  |  Part 3 — Firewall Management  |  Part 4 — Auditing & Compliance

Security as a Practice, Not a Product

Linux security is not a checkbox — it is a continuous practice of reducing attack surface, monitoring for anomalies, applying updates, and following the principle of least privilege. A freshly installed Linux server is not secure by default. It needs to be hardened, configured, and monitored.

This page covers the foundational security practices every sysadmin should apply to every server: system updates, service minimization, file permissions, failed login monitoring, and basic intrusion detection. Parts 2-4 cover SSH hardening, firewall management, and auditing in depth.

Security Fundamentals

🔄
Keep Updated

Patch management is the single highest-impact security control.

✂️
Minimize Services

Every running service is an attack surface. Run only what you need.

🔑
Least Privilege

Users and services get only the access they need — nothing more.

📋
Audit Everything

Log actions, review logs, know what normal looks like.

🛡️
Defense in Depth

Multiple layers — no single control is enough on its own.

💬
Know Your Baseline

You cannot detect intrusion without knowing what normal looks like.

Examples

1
System Updates — Patch Management
### RHEL / Rocky / AlmaLinux ###

# Check for available updates
sudo dnf check-update

# Apply all updates
sudo dnf update -y

# Apply security updates only
sudo dnf update --security -y

# List installed security updates
sudo dnf updateinfo list security installed

# Check if reboot is required
sudo needs-restarting -r

# Enable automatic security updates
sudo dnf install -y dnf-automatic
sudo vi /etc/dnf/automatic.conf
# Set: apply_updates = yes
#      upgrade_type = security
sudo systemctl enable --now dnf-automatic.timer

### Debian / Ubuntu ###

sudo apt update && sudo apt upgrade -y
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades
Patch Tuesday mindset: Security updates should be applied within 24-48 hours of release for critical vulnerabilities. Non-security updates can follow a slower change management process. Automate security-only updates and manually review the rest.
2
Minimize Running Services
# List ALL running services
systemctl list-units --type=service --state=running

# List ALL enabled services (start at boot)
systemctl list-unit-files --type=service --state=enabled

# Check what is listening on the network
sudo ss -tulpn
sudo ss -tulpn | grep LISTEN

# Disable and stop services you don't need
sudo systemctl disable --now bluetooth
sudo systemctl disable --now cups        # printing (server)
sudo systemctl disable --now avahi-daemon # mDNS discovery
sudo systemctl disable --now postfix     # if not a mail server
sudo systemctl disable --now rpcbind     # if not using NFS

# Mask a service -- completely prevent it from starting
sudo systemctl mask telnet.socket
sudo systemctl mask rsh.socket
sudo systemctl mask rlogin.socket
💡 The question to ask for every service: “Do I know what this does and do I need it?” If the answer to either part is no, disable it. Every listening port is a potential entry point. ss -tulpn on a fresh install often reveals several services you did not intentionally enable.
3
File Permission Auditing
# Find world-writable files (security risk)
sudo find / -xdev -type f -perm -0002 -ls 2>/dev/null

# Find world-writable directories
sudo find / -xdev -type d -perm -0002-ls 2>/dev/null | grep -v sticky

# Find SUID files (run as owner, usually root)
sudo find / -xdev -type f -perm -4000 -ls 2>/dev/null

# Find SGID files
sudo find / -xdev -type f -perm -2000 -ls 2>/dev/null

# Find files with no owner (orphaned)
sudo find / -xdev -nouser -ls 2>/dev/null
sudo find / -xdev -nogroup -ls 2>/dev/null

# Check critical file permissions
ls -la /etc/passwd /etc/shadow /etc/group /etc/gshadow
ls -la /etc/sudoers
ls -la /etc/ssh/sshd_config
Expected critical file permissions:
-rw-r--r--. 1 root root /etc/passwd (644) ---------. 1 root root /etc/shadow (000 or 640) -rw-r--r--. 1 root root /etc/group (644) ---------. 1 root root /etc/gshadow (000 or 640) -r--r-----. 1 root root /etc/sudoers (440)
⚠️ SUID binaries are high-value targets. A SUID binary runs with the owner's privileges regardless of who executes it. Unexpected SUID files — especially new ones that appeared since your baseline — are a red flag for compromise. Know your baseline SUID list and monitor it.
4
Monitor Failed Logins and Brute Force
# View failed login attempts
sudo journalctl -u sshd | grep "Failed"
sudo grep "Failed password" /var/log/secure | tail -20   # RHEL
sudo grep "Failed password" /var/log/auth.log | tail -20 # Debian

# Count failed attempts by IP
sudo grep "Failed password" /var/log/secure | \
    awk '{print $11}' | sort | uniq -c | sort -rn | head -20

# View successful logins
last | head -20
lastlog | grep -v "Never"

# Install and configure fail2ban
sudo dnf install -y fail2ban    # RHEL
sudo apt install -y fail2ban    # Debian/Ubuntu

# Create local jail config
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime  = 3600
findtime = 600
maxretry = 5
backend  = systemd

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

sudo systemctl enable --now fail2ban

# Check fail2ban status
sudo fail2ban-client status
sudo fail2ban-client status sshd
fail2ban-client status sshd:
Status for the jail: sshd |- Filter | |- Currently failed: 3 | |- Total failed: 847 | `- File list: /var/log/secure `- Actions |- Currently banned: 12 |- Total banned: 89 `- Banned IP list: 203.0.113.5 198.51.100.22 ...
5
Secure /tmp and Shared Memory
# Check current /tmp mount options
mount | grep /tmp
findmnt /tmp

# /tmp should be mounted with noexec,nosuid,nodev
# Add to /etc/fstab if /tmp is not already restricted:
sudo vi /etc/fstab
# Add or modify:
# tmpfs  /tmp  tmpfs  rw,nosuid,nodev,noexec,relatime  0 0

# Secure shared memory (/run/shm or /dev/shm)
# Add to /etc/fstab:
# tmpfs  /dev/shm  tmpfs  rw,nosuid,nodev,noexec  0 0

# Apply without reboot
sudo mount -o remount,noexec,nosuid,nodev /tmp

# Verify
mount | grep /tmp
noexec on /tmp prevents a common attack vector. Many exploits write a script or binary to /tmp and execute it. noexec prevents execution of any file from /tmp. nosuid prevents SUID binaries from being effective there. nodev prevents device files.
6
Kernel Security Parameters — sysctl
# Create a security sysctl config file
sudo tee /etc/sysctl.d/99-security.conf << 'EOF'
# Disable IP forwarding (unless this is a router)
net.ipv4.ip_forward = 0

# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 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

# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1

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

# Protect against smurf attacks
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Restrict core dumps
fs.suid_dumpable = 0

# Hide kernel pointers from unprivileged users
kernel.kptr_restrict = 2

# Restrict dmesg to root
kernel.dmesg_restrict = 1
EOF

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

# Verify a specific setting
sysctl net.ipv4.tcp_syncookies
sysctl kernel.kptr_restrict
💡 sysctl settings are persistent across reboots when placed in /etc/sysctl.d/. Changes take effect immediately with sysctl -p without a reboot.
7
Check for Unauthorized Users and Accounts
# List all accounts with login shells (interactive users)
awk -F: '$7 !~ /nologin|false|sync|halt|shutdown/ {print $1, $3, $7}' /etc/passwd

# Find accounts with UID 0 (root-equivalent)
awk -F: '$3 == 0 {print $1}' /etc/passwd

# Find accounts with empty passwords
sudo awk -F: '$2 == "" {print $1}' /etc/shadow

# Check for recently modified password files
ls -la /etc/passwd /etc/shadow /etc/group /etc/sudoers

# Check who has sudo access
sudo grep -v "^#\|^$" /etc/sudoers
sudo ls /etc/sudoers.d/
sudo grep -r "ALL" /etc/sudoers.d/

# Check for .rhosts and hosts.equiv files (legacy, dangerous)
sudo find / -name ".rhosts" -o -name "hosts.equiv" 2>/dev/null

# Check for authorized_keys files
sudo find /home /root -name "authorized_keys" -ls 2>/dev/null
Know your accounts. Run this audit monthly and diff it against last month. New UID-0 accounts, new sudo entries, or new authorized_keys files that you did not create are immediate red flags requiring investigation.
8
Security Baseline Snapshot Script
#!/bin/bash
# security-baseline.sh -- capture system security state for comparison

OUTDIR="/var/log/security-baseline"
DATE=$(date +%Y%m%d-%H%M%S)
OUTFILE="$OUTDIR/baseline-$DATE.txt"

mkdir -p "$OUTDIR"

{
echo "=== Security Baseline: $(hostname) ==="
echo "=== Date: $(date) ==="
echo ""

echo "--- LISTENING PORTS ---"
ss -tulpn

echo ""
echo "--- RUNNING SERVICES ---"
systemctl list-units --type=service --state=running --no-pager

echo ""
echo "--- ENABLED SERVICES ---"
systemctl list-unit-files --type=service --state=enabled --no-pager

echo ""
echo "--- UID 0 ACCOUNTS ---"
awk -F: '$3 == 0 {print $1}' /etc/passwd

echo ""
echo "--- INTERACTIVE ACCOUNTS ---"
awk -F: '$7 !~ /nologin|false/ && $3 >= 1000 {print $1, $3}' /etc/passwd

echo ""
echo "--- SUDO ACCESS ---"
grep -v "^#\|^$" /etc/sudoers 2>/dev/null
find /etc/sudoers.d -type f -exec cat {} \; 2>/dev/null

echo ""
echo "--- SUID BINARIES ---"
find / -xdev -type f -perm -4000 -ls 2>/dev/null

echo ""
echo "--- AUTHORIZED_KEYS FILES ---"
find /home /root -name "authorized_keys" -ls 2>/dev/null

echo ""
echo "--- INSTALLED PACKAGES (count) ---"
rpm -qa 2>/dev/null | wc -l || dpkg -l 2>/dev/null | wc -l

} | tee "$OUTFILE"

echo ""
echo "Baseline saved: $OUTFILE"

# Compare with previous baseline
PREV=$(ls -t "$OUTDIR"/baseline-*.txt 2>/dev/null | sed -n '2p')
if [ -n "$PREV" ]; then
    echo "Differences from previous baseline:"
    diff "$PREV" "$OUTFILE" | grep "^[<>]" | head -40
fi

Quick Reference

CommandWhat it checks
sudo dnf update --security -yApply security updates only (RHEL)
systemctl list-units --state=runningAll currently running services
sudo ss -tulpnAll listening network ports
sudo find / -xdev -perm -4000 -lsAll SUID binaries
sudo find / -xdev -perm -0002 -lsWorld-writable files
awk -F: '$3==0' /etc/passwdRoot-equivalent accounts
sudo awk -F: '$2==""' /etc/shadowAccounts with no password
last | head -20Recent login history
sudo grep "Failed" /var/log/secureFailed login attempts (RHEL)
sudo fail2ban-client status sshdBanned IPs and fail counts
sudo sysctl -p /etc/sysctl.d/99-security.confApply kernel security settings
sudo needs-restarting -rCheck if reboot needed after updates

Security Hardening Checklist

ItemCommand/Action
Apply all security updatesdnf update --security -y
Disable unnecessary servicessystemctl disable --now SERVICE
Enable firewallsystemctl enable --now firewalld
Configure fail2banInstall, configure jail.local, enable
Harden SSHSee Part 2 — SSH Hardening
Enable SELinux Enforcingsetenforce 1 + /etc/selinux/config
Secure /tmpAdd noexec,nosuid,nodev to fstab
Apply sysctl hardening/etc/sysctl.d/99-security.conf
Audit user accountsRemove unused, check UID-0, check sudo
Take security baselineRun baseline script, store for comparison

← Back to Security Index ↑ Back to EXPANDED