# Linux server security audit checklist

> A Linux server audit checks that the system is patched, that only expected services and accounts exist, that SSH and the firewall are locked down, and that logs and backups work. Use a benchmark such as a CIS Benchmark as the reference and a scanner such as Lynis to do the first pass.

Source: https://serverauditing.com/linux-server-audit-checklist/

## Start from a published baseline

Pick one written standard and audit against it, so each finding has a reference.

- The Center for Internet Security describes its [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks) as prescriptive configuration recommendations for vendor product families. Benchmarks exist for Ubuntu Linux, Debian Linux and Red Hat Enterprise Linux, among others.
- NIST [SP 800-123, Guide to General Server Security](https://csrc.nist.gov/pubs/sp/800/123/final), covers how to select, implement and maintain security controls for servers that provide network services.
- NIST [SP 800-92, Guide to Computer Security Log Management](https://csrc.nist.gov/pubs/sp/800/92/final), covers building and running log management.

Automated tools save time on the first pass. [Lynis](https://cisofy.com/documentation/lynis/) audits the host with `lynis audit system`. [OpenSCAP](https://github.com/OpenSCAP/openscap) checks a system against SCAP content with its `oscap` command.

## The checklist

The last column shows what `server_audit_notify.sh` covers. "Lynis" means the script runs Lynis, which reports on the area, and copies its warnings into the email.

| Area | What to check | Command | Script |
| --- | --- | --- | --- |
| Security updates | Pending updates, automatic security updates on | `apt list --upgradable` or `dnf check-update` | No |
| SSH | Root login, password login, key login | `sshd -T` | Lynis |
| Failed logins | Repeated failures from the same address | `lastb -n 20` | Yes |
| Accounts | Only root has UID 0, sudo group members | `awk -F: '$3 == 0' /etc/passwd` | Lynis |
| Listening services | Every open port has an owner and a reason | `ss -tulpn` | Yes |
| Firewall | Default deny for incoming traffic | `nft list ruleset` | Lynis |
| SUID files | No unexpected set-user-ID programs | `find / -xdev -perm -4000 -type f` | Lynis |
| Disk space | Room for logs and updates | `df -h` | Yes |
| Logging | Logs kept, rotated and sent off the host | `journalctl --disk-usage` | Lynis |
| Audit trail | auditd running with rules loaded | `auditctl -s` | Lynis |
| Time | Clock synchronized, so log times line up | `timedatectl` | No |
| Backups | Recent backup exists and a restore was tested | Depends on your tool | No |

## Security updates

Updates close publicly known security bugs, so check them first. List what is pending with `apt list --upgradable` on Debian and Ubuntu or `dnf check-update` on Red Hat style systems.

Ubuntu applies security updates on its own through the `unattended-upgrades` package. The [Ubuntu Server documentation](https://ubuntu.com/server/docs/how-to/software/automatic-updates/) says the schedule lives in `/etc/apt/apt.conf.d/20auto-upgrades`, the behavior in `/etc/apt/apt.conf.d/50unattended-upgrades`, and the logs in `/var/log/unattended-upgrades`.

## SSH configuration

Run `sshd -T` as root to print the settings the SSH server uses, after all include files. Compare these lines with your policy. The defaults below come from the [OpenSSH sshd_config manual](https://man.openbsd.org/sshd_config); distributions can change them.

| Setting | OpenSSH default | Common hardening choice |
| --- | --- | --- |
| `PermitRootLogin` | `prohibit-password` | `no` |
| `PasswordAuthentication` | `yes` | `no`, once keys work for every user |
| `PubkeyAuthentication` | `yes` | `yes` |
| `MaxAuthTries` | `6` | A lower number such as `3` |

Then look at failed attempts. `lastb` shows failed logins recorded in `/var/log/btmp`, and `journalctl -u ssh` (or `-u sshd` on Red Hat style systems) shows the SSH server log.

## Accounts and privileges

List accounts with UID 0 using `awk -F: '$3 == 0' /etc/passwd`; only `root` should appear. Check who can use sudo with `getent group sudo wheel`. Remove accounts for people who left, and lock service accounts that never log in.

## Open ports and firewall

`ss -tulpn` lists every listening TCP and UDP socket and the process behind it. For each line, you should know which service it is and whether it needs to accept connections from the internet. Then confirm the firewall matches: `nft list ruleset`, `ufw status verbose` or `firewall-cmd --list-all`, depending on the system.

## Logs and audit trail

Logs only help if they exist when you need them. Check that the journal or syslog keeps enough history with `journalctl --disk-usage`, that log rotation works, and that copies go to another host, since an attacker with root can edit local files.

The Linux Audit System records system calls and events from privileged programs. Its [project README](https://github.com/linux-audit/audit-userspace) describes each event as recording when it happened, who did it, what it acted on, and whether it succeeded. Check that it runs with `auditctl -s` and list the loaded rules with `auditctl -l`.

## Repeat the audit on a schedule

One audit shows the state on one day. Schedule the scan, keep the results, and compare runs so that new warnings stand out. The [install guide](https://serverauditing.com/install/) shows how to run `server_audit_notify.sh` daily with cron or a systemd timer and keep the reports for a set number of days.
