-
Notifications
You must be signed in to change notification settings - Fork 193
Add supabase-supavisor Collection #1606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
khashashin
wants to merge
13
commits into
crowdsecurity:master
Choose a base branch
from
khashashin:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
5d1eb93
feat: add Supabase Supavisor collection with parser and brute-force s…
khashashin b872470
refactor: clean up parser and scenario assertions for Supavisor logs …
khashashin f94c169
feat: add Supavisor Docker logs parser and configuration
khashashin 7e4fa6b
refactor: streamline Supavisor log parsing patterns and remove redund…
khashashin 61558b3
refactor: simplify Supavisor scenario documentation by removing redun…
khashashin d23abb0
refactor: update Supabase Supavisor documentation for clarity and acc…
khashashin 375a199
refactor: add timestamp extraction to Supavisor log parsing patterns
khashashin 13c923a
refactor: update Supavisor Docker logs parser to prepare logs for par…
khashashin 4aa1e32
refactor: simplify scenario assertions by removing redundant structure
khashashin e635d2b
refactor: remove redundant Supavisor Docker logs parser from document…
khashashin fbce5d4
refactor: update Supavisor Docker logs parser path in configuration
khashashin e40204d
docs: add detection details for Supavisor log patterns
khashashin 3865ae3
docs: add supabase-supavisor container name to regex patterns
khashashin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| parsers: | ||
| - crowdsecurity/syslog-logs | ||
| - crowdsecurity/dateparse-enrich | ||
| - ./parsers/s01-parse/crowdsecurity/supavisor-logs.yaml | ||
| scenarios: | ||
| - ./scenarios/crowdsecurity/supavisor-bf.yaml | ||
| postoverflows: | ||
| - "" | ||
| log_file: supavisor-logs.log | ||
| log_type: supavisor | ||
| ignore_parsers: false | ||
khashashin marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][0].Success == true | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][0].Evt.Meta.source_ip == "192.168.1.100" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][0].Evt.Meta.log_type == "supavisor_auth_fail" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][0].Evt.Meta.service == "supavisor" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][0].Evt.Parsed.project == "dev_tenant" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][0].Evt.Parsed.db_user == "postgres" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][6].Success == true | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][6].Evt.Meta.source_ip == "10.0.0.50" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][6].Evt.Meta.log_type == "supavisor_auth_fail" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][6].Evt.Parsed.db_user == "admin" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][12].Success == true | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][12].Evt.Meta.source_ip == "172.16.0.25" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][12].Evt.Meta.log_type == "supavisor_ssl_required" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][13].Success == true | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][13].Evt.Meta.log_type == "supavisor_bad_startup" | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][16].Success == true | ||
| results["s01-parse"]["crowdsecurity/supavisor-logs"][16].Evt.Meta.log_type == "supavisor_user_not_found" |
khashashin marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| results[0].Overflow.Alert.Source.IP == "192.168.1.100" | ||
| results[1].Overflow.Alert.Source.IP == "10.0.0.50" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| 18:37:23.568 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=192.168.1.100 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 18:38:08.977 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=192.168.1.100 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 18:38:11.207 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=192.168.1.100 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 18:38:13.394 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=192.168.1.100 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 18:38:15.581 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=192.168.1.100 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 18:38:17.778 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=192.168.1.100 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 19:33:35.083 project=dev_tenant user=admin region=local mode=transaction type=single app_name=psql peer_ip=10.0.0.50 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 19:33:37.329 project=dev_tenant user=admin region=local mode=transaction type=single app_name=psql peer_ip=10.0.0.50 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 19:33:39.530 project=dev_tenant user=admin region=local mode=transaction type=single app_name=psql peer_ip=10.0.0.50 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 19:33:41.717 project=dev_tenant user=admin region=local mode=transaction type=single app_name=psql peer_ip=10.0.0.50 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 19:33:43.903 project=dev_tenant user=admin region=local mode=transaction type=single app_name=psql peer_ip=10.0.0.50 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 19:33:45.100 project=dev_tenant user=admin region=local mode=transaction type=single app_name=psql peer_ip=10.0.0.50 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| 05:44:32.395 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=172.16.0.25 [error] ClientHandler: Tenant is not allowed to connect without SSL, user postgres | ||
| 08:31:53.782 region=local [error] ClientHandler: Client startup message error: :bad_startup_payload | ||
| 08:31:54.123 region=local [error] ClientHandler: Client startup message error: :bad_startup_payload | ||
| 08:31:54.293 region=local [error] ClientHandler: Client startup message error: :bad_startup_payload | ||
| 06:06:31.740 region=local [error] ClientHandler: User not found: "Either external_id or sni_hostname must be provided" {:single, "postgres", nil} | ||
| 06:06:31.767 region=local [error] ClientHandler: User not found: "Either external_id or sni_hostname must be provided" {:single, "postgres", nil} | ||
| 18:32:01.852 request_id=GICLZXgj-0m5cLcAAUTh region=local [info] GET /api/health | ||
| 18:32:01.853 request_id=GICLZXgj-0m5cLcAAUTh region=local [info] Sent 204 in 413µs |
khashashin marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| # Supabase Supavisor Collection | ||
|
|
||
| Detect brute force attacks against self-hosted [Supabase](https://supabase.com/) deployments using the [Supavisor](https://github.com/supabase/supavisor) connection pooler. | ||
|
|
||
| ## Acquisition | ||
|
|
||
| ```yaml | ||
| source: docker | ||
| container_name: | ||
| - supabase-supavisor | ||
| labels: | ||
| type: supavisor | ||
| ``` | ||
| For dynamic container names (Coolify, etc.): | ||
| ```yaml | ||
| source: docker | ||
| container_name_regexp: | ||
| - "supabase-supavisor" | ||
| - "supabase-supavisor-.*" | ||
| labels: | ||
| type: supavisor | ||
| ``` | ||
| ## What Gets Detected | ||
| ### ✅ Detectable (has peer_ip) | ||
| | Attack Type | Log Pattern | Action | | ||
| |-------------|-------------|--------| | ||
| | Wrong password | `Exchange error: "Wrong password"` | Block after 5 attempts | | ||
| | SSL required bypass | `Tenant is not allowed to connect without SSL` | Block after 5 attempts | | ||
|
|
||
| ### ❌ Not Detectable (no peer_ip in logs) | ||
|
|
||
| | Log Type | Reason | | ||
| |----------|--------| | ||
| | Bad startup payload | Supavisor doesn't log client IP | | ||
| | User not found | Supavisor doesn't log client IP | | ||
|
|
||
| This is a Supavisor logging limitation, not a CrowdSec limitation. | ||
|
|
||
| ## Included Components | ||
|
|
||
| | Type | Name | Description | | ||
| |------|------|-------------| | ||
| | Parser | `crowdsecurity/supavisor-logs` | Parses Supavisor logs | | ||
| | Scenario | `crowdsecurity/supavisor-bf` | Brute force detection | | ||
|
|
||
| ## Related | ||
|
|
||
| - [Supabase Self-Hosting Guide](https://supabase.com/docs/guides/self-hosting/docker) | ||
| - [Supavisor Repository](https://github.com/supabase/supavisor) | ||
| - [CrowdSec Documentation](https://docs.crowdsec.net/) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| name: crowdsecurity/supabase-supavisor | ||
| description: "Detect attacks against Supabase PostgreSQL via Supavisor connection pooler" | ||
| parsers: | ||
| - crowdsecurity/supavisor-logs | ||
| scenarios: | ||
| - crowdsecurity/supavisor-bf |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Supavisor Logs Parser | ||
|
|
||
| Parses [Supavisor](https://github.com/supabase/supavisor) connection pooler logs to detect authentication failures. | ||
|
|
||
| ## Log Format | ||
|
|
||
| ``` | ||
| 18:38:17.778 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=123.123.123.123 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| ``` | ||
|
|
||
| ## Parsed Fields | ||
|
|
||
| | Field | Description | | ||
| |-------|-------------| | ||
| | `source_ip` | Client IP address | | ||
| | `project` | Tenant/project identifier | | ||
| | `db_user` | Database user | | ||
| | `log_type` | Event classification | | ||
|
|
||
| ## Acquisition | ||
|
|
||
| ```yaml | ||
| source: docker | ||
| container_name: | ||
| - supabase-supavisor | ||
| labels: | ||
| type: supavisor | ||
| ``` |
khashashin marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| name: crowdsecurity/supavisor-logs | ||
| description: "Parse Supavisor connection pooler logs for authentication failures" | ||
| filter: "evt.Parsed.program == 'supavisor'" | ||
| onsuccess: next_stage | ||
| debug: false | ||
|
|
||
| # Supavisor uses Elixir Logger format with metadata | ||
| # Real log example: | ||
| # 18:38:17.778 project=dev_tenant user=postgres region=local mode=transaction type=single app_name=psql peer_ip=123.123.123.123 [error] ClientHandler: Exchange error: "Wrong password" when method :auth_query | ||
| pattern_syntax: | ||
| SUPAVISOR_TS: '%{TIME:timestamp}\.%{INT:timestamp_ms}' | ||
| SUPAVISOR_LEVEL: '\[%{WORD:log_level}\]' | ||
| SUPAVISOR_META_FULL: 'project=%{DATA:project}\s+user=%{DATA:db_user}\s+region=%{DATA:region}\s+mode=%{DATA:pool_mode}\s+type=%{DATA:pool_type}\s+app_name=%{DATA:app_name}\s+peer_ip=%{IP:source_ip}' | ||
| SUPAVISOR_META_PARTIAL: 'region=%{DATA:region}' | ||
|
|
||
| nodes: | ||
| - grok: | ||
| pattern: '%{SUPAVISOR_TS}\s+%{SUPAVISOR_META_FULL}\s+%{SUPAVISOR_LEVEL}\s+ClientHandler:\s+Exchange error:\s+"Wrong password"%{GREEDYDATA}' | ||
| apply_on: message | ||
| statics: | ||
| - meta: log_type | ||
| value: supavisor_auth_fail | ||
| - meta: service | ||
| value: supavisor | ||
| - meta: source_ip | ||
| expression: evt.Parsed.source_ip | ||
| - target: evt.StrTime | ||
| expression: evt.Parsed.timestamp | ||
|
|
||
| - grok: | ||
| pattern: '%{SUPAVISOR_TS}\s+%{SUPAVISOR_META_FULL}\s+%{SUPAVISOR_LEVEL}\s+ClientHandler:\s+Tenant is not allowed to connect without SSL%{GREEDYDATA}' | ||
| apply_on: message | ||
| statics: | ||
| - meta: log_type | ||
| value: supavisor_ssl_required | ||
| - meta: service | ||
| value: supavisor | ||
| - meta: source_ip | ||
| expression: evt.Parsed.source_ip | ||
| - target: evt.StrTime | ||
| expression: evt.Parsed.timestamp | ||
|
|
||
| - grok: | ||
| pattern: '%{SUPAVISOR_TS}\s+%{SUPAVISOR_META_FULL}\s+%{SUPAVISOR_LEVEL}\s+ClientHandler:\s+Exchange error:%{GREEDYDATA:error_detail}' | ||
| apply_on: message | ||
| statics: | ||
| - meta: log_type | ||
| value: supavisor_auth_fail | ||
| - meta: service | ||
| value: supavisor | ||
| - meta: source_ip | ||
| expression: evt.Parsed.source_ip | ||
| - target: evt.StrTime | ||
| expression: evt.Parsed.timestamp | ||
|
|
||
| - grok: | ||
| pattern: '%{SUPAVISOR_TS}\s+%{SUPAVISOR_META_FULL}\s+%{SUPAVISOR_LEVEL}\s+%{GREEDYDATA:error_message}' | ||
| apply_on: message | ||
| filter: "evt.Parsed.log_level == 'error'" | ||
| statics: | ||
| - meta: log_type | ||
| value: supavisor_error_with_ip | ||
| - meta: service | ||
| value: supavisor | ||
| - meta: source_ip | ||
| expression: evt.Parsed.source_ip | ||
| - target: evt.StrTime | ||
| expression: evt.Parsed.timestamp | ||
|
|
||
| - grok: | ||
| pattern: '%{SUPAVISOR_TS}\s+%{SUPAVISOR_META_PARTIAL}\s+%{SUPAVISOR_LEVEL}\s+ClientHandler:\s+Client startup message error:\s+:bad_startup_payload' | ||
| apply_on: message | ||
| statics: | ||
| - meta: log_type | ||
| value: supavisor_bad_startup | ||
| - meta: service | ||
| value: supavisor | ||
| - target: evt.StrTime | ||
| expression: evt.Parsed.timestamp | ||
|
|
||
| - grok: | ||
| pattern: '%{SUPAVISOR_TS}\s+%{SUPAVISOR_META_PARTIAL}\s+%{SUPAVISOR_LEVEL}\s+ClientHandler:\s+User not found:%{GREEDYDATA:enum_detail}' | ||
| apply_on: message | ||
| statics: | ||
| - meta: log_type | ||
| value: supavisor_user_not_found | ||
| - meta: service | ||
| value: supavisor | ||
| - target: evt.StrTime | ||
| expression: evt.Parsed.timestamp | ||
|
|
||
| statics: | ||
| - meta: service | ||
| value: supavisor |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Supavisor Brute Force Detection | ||
|
|
||
| Detects brute force attacks against PostgreSQL databases through the Supavisor connection pooler. | ||
|
|
||
| ## Description | ||
|
|
||
| This scenario triggers when multiple authentication failures are detected from the same IP address. It detects wrong password attempts via Supavisor's `auth_query` authentication method. | ||
|
|
||
| ## Behavior | ||
|
|
||
| | Parameter | Value | Description | | ||
| |-----------|-------|-------------| | ||
| | `capacity` | 5 | Failed attempts before triggering | | ||
| | `leakspeed` | 30s | Time window for counting | | ||
| | `blackhole` | 5m | Cooldown after trigger | | ||
|
|
||
| ## Labels | ||
|
|
||
| | Label | Value | | ||
| |-------|-------| | ||
| | `confidence` | 3 | | ||
| | `spoofable` | 0 | | ||
| | `classification` | attack.T1110 | | ||
| | `remediation` | true | | ||
|
|
||
| ## Acquisition | ||
|
|
||
| ```yaml | ||
| source: docker | ||
| container_name_regexp: | ||
| - "supabase-supavisor" | ||
| - "supabase-supavisor-.*" | ||
| labels: | ||
| type: supavisor | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| type: leaky | ||
| name: crowdsecurity/supavisor-bf | ||
| description: "Detect brute force attacks against PostgreSQL via Supavisor connection pooler" | ||
| filter: evt.Meta.log_type == 'supavisor_auth_fail' | ||
| groupby: evt.Meta.source_ip | ||
| capacity: 5 | ||
| leakspeed: 30s | ||
| blackhole: 5m | ||
| labels: | ||
| service: supavisor | ||
| confidence: 3 | ||
| spoofable: 0 | ||
| classification: | ||
| - attack.T1110 | ||
| behavior: "database:bruteforce" | ||
| label: "Supavisor bruteforce" | ||
| remediation: true |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.