|
| 1 | +--- |
| 2 | +title: Postgres Audit Log Guide |
| 3 | +author: Adela |
| 4 | +updated_at: 2025/11/10 18:00:00 |
| 5 | +feature_image: /content/blog/postgres-audit-log/cover.webp |
| 6 | +tags: Explanation |
| 7 | +description: A guide to audit logging in Postgres. |
| 8 | +--- |
| 9 | + |
| 10 | +Audit logging is a cornerstone of database security and compliance. Whether you’re tracking who changed what, investigating anomalies, or preparing for an audit, PostgreSQL gives you several ways to record activity at different levels of detail. |
| 11 | + |
| 12 | +In this guide, we’ll walk through the most practical approaches — from PostgreSQL’s built-in logging to advanced tools like pgAudit and Bytebase — to help you choose the right setup for your organization. |
| 13 | + |
| 14 | +## 1. Native PostgreSQL Logging |
| 15 | + |
| 16 | +[PostgreSQL logging documentation](https://www.postgresql.org/docs/current/runtime-config-logging.html) |
| 17 | + |
| 18 | +PostgreSQL comes with a robust logging subsystem out of the box. It’s often the first step in building an audit trail. |
| 19 | + |
| 20 | +**Key settings** |
| 21 | + |
| 22 | +You can enable and configure logging in your `postgresql.conf` file: |
| 23 | + |
| 24 | +```ini |
| 25 | +logging_collector = on |
| 26 | +log_statement = 'all' # Options: none, ddl, mod, all |
| 27 | +log_line_prefix = '%m [%p] %u@%d ' # Timestamp, process ID, user, database |
| 28 | +log_duration = on |
| 29 | +log_destination = 'csvlog' |
| 30 | +``` |
| 31 | + |
| 32 | +This setup tells PostgreSQL to collect all executed SQL statements, include who ran them and when, and record query durations. |
| 33 | + |
| 34 | +**Pros** |
| 35 | + |
| 36 | +- Simple to enable, built-in, no extension needed. |
| 37 | +- Useful for performance analysis and basic audit visibility. |
| 38 | + |
| 39 | +**Cons** |
| 40 | + |
| 41 | +- Unstructured text logs — difficult to parse automatically. |
| 42 | +- Can grow large quickly. |
| 43 | +- May include sensitive query parameters. |
| 44 | + |
| 45 | +You can use tools like [pgBadger](https://github.com/darold/pgbadger) to analyze these logs and generate visual reports of who executed what queries and when. |
| 46 | + |
| 47 | +➡️ *Takeaway:* Native logging is the minimum audit layer every PostgreSQL instance should have enabled. |
| 48 | + |
| 49 | +## 2. Trigger-Based Auditing |
| 50 | + |
| 51 | +[PostgreSQL Triggered Change Notification (tcn) documentation](https://www.postgresql.org/docs/current/tcn.html) |
| 52 | + |
| 53 | +If you need to record **row-level changes** — for example, before and after values on UPDATE — you can use triggers. |
| 54 | + |
| 55 | +**Example** |
| 56 | + |
| 57 | +Create a table to store change history: |
| 58 | + |
| 59 | +```sql |
| 60 | +CREATE TABLE audit_log ( |
| 61 | + id serial PRIMARY KEY, |
| 62 | + table_name text, |
| 63 | + action text, |
| 64 | + changed_by text, |
| 65 | + changed_at timestamptz DEFAULT now(), |
| 66 | + old_data jsonb, |
| 67 | + new_data jsonb |
| 68 | +); |
| 69 | +``` |
| 70 | + |
| 71 | +Then define a trigger: |
| 72 | + |
| 73 | +```sql |
| 74 | +CREATE OR REPLACE FUNCTION audit_trigger() RETURNS trigger AS $$ |
| 75 | +BEGIN |
| 76 | + INSERT INTO audit_log (table_name, action, changed_by, old_data, new_data) |
| 77 | + VALUES (TG_TABLE_NAME, TG_OP, current_user, row_to_json(OLD), row_to_json(NEW)); |
| 78 | + RETURN NEW; |
| 79 | +END; |
| 80 | +$$ LANGUAGE plpgsql; |
| 81 | + |
| 82 | +CREATE TRIGGER audit_user_table |
| 83 | +AFTER INSERT OR UPDATE OR DELETE ON users |
| 84 | +FOR EACH ROW EXECUTE FUNCTION audit_trigger(); |
| 85 | +``` |
| 86 | + |
| 87 | +This captures all DML operations (`INSERT`, `UPDATE`, `DELETE`) on the `users` table, recording what changed and by whom. |
| 88 | + |
| 89 | +**Pros** |
| 90 | + |
| 91 | +- Captures before/after data. |
| 92 | +- Fully customizable schema. |
| 93 | + |
| 94 | +**Cons** |
| 95 | + |
| 96 | +- Must be defined per table. |
| 97 | +- Can impact performance on write-heavy workloads. |
| 98 | + |
| 99 | +For real-time change notifications, PostgreSQL offers the `tcn` module (Triggered Change Notification), which can be used to send `NOTIFY` events to listening clients when data changes. |
| 100 | + |
| 101 | +➡️ *Takeaway:* Trigger-based auditing gives detailed change tracking for sensitive tables — best used selectively. |
| 102 | + |
| 103 | +## 3. pgAudit Extension |
| 104 | + |
| 105 | +[Visit the pgAudit GitHub repository](https://github.com/pgaudit/pgaudit) |
| 106 | + |
| 107 | +For structured, compliance-grade audit logs, PostgreSQL’s **pgAudit** extension is the standard choice. |
| 108 | +It extends native logging to provide more context and granularity, especially around read/write operations. |
| 109 | + |
| 110 | +**Installation** |
| 111 | + |
| 112 | +Enable the extension: |
| 113 | + |
| 114 | +```sql |
| 115 | +CREATE EXTENSION pgaudit; |
| 116 | +``` |
| 117 | + |
| 118 | +Update configuration: |
| 119 | + |
| 120 | +```ini |
| 121 | +shared_preload_libraries = 'pgaudit' |
| 122 | +pgaudit.log = 'READ, WRITE' |
| 123 | +pgaudit.log_catalog = off |
| 124 | +``` |
| 125 | + |
| 126 | +After restarting PostgreSQL, you’ll start seeing audit logs like: |
| 127 | + |
| 128 | +``` |
| 129 | +AUDIT: SESSION,1,READ,SELECT,,,,"SELECT * FROM customers WHERE id=42;",<none> |
| 130 | +``` |
| 131 | + |
| 132 | +**Benefits** |
| 133 | + |
| 134 | +- Records who executed which statement, in which session. |
| 135 | +- Captures both DDL and DML activity. |
| 136 | +- Integrates with PostgreSQL’s standard log collector — no new storage model. |
| 137 | + |
| 138 | +**Considerations** |
| 139 | + |
| 140 | +- Logs can be verbose — use `pgaudit.log_parameter = off` to reduce noise. |
| 141 | +- Requires proper log rotation and analysis strategy. |
| 142 | + |
| 143 | +➡️ *Takeaway:* pgAudit is the go-to choice for organizations that need **detailed, compliant** audit trails. |
| 144 | + |
| 145 | +## 4. Bytebase |
| 146 | + |
| 147 | +[See the Bytebase audit log documentation](https://docs.bytebase.com/security/audit-log) |
| 148 | + |
| 149 | +Bytebase is a Database DevSecOps platform that provides a **centralized audit trail protected from unauthorized modification** across your PostgreSQL environments. |
| 150 | +It records *who did what, when, and why* — linking SQL actions to their **context** (issues, approvals, and deployments) while keeping sensitive data secure. |
| 151 | + |
| 152 | +**What Bytebase Audits** |
| 153 | + |
| 154 | +- **Query access:** logs *who queried which data* and *when* across SQL Editor, Admin Query, and Data Export. |
| 155 | + Thanks to **dynamic data masking**, Bytebase only stores the **executed SQL statements** and metadata — **never the actual query results**. |
| 156 | +- **Schema and data changes:** tracks *who made which changes*, *when they were approved*, and *through which workflow or Git commit*. |
| 157 | +- **Governance controls:** built-in SQL review rules, approval flow, and role-based access help prevent unauthorized actions. |
| 158 | + |
| 159 | +**Why It Matters** |
| 160 | + |
| 161 | +- **Complete visibility** across read and write operations. |
| 162 | +- **Privacy-safe auditing** with no sensitive data exposure. |
| 163 | +- **Compliance-ready** logs aligned with SOC 2, ISO 27001, and GDPR. |
| 164 | + |
| 165 | +➡️ *Takeaway:* Unlike pgAudit, which records statements at the database level, Bytebase captures **who accessed or changed data, under which approval, without exposing sensitive information** — a privacy-first audit trail for modern teams. |
| 166 | + |
| 167 | +## Best Practices |
| 168 | + |
| 169 | +Audit logging can generate large volumes of data, so design it carefully. |
| 170 | + |
| 171 | +- **Centralize and retain logs:** forward to ELK, Datadog, or S3. |
| 172 | +- **Avoid sensitive data:** mask or omit personal identifiers. |
| 173 | +- **Rotate regularly:** control log size and prevent disk exhaustion. |
| 174 | +- **Test impact:** measure overhead before enabling full-statement logging. |
| 175 | +- **Layer approaches:** combine pgAudit (low-level) with Bytebase (change workflow) for complete visibility. |
| 176 | + |
| 177 | +## Conclusion |
| 178 | + |
| 179 | +PostgreSQL offers multiple layers of auditing — from basic text logs to complete governance solutions. |
| 180 | + |
| 181 | +- Use **native logging** for baseline activity tracking. |
| 182 | + |
| 183 | +- Use **pgAudit** for structured, compliance-grade statement logging. |
| 184 | + |
| 185 | +- Add **Bytebase** for centralized auditing that records who accessed or changed data, when, and why — all while protecting sensitive information. |
| 186 | + |
| 187 | +- Optionally, use **triggers** for fine-grained row-level auditing on critical tables. |
| 188 | + |
| 189 | +By combining these layers, you gain both the visibility and control needed for secure, compliant, and well-governed database operations. |
0 commit comments