Skip to content

fix: add row level security over shared tables - #303

Open
AndrewJackson2020 wants to merge 1 commit into
masterfrom
row_level_security
Open

AndrewJackson2020 wants to merge 1 commit into
masterfrom
row_level_security

Conversation

@AndrewJackson2020

Copy link
Copy Markdown
Contributor

Currently any user that has any ability to read the pg_net request or queue tables also has the ability to read every other users data on these tables. This is particularly problematic if users are using secrets (passwords, API keys, etc) in a multi tenant database environment.

@steve-chavez would appreciate any feedback on this PR in terms of the historical goals/design decisions of pg_net.

Currently any user that has any ability to read the pg_net request or
queue tables also has the ability to read every other users data on
these tables. This is particularly problematic if users are using
secrets (passwords, API keys, etc) in a multi tenant database
environment.
@AndrewJackson2020
AndrewJackson2020 marked this pull request as ready for review October 1, 2026 14:41
@AndrewJackson2020
AndrewJackson2020 requested a review from a team as a code owner October 1, 2026 14:41
@steve-chavez

Copy link
Copy Markdown
Member

@AndrewJackson2020 I wonder if this is the right design 🤔 :

  1. If we switch to callbacks (Change table queue to in-memory queue and add callbacks #62) then the table can be controlled by the user. Side-stepping the need for RLS.
  2. Another idea would be allowing the user to create the net tables on a custom schema. This would also avoid RLS.

1 would be a major redesign, 2 would keep it but seems more messy than yours.

Since we're going to do a breaking change soon, perhaps we should try 1 anyways? WDYT?

@AndrewJackson2020

Copy link
Copy Markdown
Contributor Author

I wonder if this is the right design 🤔

maybe, maybe not. hoping we can figure this out. I will say that this design is consistent with pg_cron so there is prior art to draw from. The only thing analogous in postgres contrib is probably pg_stat_statements which uses a hybrid shared memory data structure/on disk flat file. the pg_stat_statements approach is a lot more complex than an RLS table.

If we switch to callbacks

This is an interesting idea. It's a lot more true to the interface of other asynchronous frameworks. I also feel like it is harder for users to reason about. It also feels like much higher touch than this PR. I don't think I have a good opinion on this right now.

Another idea would be allowing the user to create the net tables on a custom schema

This also feels a bit higher touch than the proposed solution. Interesting idea though. What would the interface look like? You would just provide the schema/tablename of the intended request/response tables to the function calls? The user would just need to make sure that the table is set up with the correct schema and update it accordingly if we ever decide to add/remove a column, change a data type, etc? I think it would allow more granular ability to grant access though. I can definitely see the row level security change breaking applications where one user executes a requests and lets another user pick up the response and do some processing on it or whatever.

@steve-chavez

Copy link
Copy Markdown
Member

I will say that this design is consistent with pg_cron so there is prior art to draw from

TIL about that https://github.com/citusdata/pg_cron/blob/main/pg_cron.sql#L29. That does give more confidence in extensions working fine with RLS.

It also feels like much higher touch than this PR

Agree.

The user would just need to make sure that the table is set up with the correct schema and update it accordingly if we ever decide to add/remove a column, change a data type, etc?

Right, looks more complex and prone to failure.

I can definitely see the row level security change breaking applications where one user executes a requests and lets another user pick up the response and do some processing on it or whatever.

Seems acceptable to do on next major release.

Comment thread src/worker.c
init_curl_handle(&handles[j],
get_request_queue_row(queue_rows->vals[j], queue_rows->tupdesc));
RequestQueueRow req_queue_row = get_request_queue_row(queue_rows->vals[j], queue_rows->tupdesc);
init_curl_handle(&handles[j], req_queue_row);

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.

This is a separate refactor right? Maybe it can go in another commit.

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.

this was from an earlier implementation before I understood the data structures, I will fix.

This branch has not been deployed

No deployments
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.

2 participants