Linux Server Hardening Checklist

Chapter 1 of 7 · 5 checks · 3 min

User accounts and sudo

Checks that every person has their own account, nobody works as root, and admin rights are limited and traceable.

Show
  1. Every person who logs in has their own named accountMust

    Why it matters and how to check

    Shared logins such as one ubuntu or deploy account for the whole team make it impossible to tell who did what, and impossible to remove one person's access without changing it for everyone. Give each person their own account and their own SSH key.

    To verify: list accounts that have a real login shell with getent passwd | awk -F: '$7 !~ /(nologin|false)$/'. Every human account on the list should map to one current team member. Check ~/.ssh/authorized_keys for each shared or default account and remove keys that belong to individuals.

    Example

    Shell
    sudo adduser alice
    sudo usermod -aG sudo alice      # RHEL: sudo usermod -aG wheel alice
    getent passwd | awk -F: '$7 !~ /(nologin|false)$/ {print $1, $7}'
  2. Nobody logs in as root; admins use sudo from their own accountMust

    Why it matters and how to check

    Working as root means every typo runs with full power and every action is logged as "root". With sudo, each privileged command is recorded against a named user and needs a deliberate step. Ubuntu ships with the root password locked for this reason.

    To verify: run sudo passwd -S root. The second field should be L (locked). Check that root cannot log in over SSH (see the SSH chapter). Search the auth log for sudo entries and confirm they show real user names: sudo grep sudo /var/log/auth.log | tail on Ubuntu, or sudo journalctl _COMM=sudo on any systemd distro.

  3. sudo rules are edited with visudo and grant only what each role needsShould

    Why it matters and how to check

    A syntax error in /etc/sudoers can lock every admin out, and a broad NOPASSWD: ALL rule turns any compromised account into root without a password. Red Hat's hardening guide recommends granting specific commands to users who do not need full sudo access.

    To verify: run sudo visudo -c to check the syntax of the main file and every drop-in. Review /etc/sudoers and /etc/sudoers.d/ for NOPASSWD and ALL. A deploy user should usually get only the exact commands it runs, such as restarting one service. Run sudo -l -U deploy to see what an account can actually do.

    Example

    Shell
    # /etc/sudoers.d/deploy  (edit with: sudo visudo -f /etc/sudoers.d/deploy)
    deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp.service
  4. Accounts and keys of people who left are removed the same dayMust

    Why it matters and how to check

    An old SSH key on a server works until someone removes it, no matter what happened to the person's laptop or company email. Server accounts are easy to forget in offboarding because they live outside your identity provider.

    To verify: for each human account, check when it last logged in with sudo lastlog (or lastlog2 where lastlog is not available) and compare against your team list. Check every authorized_keys file, including root's and the default cloud user's, for keys you cannot name: sudo find / -name authorized_keys -path '*/.ssh/*' 2>/dev/null. Lock or delete accounts that should not exist with sudo usermod -L or sudo deluser.

  5. Service accounts have no login shell and own only their own filesNice to have

    Why it matters and how to check

    Your app, database and workers should each run as their own unprivileged user, not as root and not as a person's account. Those users never need to log in, so give them a shell of /usr/sbin/nologin.

    To verify: run ps -eo user,comm --sort=user and confirm app processes do not run as root. Check the service users with getent passwd myapp and look for nologin as the last field. Confirm the app's data directory is owned by its user and not writable by others: ls -ld /srv/myapp.

    Example

    Shell
    sudo useradd --system --home /srv/myapp --shell /usr/sbin/nologin myapp
    # in the systemd unit
    # [Service]
    # User=myapp
    # Group=myapp