-
-
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
[Feature Request] HTTP headers filtering - whitelist transaction-scoped settings #1941
Comments
Related to #1857. We'll need to set all the headers in a single When we do that, perhaps passing all the headers won't be a problem?
I see no harm in offering such a config option though, it would reduce the passed json payload for #1857 as well. |
A different approach, compared to another config option, that achieves the same thing, but is much more flexible down the road is mentioned in #1710 (comment). |
@steve-chavez, of course, proposed enhancement would reduce JSON-payload, that decrease request overhead time.
@wolfgangwalther, your enhancement doesn't filter headers on PostgREST level, only on PostgreSQL level. Therefore, these features can complement each other, not replace. |
That's not correct. Implementing the full proposal would allow filtering the headers on the PostgREST level already. It would be set up via arguments to a pre-request function - but those headers that are not used, will never be sent to PostgreSQL. |
@wolfgangwalther So I don't understand how it works, please tell me in more detail. |
The proposal starts by stripping all At schema cache creation time, we'd read the argument list of the pre-request function definition. If that reads something like Thereby the filter will apply at schema cache creation time - and therefore at the PostgREST level, before getting to PostgreSQL at all during the actual query. Does that make sense? |
@wolfgangwalther The |
@wolfgangwalther now everything is clear. IMHO main issue of this solution is function parameters, it is not very flexible and difficulty updating under load. I would prefer something like @steve-chavez of course |
Yes, I assumed that would be part of implementing that. But I can see how we'll face the same problem with So maybe we should join the
Well, the proposal includes the ability to create a I don't really see the difficulty of updating under load, yet, but I haven't thought about that too much either. Could you explain where you see the problem? |
Yes, I understand that needs to be added
For example:
Our actions:
Our actions (single JSON):
I think the first case is more difficult than the second. Especially when DevOps and DBA are different people. |
Thanks for the walk-through.
I think this is the core of the issue. Once we create pre-request functions with different arguments, we can overload the same function. This will then quickly lead to a situation, where PostgREST needs to decide which of those to call later, while reloading the schema cache. One way to handle this would be to move away from the config option This would allow to:
This would also make the system extensible to support hooks in other places than "pre-request" in the same way. One side effect of this, that I like: We'd move more of the config right into SQL, where objects (here |
I don't understand how it works, please tell me in more detail. |
The concept of The basic idea is that we can set all kinds of "flags" or "parameters" via |
I tried the above and the query can work like this: WITH
pgrst_pre_request AS ( SELECT test."pre_request"() ),
pgrst_source AS ( SELECT "test"."clients".*FROM "test"."clients" )
SELECT
(select 1 from pgrst_pre_request) AS pre_req, -- it must be before the response_headers below otherwise headers set on pre-req don't get passed to PostgREST
null::bigint AS total_result_set,
pg_catalog.count(_postgrest_t) AS page_total,
coalesce(json_agg(_postgrest_t), '[]')::character varying AS body,
nullif(current_setting('response.headers', true), '') AS response_headers,
nullif(current_setting('response.status', true), '') AS response_status
FROM ( SELECT * FROM pgrst_source ) _postgrest_t; |
Don't we have the same problem with I was now finally able to produce an example where joining create role authenticator;
create role alice;
create schema a;
grant create, usage on schema a to alice;
set role alice;
create table a.t ();
select * from a.t;
reset role;
select set_config('role', 'alice', false), current_setting('role');
-- returns: alice | alice
-- BUT:
set role authenticator;
select set_config('role', 'alice', false), current_setting('role') from a.t;
-- returns: permission denied for schema a
reset role;
grant usage on schema a to authenticator;
set role authenticator;
select set_config('role', 'alice', false), current_setting('role') from a.t;
-- returns: permission denied for table t Since the |
Good call, my proposed query is a no go then. Then the only way to improve perf for pre-request would be pipeline mode. |
If we had pipeline mode, then #1941 (comment) would suddenly be a lot more attractive, I think. |
Now that we have transaction-scoped settings clearly defined, I think we can have a single config for all. Should be like: # default
tx-settings = '{"*": {"*": ["*"]}}'
# whitelisting some headers and allowing all jwt claims
tx-settings = '{"public.table": {"request.headers": ["header1", "header2"]}, "public.func()": {"request.jwt.claims": ["*"]}}' And with pre-config: create or replace function postgrest.pre_config()
returns void as $$
select
set_config('pgrst.tx_settings',
, json_build_object('public.table'
, json_build_object('request.headers', json_build_array('header1', 'header2'))
)::text
, true
)
;
$$ language sql; |
tx-settings = '{"public.table": {"request.headers": ["header1", "header2"]}, "public.func()": {"request.jwt.claims": ["*"]}}' @steve-chavez Could you give more detail about what |
@taimoorzaeem Those were meant to be a table and a function.. but I think we should take a step back. There was a recent change that affects this issue.
@wolfgangwalther How would the above work now that we only have the JSON GUCs (60a9000)? So if we had: CREATE FUNCTION your_pre_req ("request.headers" json) This would mean all the headers would be always passed to the pre-request function, which would still have a perf impact? How could we filter the headers that get passed as an argument? (the |
Still the same. The "new" JSON GUC format was only invented because of a limitation in what characters were allowed for GUC names. There is no such limitation for argument names... except maybe |
Hm, so the proposal remains in that we should filter the passed headers according to the pre-request parameters. But that caused some problems with deployment as mentioned above. It would be complex to define a function with 20 arguments if the user is interested in 20 headers. Really this looks to me like a pure proxy issue. So if we had an nginx like directive, we could do it like: server{
location{
pg_pre_request 'pre_req_func' '[$http_user_agent, $http_referer]' '..'
}
} We don't have that kind of flexibility, but maybe we can come up with a similar solution. |
This is not a problem with the proposal here - this is a general problem of "how to do HA with PostgREST". The core problem was identified in #1941 (comment). You can easily work around that problem by versioning your pre-request function names to avoid any overloaded collisions:
Yes, we do need to figure out what to do with multiple overloaded pre-request functions which all match our config. But I already made some proposals above.
But that's the opposite of what was the idea of this issue. If you need 20 headers, you are more than likely fine with just adding a catch-all |
It's good to introduce an option for filtering HTTP headers passed to PostgreSQL.
For example,
request-headers-allowlist
, with default value is*
(meaning all headers are passed).There're many unnecessary
set_config()
commands in every transaction.I've gotten 22 params at all, where a 50% of them are HTTP headers, a lot of people doesn't use (or uses small portion) it. We use only two of 11.
The text was updated successfully, but these errors were encountered: