Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tESi9-007SGy-RV for pgsql-general@arkaria.postgresql.org; Fri, 22 Nov 2024 12:24:34 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tESi8-0089qX-62 for pgsql-general@arkaria.postgresql.org; Fri, 22 Nov 2024 12:24:32 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tESi7-0089ov-GN for pgsql-general@lists.postgresql.org; Fri, 22 Nov 2024 12:24:31 +0000 Received: from mail-ej1-x62c.google.com ([2a00:1450:4864:20::62c]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1tESi0-003DGv-DP for pgsql-general@postgresql.org; Fri, 22 Nov 2024 12:24:30 +0000 Received: by mail-ej1-x62c.google.com with SMTP id a640c23a62f3a-a9a850270e2so356863866b.0 for ; Fri, 22 Nov 2024 04:24:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aquameta-com.20230601.gappssmtp.com; s=20230601; t=1732278262; x=1732883062; darn=postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=zBJjgVPmlrNf+EtO/T42VR1vO+YWk6Sg9oIuB315+lw=; b=R+t/kDP7/9D/t5RNLy+jrY6CM9+qTJTK62o65IJCJVyoiCVnQvvybowjzGBdp1f1Kb IDRUo/A9J0GgUiDIdrV+jhHfeeobl1yz1c/UZ/WqNzpeUoUIga4uN5vR0bp+YTs4LJgW 6w5yVavybBcdtjtwXQVBfr5svg1+cdPHqAptMEdgnFR0v0a0mUeYOPFxYHHHv5Wo5JpF m3fLVEvrkLaqyZ/tXo7h2PlKHFdQSE+sIiEmmU9rqFV/U1OtYedQcnqGc4fIujHGAR8x jJVTPgYQRq601g2E48Eq2dW7VTozxhC2xXq1j666UgZfll30BGxD4yYHyjDHiKRapEIe NMbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732278262; x=1732883062; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=zBJjgVPmlrNf+EtO/T42VR1vO+YWk6Sg9oIuB315+lw=; b=ol1BlFazsUKeZJgXroYr34arLLivKHJhU/tgDBb86ncqNk+HXqrKPHhPEHU2dyA+rk LAtUlr9wW1+JlFAzXVKqJ1XcXqG+W4km9MhBhGsnub7JbGyaqNXawsi/4U4YPEVfLSlB 9/2XJYsCtR/XUVsdrNtChVfHpP0Vjt9l3oZmX+QWamCOImDA018hRVbv+yF26Ap3a0EM mvvRlzeLCwgaw5rjtFRblXPVnbDnc/IzkFsw3Y37hqh+hAEOIzBZoouuVGjGHeEDqGxy aoAhyz/F2tEGDOrmziKjHioM9QWoKingv+PvO/SVRDxfhRq0leMFiKlypQF/sXLClod0 9oOg== X-Forwarded-Encrypted: i=1; AJvYcCVnFsJz5ZuNHmzryBimiSLLkt6mqPx7pa79vgnxSqIZ6ezympwVY2YI5qWcEEE0PnHqYnVRwoBzG70YPBVl@postgresql.org X-Gm-Message-State: AOJu0Yw2vIpm9JEBU8NoP3BT/AoLv9j9ZJruePkJFyCUJfLEr+L5IVF6 sbldA3/e1G+JDcgnuvMz0rSN90MLxLXIIi+sZGjSuzkGrohtFD6wy18yaSutHqs5AKzk2sg/WJT 8upYd/zxyvniyiNvf9eAAPOSS7f9X5m5gZ8t9 X-Gm-Gg: ASbGnctfNRVXZN1p/rphOEb85is/AICBNXBf64tkOazaMyrNmV89wJQBdpZ+he/PHj4 wxMCOnxav4QUMEodgzLJNCLkg60xkqOh5 X-Google-Smtp-Source: AGHT+IFnw7uunxr9Sp6CB7Pj7duh601ZHobnQOPyk537xRU+rpJ7EoGzO2ltFoK1OxVtNC4JAMAF1KbXYdlr077hlgo= X-Received: by 2002:a17:907:1b27:b0:a9e:c267:78c5 with SMTP id a640c23a62f3a-aa509c00bc8mr279750166b.55.1732278261976; Fri, 22 Nov 2024 04:24:21 -0800 (PST) MIME-Version: 1.0 References: <202411131029.qchduffwgzhm@alvherre.pgsql> <7d32e088-34a7-421a-9398-80958acb3f64@technowledgy.de> In-Reply-To: <7d32e088-34a7-421a-9398-80958acb3f64@technowledgy.de> From: Eric Hanson Date: Fri, 22 Nov 2024 06:24:10 -0600 Message-ID: Subject: Re: Fwd: A million users To: walther@technowledgy.de Cc: Dominique Devienne , Alvaro Herrera , Vijaykumar Jain , pgsql-general , "kaare@jasonic.dk" Content-Type: multipart/alternative; boundary="00000000000075306d06277f764e" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --00000000000075306d06277f764e Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, Nov 13, 2024 at 12:02=E2=80=AFPM wrote: > I don't have any benchmarks, but the following data point: > > We use PostgREST [1] which connects to the database with one > "authenticator" role. For each request it handles, it does a SET ROLE to > a role defined in the Authorization Header (JWT). > > Some numbers we are running with currently: > - 1 authenticator role > - ~ 127.000 user roles granted to "authenticator" > - ~ 14.000 "scope" roles granted to the user roles (tenants, groups, ..) > - ~ 15 "context" roles granted to user roles ("admin", "user", ...) > - ~ 50 "access" roles granted to context roles ("view_x", "do_y", ...) > > Only the access roles have any direct privileges granted. > > We currently have ~ 700 RLS policies defined. Those are created TO the > context roles. The policies check the current role's scope roles to > select "allowed" rows. > > In total, we have ~370.000 roles granted to each other (pg_auth_members). > > Except for one thing, we have never had any real problems with this. We > didn't observe anything getting massively worse with many roles, even > though we use them extensively. RLS policies need to be carefully > written to get any performance, though. > > The one problem we found is: > > The first time the authenticator role does a SET ROLE in a session it's > **terribly** slow. With fewer users back then it took 6-7 minutes to do > it. Any SET ROLE afterwards in the same session would be fast. Even more > annoying - killing the session with SET ROLE running would not work > properly and leave zombie processes. Giving the authenticator role the > SUPERUSER privilege avoids the problem and makes it instant. However.. > that's not very desirable. > > There were some improvements, IIRC in the 17 cycle (?), in that area, > but I had not have the time to test it with that. We are still on v15 > and the last time I tested this was ~ two years ago. I still wasn't able > to put together a simple reproducer either. > > You should *probably* be better off with your different LOGIN roles, I > assume the role cache builds up much quicker in that case. > I'm really interested in how this works. Role-per-user or even the ability to have many roles (370k??) seems like a dream come true. But I always was wary of it because: a) A connection-per-role hits the ceiling pretty quickly because connections can't be pooled and shared between users and take up a lot of memory etc. b) One could try to get around this with an authenticator role as you describe, but isn't it then possible to do a RESET ROLE and then another SET ROLE to get access to another user? This of course would have to be through SQL injection or some such, but it seems like that defeats at least some of the purpose of RLS. Did you find some way to prevent RESET ROLE? I once advocated for a NO RESET option on SET ROLE [1] so that RESET ROLE would be impossible for the rest of the session. Still think it would be helpful. Thanks, Eric [1] https://www.postgresql.org/message-id/flat/CACA6kxgdzt-oForijaxfXHHhnZ1WBoV= GMXVwFrJqUu-Hg3C-jA%40mail.gmail.com --00000000000075306d06277f764e Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Wed, Nov 13, 2024 at 12:02=E2=80=AFPM = <walther@technowledgy.de&= gt; wrote:
I don't have any benchmarks, but the following data p= oint:

We use PostgREST [1] which connects to the database with one
"authenticator" role. For each request it handles, it does a SET = ROLE to
a role defined in the Authorization Header (JWT).

Some numbers we are running with currently:
- 1 authenticator role
- ~ 127.000 user roles granted to "authenticator"
- ~ 14.000 "scope" roles granted to the user roles (tenants, grou= ps, ..)
- ~ 15 "context" roles granted to user roles ("admin", = "user", ...)
- ~ 50 "access" roles granted to context roles ("view_x"= ;, "do_y", ...)

Only the access roles have any direct privileges granted.

We currently have ~ 700 RLS policies defined. Those are created TO the
context roles. The policies check the current role's scope roles to select "allowed" rows.

In total, we have ~370.000 roles granted to each other (pg_auth_members).
Except for one thing, we have never had any real problems with this. We didn't observe anything getting massively worse with many roles, even <= br> though we use them extensively. RLS policies need to be carefully
written to get any performance, though.

The one problem we found is:

The first time the authenticator role does a SET ROLE in a session it's=
**terribly** slow. With fewer users back then it took 6-7 minutes to do it. Any SET ROLE afterwards in the same session would be fast. Even more annoying - killing the session with SET ROLE running would not work
properly and leave zombie processes. Giving the authenticator role the
SUPERUSER privilege avoids the problem and makes it instant. However..
that's not very desirable.

There were some improvements, IIRC in the 17 cycle (?), in that area,
but I had not have the time to test it with that. We are still on v15
and the last time I tested this was ~ two years ago. I still wasn't abl= e
to put together a simple reproducer either.

You should *probably* be better off with your different LOGIN roles, I
assume the role cache builds up much quicker in that case.
=

I'm really interested in how this works.=C2=A0 Role= -per-user or even the ability to have many roles (370k??)=C2=A0seems like a= dream come true.=C2=A0But I always was wary of it because:

<= /div>
a) A connection-per-role hits the ceiling pretty quickly because = connections can't be pooled and shared between users and take up a lot = of memory etc.

b) One could try to get around this= with an authenticator role as you describe, but isn't it then possible= to do a RESET ROLE and then another SET ROLE to get access to another user= ?=C2=A0 This of course would have to be through SQL injection or some such,= but it seems like that defeats at least some of the purpose of RLS.
<= div>
Did you find some way to prevent RESET ROLE?=C2=A0 I onc= e advocated for a NO RESET option on SET ROLE [1] so that RESET ROLE would = be impossible for the rest of the session.=C2=A0 Still think it would be he= lpful.

Thanks,
Eric

=
=C2=A0
=
--00000000000075306d06277f764e--