Skip to content

Add pgbouncer authentication failure log format to pgsql-logs (#1881) - #1951

Merged
sabban merged 4 commits into
crowdsecurity:masterfrom
rafaelsoje:add-pgbouncer-auth-logs
Nov 3, 2026
Merged

sabban merged 4 commits into
crowdsecurity:masterfrom
rafaelsoje:add-pgbouncer-auth-logs

Conversation

@rafaelsoje

Copy link
Copy Markdown
Contributor

Description

This PR adds parsing support for PgBouncer authentication failure log formats (both password authentication and SASL failures), closing #1881.

Details

  • Updates filter to accept both postgres and pgbouncer programs: evt.Parsed.program in ['postgres', 'pgbouncer'].
  • Adds grok pattern for PgBouncer ERROR C-... password authentication failed.
  • Adds grok pattern for PgBouncer LOG C-... closing because: SASL authentication failed.
  • Extracts timestamp, source_ip, source_port, pgsql_target_user, pgsql_dbname, and auth_method.
  • Emits log_type: pgsql_failed_auth, allowing automatic correlation with the existing crowdsecurity/pgsql-bf brute-force detection scenario.
  • Updated test logs and assertions in .tests/pgsql-logs/.

Closes #1881

Checklist

  • I have read the contributing guide
  • I have tested my changes locally
  • For new parsers or scenarios, tests have been added
  • I have run the hub linter and no issues were reported (see contributing guide)
  • Automated tests are passing
  • AI was used to generate any/all content of this PR

Comment thread .tests/pgsql-logs/parser.assert Outdated
@@ -1,4 +1,4 @@
len(results["s01-parse"]["crowdsecurity/pgsql-logs"]) == 6
len(results["s01-parse"]["crowdsecurity/pgsql-logs"]) == 8

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the assert file was only partially regenerated?
It's missing the full asserts for the 2 new lines

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Added the missing assertions for both PgBouncer log lines and verified that all tests are passing locally.

@sabban sabban left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi,

THank you for your contribution. Here's a review and please add a piece of doc to explain how to configure the datasource

- grok:
#pgbouncer SASL authentication failed
pattern: '%{TIMESTAMP_ISO8601:timestamp} %{WORD:zone} \[%{INT:PID}\] LOG C-%{NOTSPACE:connection_id}: %{DATA:pgsql_dbname}/%{DATA:pgsql_target_user}@%{IP:source_ip}:%{INT:source_port} closing because: %{WORD:auth_method} authentication failed'
apply_on: message

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that you are counting each failed login twice.

@rafaelsoje rafaelsoje Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ca7572d. I removed the duplicate grok pattern for connection closing. Only the initial ERROR log line is now parsed to prevent duplicate counting, and I added a test assertion verifying that closing lines are ignored.

apply_on: message
- grok:
#pgbouncer password authentication failed
pattern: '%{TIMESTAMP_ISO8601:timestamp} %{WORD:zone} \[%{INT:PID}\] ERROR C-%{NOTSPACE:connection_id}: %{DATA:pgsql_dbname}/%{DATA:pgsql_target_user}@%{IP:source_ip}:%{INT:source_port} %{WORD:auth_method} authentication failed'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is not ipv6 compatible. You can use [? and ]? to add optional brackets

@rafaelsoje rafaelsoje Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ca7572d. I updated the pattern to @[?%{IP:source_ip}]?:%{INT:source_port} and added test cases verifying bracketed IPv6 parsing (@[2001:db8::1]:port).

filter: "evt.Parsed.program == 'postgres'"
description: "Parse PgSQL and PgBouncer logs"
filter: "evt.Parsed.program in ['postgres', 'pgbouncer']"
nodes:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why adding pgbouncer here as there's the logs you added still have postgres ?

@rafaelsoje rafaelsoje Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept pgbouncer in the filter so both file acquisition (labels.type: pgbouncer) and syslog/journald (where program name is pgbouncer) are supported. I added a dedicated test suite under .tests/pgbouncer-logs/ with log_type: pgbouncer (testing IPv4, IPv6, ignoring close logs, and bruteforce scenario overflow), while restoring .tests/pgsql-logs/ to focus purely on PostgreSQL.

- Prevent double counting by removing duplicate closing because grok pattern
- Support bracketed IPv6 addresses in PgBouncer grok pattern
- Add dedicated pgbouncer-logs hub test with log_type pgbouncer
- Add datasource configuration documentation in pgsql-logs.md
@rafaelsoje
rafaelsoje force-pushed the add-pgbouncer-auth-logs branch from f11eea9 to ca7572d Compare October 29, 2026 00:03
@rafaelsoje

rafaelsoje commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

Hi @sabban,

Thank you for the detailed review! All requested points have been addressed in commit ca7572d:

  1. Double Counting: I removed the grok pattern matching the connection close message (LOG C-... closing because: SASL authentication failed). Only the initial ERROR C-... <method> authentication failed log entry is now parsed, preventing duplicate event increments. I also added a test assertion verifying that closing lines are ignored.
  2. IPv6 Compatibility: I updated the pattern to @\[?%{IP:source_ip}\]?:%{INT:source_port}. Verified with bracketed IPv6 addresses (@[2001:db8::1]:port), extracting the clean IP without brackets.
  3. Filter and Test Consistency: I kept evt.Parsed.program in ['postgres', 'pgbouncer'] so both file acquisition (type: pgbouncer) and syslog/journald (where program name is pgbouncer) are supported. I added a dedicated test suite under .tests/pgbouncer-logs/ with log_type: pgbouncer (testing IPv4, IPv6, ignoring close logs, and bruteforce scenario overflow), while restoring .tests/pgsql-logs/ to focus purely on PostgreSQL.
  4. Documentation: I updated parsers/s01-parse/crowdsecurity/pgsql-logs.md with explicit acquis.yaml examples for both PostgreSQL and PgBouncer (file and syslog/journald), along with a summary table of parsed fields.

All hub tests (pgsql-logs with 100 assertions and pgbouncer-logs with 106 assertions) pass with 100% success.

@sabban sabban left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last question before merging


```yaml
journalctl_filter:
- _SYSTEMD_UNIT=pgbouncer.service

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you you actually test this setup ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, you are completely right. I had only validated the file-based configuration (type: pgbouncer on /var/log/postgresql/pgbouncer.log, which is tested under .tests/pgbouncer-logs), and added the journalctl snippet speculatively (which was also missing source: journalctl).

Since syslog/journald setups often format or strip application prefixes differently depending on daemon setup and haven't been validated end-to-end here, I removed the journalctl block so the documentation focuses strictly on the tested file-based acquisition, consistent with the PostgreSQL section.

@sabban
sabban merged commit 58b38ff into crowdsecurity:master Nov 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Proposal] Add support for PgBouncer authentication failure log format

3 participants