Log PostgreSQL connections and authentication
postgresql.conflog_connections = onlog_disconnections = onlog_hostname = offlog_line_prefix = '%m [%p] %q%u@%d from %h 'SELECT pg_reload_conf();Why it matters
Section titled “Why it matters”This closes no exposure, which is why it is low and last. It changes what you
can find out afterwards.
Without log_connections, a successful authentication leaves no trace. You
cannot answer “who connected, from where, and how” — not during an incident, not
during an audit, and not when you’re trying to work out which client is still on
plaintext or still using md5. The log line names the authentication method, which
makes it the most reliable way to confirm the migrations on the other pages in
this cluster actually landed.
log_disconnections adds session duration, which is what turns a list of logins
into something you can spot anomalies in.
log_hostname is a trap
Section titled “log_hostname is a trap”log_hostname = on looks helpful — hostnames are friendlier than addresses. It
performs a reverse DNS lookup on every connection, synchronously.
On a busy server that is a per-connection DNS round trip in the connection path, and if the resolver is slow or unreachable, connection latency follows it. Worse, the resulting name is attacker-influenced: reverse DNS is controlled by whoever owns the address, so a hostname in your logs is not evidence of anything.
Leave it off and log addresses. %h in log_line_prefix gives you the client
address, which is both faster and more truthful.
log_statement = ‘all’ will log your passwords
Section titled “log_statement = ‘all’ will log your passwords”The other common suggestion is log_statement = 'all'. Understand what it does
before enabling it: it writes every SQL statement to the log, including
ALTER ROLE myapp WITH PASSWORD 'the-actual-secret';in cleartext. It logs your data too — every value in every INSERT. You have
moved sensitive data into a file with different permissions, different retention
and different backup rules than the database, and probably shipped it to a log
aggregator.
For an audit trail of changes, log_statement = 'ddl' is the defensible middle
ground: schema changes without the data or the credentials. For real auditing,
use the pgaudit extension, which is designed for it and can exclude sensitive
statements.
Related
Section titled “Related”- Use scram-sha-256, not md5 — the log line names the method, which is how you confirm it.
- Enable TLS —
pg_stat_sslfor the live picture, logs for the history.