Database audit fixes

Configuration & Hardening: fixing all 7 checks

The configuration and hardening audit covers how the engine is run and backed up: the OS user it executes as, installer defaults left in place, pending engine patches and who can read your dumps.

Most skips here mean nothing was found to look at rather than nothing was wrong: the two backup checks search only /var/backups, /backup, /opt/backup, /srv/backup and /root/backups, three levels deep, for .sql, .sql.gz, .dump and .bak files, so dumps kept anywhere else report SKIP. The service user check skips when no mysqld, mariadbd, postgres, mongod or redis-server process is running at that moment, and Insecure Database Defaults and Transaction Log Placement skip without a root socket login to the engine.

7
checks in this audit
4
rated high severity
5
need root or sudo
~19s
automated run time

Transcribed from the database-security-hardening audit script. For what the audit covers rather than how to fix it, see the Configuration & Hardening checklist.

Every check

Find your finding

Listed in the order the audit runs them. Take the check name from the third field of the result line and open its page.

  • Database Service User

    Soon

    Checks whether running database engines execute as a dedicated unprivileged user rather than root

    HighNo root3 results
  • Insecure Database Defaults

    Soon

    Checks each detected engine for installer defaults left in place after setup

    LowNeeds root3 results
  • Database Patches

    Soon

    Checks for pending package and security updates for the installed database engines

    HighNo root4 results
  • Transaction Log Placement

    Soon

    Checks whether transaction and binary logs share the same disk as the database data files

    LowNeeds root3 results
  • Scheduled Database Backups

    Soon

    Checks cron jobs and systemd timers for a scheduled database backup

    MediumNeeds root2 results
  • Backup File Permissions

    Soon

    Checks whether database dump files in common backup paths are world-readable

    HighNeeds root3 results
  • Backup Encryption

    Soon

    Whether database dumps are encrypted at rest

    HighNeeds root4 results
Shared script behaviour

How the Configuration & Hardening audit reads your server

Every check in this audit runs after the same preamble, and several of its results only make sense once you know what that preamble could and could not see.

Engine detection: HAS_MY, HAS_PG, HAS_MG, HAS_RD are set from client binaries, server processes or config directories. MYOK=1 only if mysql -N -e 'SELECT 1' works as root over the socket; PGOK=1 only if su postgres -c 'psql -X -tAc "SELECT 1"' works. RDCONF is /etc/redis/redis.conf or /etc/redis.conf; MGCONF is /etc/mongod.conf. Containerised databases are not detected by these probes; audit them with the Docker checks or exec into the container.

Why checks skip

A SKIP is never a pass

A skipped check verified nothing at all. The most common cause is privilege: 5 of the 7 checks in this audit need root for a complete result. Before every run, each script works out which of four privilege modes it is in.

The four privilege modes an audit script can run in, and what each one means for checks that need root
ModeHow it is reachedWhat it means for your results
rootThe audit runs as UID 0.Every privileged branch runs directly. No check skips for lack of permission.
nopasssudo -n true succeeds, so the account has passwordless sudo.Privileged commands run through sudo -n.
passA sudo password was supplied in the CtrlOps audit settings and accepted.Privileged commands run through sudo -S.
noneNone of the above worked.CAN_ROOT=0. Every privileged branch returns SKIP with a "Need root" message rather than guessing.

If many checks skip with a “need root” message, run the audit as root, grant the audit account sudo (with or without NOPASSWD), or supply the sudo password in the CtrlOps audit settings.

FAQ

Configuration & Hardening questions

The check greps /etc/crontab, /etc/cron.d and the cron.hourly, cron.daily, cron.weekly and cron.monthly directories, plus /var/spool/cron when it has root, for mysqldump, mariadb-dump, pg_dump, pg_basebackup, mongodump, xtrabackup, mariabackup, borg or restic, then falls back to any systemd timer whose unit name contains backup or dump. Anything scheduled elsewhere is a false WARN: provider snapshots, a backup server that pulls over SSH, Kubernetes CronJobs, WAL archiving through archive_command, pgBackRest or Barman. A cron line that calls a wrapper script matches only if the script name itself contains one of those keywords, because the script body is never read.
It means every dump file the check could see is not world-readable, and nothing beyond that. It reads file modes only, so a 700 parent directory is not credited and a loose one is not penalised, and it looks nowhere outside the five backup paths, including offsite copies. Run without root it cannot enter /root/backups and says so in the message. Whether those dumps are encrypted is a separate check, and a mode 600 plaintext dump is still the whole database in one file.
On Debian and Ubuntu the count comes from a simulated apt-get upgrade filtered to mysql, mariadb, postgres, mongo and redis packages, and it becomes a FAIL rather than a WARN only when a matching line mentions security. Upgrading those packages restarts the engine on most distributions, so plan it as a maintenance window rather than running it inline. The numbers come from the cached package lists, so refresh with apt update first if the host has not done so recently, and note that held packages, tarball installs and engines inside containers never appear here at all.
Audit your fleet

Run all 7 Configuration & Hardening checks, in one click

CtrlOps runs this audit over your existing SSH connection - no agents, no scripts to manage. $7/user/month after a 1 month free trial - no credit card required.

Start instantly· No credit card· No sneaky autorenewals