-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
how to restrict which operators can be used and which props can be used for ordering #2442
Comments
This would be an interesting feature. I don't know the interface yet but Ideally we'd reuse some PostgreSQL mechanism.
For example, if we would expose operators based on indexes, I see that CREATE OPERATOR CLASS has a The CREATE OPERATOR FAMILY can be schema namespaced, it would be great if we could have an operator family for postgREST. (Mostly thinking out loud above, those interfaces might not work) Another idea on #2028 (comment)
For now you could use functions/views and only expose the columns you want to be searched on. The most restrictive way would be scalar functions(that don't return table valued types) which wouldn't allow any filter or order, those would have to be done internally. Ideally pg would get the hint from: grant EXECUTE on FUNCTION pg_catalog.int4eq(test.projects.id%TYPE,integer) TO postgrest_test_anonymous;
grant EXECUTE on FUNCTION pg_catalog.int4eq(test.projects.client_id%TYPE,integer) TO postgrest_test_anonymous;
Tthat |
Using the YAML idea above but namespacing the configs to our role, it could be like: ALTER ROLE authenticator SET pgrst.operators TO $$
available:
-lt: '<'
- gt: '>'
- like: 'LIKE'
schema:
table:
- column1: lt, gt
- column2: like
- order: column3
$$; |
@adrian-gierakowski Instead of whitelisting the operations, what do you think of disallowing requests by their plan cost using the pg_plan_filter extension? Using https://www.postgresql.org/docs/current/pgstatstatements.html, it seems possible to determine the query with the highest cost and set that as a cost limit. |
This does not sound like what I'm looking for. What I'm looking for is something which would allow me to start by crafting a minimal API for a particular purpose, and then easily expand it as the need arises, making sure that any allowed queries can be server efficiently. The solution I'm looking for should also enable the generated OpenApi spec to reflect exactly what is allowed. And error messages returned for the rejected requests should clearly indicate why the reason for rejection (for example: "ordering by name is not allowed"). I could obviously slap a reverse proxy in front of the postgrest instance and reject unwanted queries, but that would required a re-implementation of the parser for the not so trivial postgrest query language on the proxy, which I think doesn't make sense, given that postgrest does the parsing already. |
Fair points. Some other ideas. Ideally pg would get the hint from: grant EXECUTE on FUNCTION pg_catalog.int4eq(test.projects.id%TYPE,integer) TO postgrest_test_anonymous;
grant EXECUTE on FUNCTION pg_catalog.int4eq(test.projects.client_id%TYPE,integer) TO postgrest_test_anonymous;
That Another idea is to have a convention on a function like: CREATE FUNCTION eq(test.projects, integer) RETURNS bool
AS $_$
SELECT $1.id = $2
$_$ LANGUAGE SQL STABLE; That wouldnn't work as well because we need the function to apply for integer types coming from different columns. Defining operators in this way could get long too. Another option would be CREATE FUNCTION "pgrst.projects.id.eq"(test.projects, test.projects.id%TYPE) RETURNS bool
AS $_$
SELECT $1.id = $2
$_$ LANGUAGE SQL STABLE;
CREATE FUNCTION "pgrst.projects.client_id.eq"(test.projects, test.projects.client_id%TYPE) RETURNS bool
AS $_$
SELECT $1.client_id = $2
$_$ LANGUAGE SQL STABLE; |
There's another way that michelp suggested to me. PostgreSQL has the SECURITY LABEL command, we could use it as: SECURITY LABEL FOR pgrest ON TABLE foo.bar IS $$
GRANT ORDER ON col TO anonymous
GRANT USAGE ON col2.eq TO anonymous
$$; The The benefit is that it would allow us to restrict ORDER or any other feature, unlike the FUNCTION approach. The drawback is that it would require installing a postgresql extension but we can fallback to our in-db config or env vars using the same syntax. |
Nice, this sounds really promising! Thank you for giving it such a thorough consideration. Let me know if there is anything I could do to help make it happen. |
I thought about using I'm not sure whether we should start attaching metadata to objects in this way, when we're that limited down the road. |
Not sure we'll need all of those but we could propose extending SECURITY LABEL in postgres core(feasible now that I have a couple of patches landed) and for past versions we could fallback to our in-db config. Edit: Additionally, since we'll have to parse the label inside anyway, we could extend the approach this way SECURITY LABEL FOR pgrest ON TABLE foo.bar IS $$
HIDE CONSTRAINT mypkey MESSAGE WITH 'duplicate id'
$$; Meaning we could use the label to refer to other objects of the table. Using |
One of the upsides of using
Yeah, extending Another option could be to try to extend |
Hm, I don't see how's that a dealbreaker for going with SECURITY LABEL. Orphaned metadata can be noticed and cleaned up on git-versioned database code and we could warn or err when trying to apply it. After all we're going to have to parse the label metadata on Haskell code. Also consider that we'd need to support the in-db config and the other configs as fallback too ALTER ROLE authenticator SET pgrest.sec.table."foo.bar" IS $$
HIDE CONSTRAINT mypkey MESSAGE WITH 'duplicate id'
$$; And those could leave orphaned metadata too |
I've been thinking this could be kept friendlier(less cognitive overload for the user) and conciser if we use plain HTTP syntax for an allowlist. GET /clients?select=projects(),tasks()&id=eq.*&name=like.*&order=name # users can only use eq on id, like on name, order on name and only embed on projects and tasks
PATCH /clients?id=eq.* # users can only patch by using the id filter Every other request would fail. This allowlist could limit the Schema Cache and also the OpenAPI output. (Specific columns in Ideally there would be a mode where PostgREST starts without an allowlist but can generate it based on the requests it receives. So users can start with an unrestricted instance, build a test suite, run it against the instance and have it generate the allowlist(likely with an endpoint on |
@steve-chavez this sounds great! |
Just so I don't forget. This could be more easily implemented with #1710 plus a
|
So I've been trying hard to restrict operators using pg itself(ref). The interface turns out to be clunky and requires a lot of database objects. And that doesn't even cover restricting Instead of trying to encode HTTP concerns into pg. What if we take an OpenAPI spec as input? The user can take our openapi output and then store it in a db function, say Notes:
|
Environment
14.3
9.0.1.20220717
linux (nixos, debian)
Description of issue
By default, users of the api served by postgrest can execute queries using all available operators and sort the results based on all available columns. I'd like to be able to restrict which operators can be used (and with which columns) as well as only enable ordering on specific columns. I don't see any mention of such capabilities in the postgrest docs. What's the recommended way of doing this?
Thanks!
The text was updated successfully, but these errors were encountered: