Re: Non-superuser subscription owners

2023-06-15 Thread Amit Kapila
On Thu, Jun 15, 2023 at 11:18 PM Alvaro Herrera  wrote:
>
> On 2023-Jun-13, Amit Kapila wrote:
>
> > I'll push this tomorrow unless there are any suggestions or comments.
>
> Note the proposed commit message is wrong about which commit is to blame
> for the original problem -- it mentions e7e7da2f8d57 twice, but one of
> them is actually c3afe8cf5a1e.
>

Right, I also noticed this and changed it before pushing, See
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=b5c517379a40fa1af84c0852aa3730a5875a6482

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-06-15 Thread Alvaro Herrera
On 2023-Jun-13, Amit Kapila wrote:

> I'll push this tomorrow unless there are any suggestions or comments.

Note the proposed commit message is wrong about which commit is to blame
for the original problem -- it mentions e7e7da2f8d57 twice, but one of
them is actually c3afe8cf5a1e.

-- 
Álvaro Herrera   48°01'N 7°57'E  —  https://www.EnterpriseDB.com/




RE: Non-superuser subscription owners

2023-06-13 Thread Zhijie Hou (Fujitsu)
On Wednesday, June 14, 2023 10:11 AM Amit Kapila  
wrote:
> 
> On Tue, Jun 13, 2023 at 2:25 PM Amit Kapila  wrote:
> >
> > On Fri, May 12, 2023 at 3:28 PM Zhijie Hou (Fujitsu)
> >  wrote:
> > >
> > >
> > > I can reproduce this via gdb following similar steps in [1].
> > >
> > > I think we need to move this call into a transaction as well and
> > > here is an attempt to do that.
> > >
> >
> > I am able to reproduce this issue following the steps mentioned by you
> > and the proposed patch to fix the issue looks good to me.
> >
> 
> Today, again looking at the patch, it seems to me that it would be better if 
> we
> can fix this without starting a new transaction. Won't it be better if we 
> move this
> syscall to a place where we are fetching relstate (GetSubscriptionRelState()) 
> a
> few lines above? I understand by doing that in some cases like when copy_data
> = false, we may do this syscall unnecessarily but OTOH, starting a new
> transaction just for a syscall (superuser_arg()) also doesn't seem like a good
> idea to me.

Makes sense to me, here is the updated patch which does the same.

Best Regards,
Hou zj


v2-0001-Fix-possible-logical-replication-table-sync-crash.patch
Description:  v2-0001-Fix-possible-logical-replication-table-sync-crash.patch


Re: Non-superuser subscription owners

2023-06-13 Thread Amit Kapila
On Tue, Jun 13, 2023 at 2:25 PM Amit Kapila  wrote:
>
> On Fri, May 12, 2023 at 3:28 PM Zhijie Hou (Fujitsu)
>  wrote:
> >
> >
> > I can reproduce this via gdb following similar steps in [1].
> >
> > I think we need to move this call into a transaction as well and here is an 
> > attempt
> > to do that.
> >
>
> I am able to reproduce this issue following the steps mentioned by you
> and the proposed patch to fix the issue looks good to me.
>

Today, again looking at the patch, it seems to me that it would be
better if we can fix this without starting a new transaction. Won't it
be better if we move this syscall to a place where we are fetching
relstate (GetSubscriptionRelState()) a few lines above? I understand
by doing that in some cases like when copy_data = false, we may do
this syscall unnecessarily but OTOH, starting a new transaction just
for a syscall (superuser_arg()) also doesn't seem like a good idea to
me.

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-06-13 Thread Amit Kapila
On Tue, Jun 13, 2023 at 2:25 PM Amit Kapila  wrote:
>
> On Fri, May 12, 2023 at 3:28 PM Zhijie Hou (Fujitsu)
>  wrote:
> >
> >
> > I can reproduce this via gdb following similar steps in [1].
> >
> > I think we need to move this call into a transaction as well and here is an 
> > attempt
> > to do that.
> >
>
> I am able to reproduce this issue following the steps mentioned by you
> and the proposed patch to fix the issue looks good to me.
>

I'll push this tomorrow unless there are any suggestions or comments.

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-06-13 Thread Amit Kapila
On Fri, May 12, 2023 at 3:28 PM Zhijie Hou (Fujitsu)
 wrote:
>
>
> I can reproduce this via gdb following similar steps in [1].
>
> I think we need to move this call into a transaction as well and here is an 
> attempt
> to do that.
>

I am able to reproduce this issue following the steps mentioned by you
and the proposed patch to fix the issue looks good to me.

-- 
With Regards,
Amit Kapila.




RE: Non-superuser subscription owners

2023-05-12 Thread Zhijie Hou (Fujitsu)
On Tuesday, April 4, 2023 1:57 AM Robert Haas  wrote:
> 
> On Sat, Apr 1, 2023 at 12:00 PM Alexander Lakhin 
> wrote:
> > I've managed to reproduce it using the following script:
> > for ((i=1;i<=10;i++)); do
> > echo "iteration $i"
> > echo "
> > CREATE ROLE sub_user;
> > CREATE SUBSCRIPTION testsub CONNECTION 'dbname=db'
> >   PUBLICATION testpub WITH (connect = false); ALTER SUBSCRIPTION
> > testsub ENABLE; DROP SUBSCRIPTION testsub; SELECT pg_sleep(0.001);
> > DROP ROLE sub_user; " | psql psql -c "ALTER SUBSCRIPTION testsub
> > DISABLE;"
> > psql -c "ALTER SUBSCRIPTION testsub SET (slot_name = NONE);"
> > psql -c "DROP SUBSCRIPTION testsub;"
> > grep 'TRAP' server.log && break
> > done
> 
> After a bit of experimentation this repro worked for me -- I needed
> -DRELCACHE_FORCE_RELEASE as well, and a bigger iteration count. I verified
> that the patch fixed it, and committed the patch with the addition of a
> comment.

Thanks for pushing!

While testing this, I found a similar problem in table sync worker,
as we also invoke superuser_arg() in table sync worker which is not in a
transaction.

LogicalRepSyncTableStart
...
/* Is the use of a password mandatory? */
must_use_password = MySubscription->passwordrequired &&
!superuser_arg(MySubscription->owner);

#0  0x7f18bb55aaff in raise () from /lib64/libc.so.6
#1  0x7f18bb52dea5 in abort () from /lib64/libc.so.6
#2  0x00b69a22 in ExceptionalCondition (conditionName=0xda4338 
"IsTransactionState()", fileName=0xda403e "catcache.c", lineNumber=1208) at 
assert.c:66
#3  0x00b4842a in SearchCatCacheInternal (cache=0x27cab80, nkeys=1, 
v1=10, v2=0, v3=0, v4=0) at catcache.c:1208
#4  0x00b48329 in SearchCatCache1 (cache=0x27cab80, v1=10) at 
catcache.c:1162
#5  0x00b630c7 in SearchSysCache1 (cacheId=11, key1=10) at 
syscache.c:825
#6  0x00b982e3 in superuser_arg (roleid=10) at superuser.c:70

I can reproduce this via gdb following similar steps in [1].

I think we need to move this call into a transaction as well and here is an 
attempt
to do that.

[1] 
https://www.postgresql.org/message-id/OS0PR01MB5716E596E4FB83DE46F592FE948C9%40OS0PR01MB5716.jpnprd01.prod.outlook.com

Best Regards,
Hou zj


0001-Fix-possible-logical-replication-table-sync-crash.patch
Description:  0001-Fix-possible-logical-replication-table-sync-crash.patch


Re: Non-superuser subscription owners

2023-04-23 Thread Amit Kapila
On Fri, Apr 21, 2023 at 6:21 PM Robert Haas  wrote:
>
> On Fri, Apr 21, 2023 at 8:19 AM Amit Kapila  wrote:
> > LGTM. Let's see if Robert or others have any comments, otherwise, I'll
> > push this early next week.
>
> LGTM too.
>

Pushed.

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-04-21 Thread Robert Haas
On Fri, Apr 21, 2023 at 8:19 AM Amit Kapila  wrote:
> LGTM. Let's see if Robert or others have any comments, otherwise, I'll
> push this early next week.

LGTM too.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-04-21 Thread Amit Kapila
On Fri, Apr 21, 2023 at 12:30 PM vignesh C  wrote:
>
> On Fri, 21 Apr 2023 at 01:49, Robert Haas  wrote:
> >
> > On Thu, Apr 20, 2023 at 1:08 AM Amit Kapila  wrote:
> > > Pushed. I noticed that we didn't display this new subscription option
> > > 'password_required' in \dRs+:
> > >
> > > postgres=# \dRs+
> > >
> > >   List of subscriptions
> > >  Name |  Owner   | Enabled | Publication | Binary | Streaming |
> > > Two-phase commit | Disable on error | Origin | Run as Owner? |
> > > Synchronous commit |Conninfo | Skip LSN
> > >
> > > Is that intentional? Sorry, if it was discussed previously because I
> > > haven't followed this discussion in detail.
> >
> > No, I don't think that's intentional. I just didn't think about it.
>
> Here is a patch to display Password required with \dRs+ command. Also
> added one test to describe subscription when password_required is
> false, as all the existing tests were there only for password_required
> as true.
>

LGTM. Let's see if Robert or others have any comments, otherwise, I'll
push this early next week.

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-04-21 Thread vignesh C
On Fri, 21 Apr 2023 at 01:49, Robert Haas  wrote:
>
> On Thu, Apr 20, 2023 at 1:08 AM Amit Kapila  wrote:
> > Pushed. I noticed that we didn't display this new subscription option
> > 'password_required' in \dRs+:
> >
> > postgres=# \dRs+
> >
> >   List of subscriptions
> >  Name |  Owner   | Enabled | Publication | Binary | Streaming |
> > Two-phase commit | Disable on error | Origin | Run as Owner? |
> > Synchronous commit |Conninfo | Skip LSN
> >
> > Is that intentional? Sorry, if it was discussed previously because I
> > haven't followed this discussion in detail.
>
> No, I don't think that's intentional. I just didn't think about it.

Here is a patch to display Password required with \dRs+ command. Also
added one test to describe subscription when password_required is
false, as all the existing tests were there only for password_required
as true.

Regards,
Vignesh
From d0379b915a449d5763bd7665a1ec32edad009bd3 Mon Sep 17 00:00:00 2001
From: Vignesh C 
Date: Fri, 21 Apr 2023 11:54:17 +0530
Subject: [PATCH] Display 'password_required' option for \dRs+ command.

In commit c3afe8cf5a, we added the option 'password_required', this option
should be displayed with \dRs+ command.
---
 src/bin/psql/describe.c|   4 +-
 src/test/regress/expected/subscription.out | 151 +++--
 src/test/regress/sql/subscription.sql  |   2 +
 3 files changed, 84 insertions(+), 73 deletions(-)

diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 83a37ee601..058e41e749 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -6493,7 +6493,7 @@ describeSubscriptions(const char *pattern, bool verbose)
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
 	static const bool translate_columns[] = {false, false, false, false,
-	false, false, false, false, false, false, false, false, false};
+	false, false, false, false, false, false, false, false, false, false};
 
 	if (pset.sversion < 10)
 	{
@@ -6551,8 +6551,10 @@ describeSubscriptions(const char *pattern, bool verbose)
 		if (pset.sversion >= 16)
 			appendPQExpBuffer(,
 			  ", suborigin AS \"%s\"\n"
+			  ", subpasswordrequired AS \"%s\"\n"
 			  ", subrunasowner AS \"%s\"\n",
 			  gettext_noop("Origin"),
+			  gettext_noop("Password required"),
 			  gettext_noop("Run as Owner?"));
 
 		appendPQExpBuffer(,
diff --git a/src/test/regress/expected/subscription.out b/src/test/regress/expected/subscription.out
index 9c52890f1d..d736246259 100644
--- a/src/test/regress/expected/subscription.out
+++ b/src/test/regress/expected/subscription.out
@@ -115,18 +115,18 @@ CREATE SUBSCRIPTION regress_testsub4 CONNECTION 'dbname=regress_doesnotexist' PU
 WARNING:  subscription was created, but is not connected
 HINT:  To initiate replication, you must manually create the replication slot, enable the subscription, and refresh the subscription.
 \dRs+ regress_testsub4
- List of subscriptions
-   Name   |   Owner   | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Run as Owner? | Synchronous commit |  Conninfo   | Skip LSN 
---+---+-+-++---+--+--++---++-+--
- regress_testsub4 | regress_subscription_user | f   | {testpub}   | f  | off   | d| f| none   | f | off| dbname=regress_doesnotexist | 0/0
+   List of subscriptions
+   Name   |   Owner   | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as Owner? | Synchronous commit |  Conninfo   | Skip LSN 
+--+---+-+-++---+--+--++---+---++-+--
+ regress_testsub4 | regress_subscription_user | f   | {testpub}   | f  | off   | d| f| none   | t | f | off| dbname=regress_doesnotexist | 0/0
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub4 SET (origin = any);
 \dRs+ regress_testsub4
- List of subscriptions
-   Name   |   Owner   | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Run as Owner? | Synchronous commit |  Conninfo   | Skip LSN 

Re: Non-superuser subscription owners

2023-04-20 Thread Robert Haas
On Thu, Apr 20, 2023 at 1:08 AM Amit Kapila  wrote:
> Pushed. I noticed that we didn't display this new subscription option
> 'password_required' in \dRs+:
>
> postgres=# \dRs+
>
>   List of subscriptions
>  Name |  Owner   | Enabled | Publication | Binary | Streaming |
> Two-phase commit | Disable on error | Origin | Run as Owner? |
> Synchronous commit |Conninfo | Skip LSN
>
> Is that intentional? Sorry, if it was discussed previously because I
> haven't followed this discussion in detail.

No, I don't think that's intentional. I just didn't think about it.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-04-19 Thread Amit Kapila
On Thu, Apr 13, 2023 at 8:02 AM Amit Kapila  wrote:
>
> On Wed, Apr 12, 2023 at 5:50 PM Robert Haas  wrote:
> >
> > On Tue, Apr 11, 2023 at 10:56 PM Amit Kapila  
> > wrote:
> > > Anyway, I don't think as such there is any problem
> > > with restarting the worker even when the subscription owner is a
> > > superuser, so adjusted the check accordingly.
> >
> > LGTM.
> >
>
> Thanks. I am away for a few days so can push it only next week.
>

Pushed. I noticed that we didn't display this new subscription option
'password_required' in \dRs+:

postgres=# \dRs+

  List of subscriptions
 Name |  Owner   | Enabled | Publication | Binary | Streaming |
Two-phase commit | Disable on error | Origin | Run as Owner? |
Synchronous commit |Conninfo | Skip LSN

Is that intentional? Sorry, if it was discussed previously because I
haven't followed this discussion in detail.

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-04-12 Thread Amit Kapila
On Wed, Apr 12, 2023 at 5:50 PM Robert Haas  wrote:
>
> On Tue, Apr 11, 2023 at 10:56 PM Amit Kapila  wrote:
> > Anyway, I don't think as such there is any problem
> > with restarting the worker even when the subscription owner is a
> > superuser, so adjusted the check accordingly.
>
> LGTM.
>

Thanks. I am away for a few days so can push it only next week.

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-04-12 Thread Robert Haas
On Tue, Apr 11, 2023 at 10:56 PM Amit Kapila  wrote:
> Anyway, I don't think as such there is any problem
> with restarting the worker even when the subscription owner is a
> superuser, so adjusted the check accordingly.

LGTM. I realize we could do more sophisticated things here, but I
think it's better to keep the code simple.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-04-11 Thread Amit Kapila
On Tue, Apr 11, 2023 at 8:21 PM Robert Haas  wrote:
>
> On Tue, Apr 11, 2023 at 5:53 AM Amit Kapila  wrote:
> > I think additionally, we should check that the new owner of the
> > subscription is not a superuser, otherwise, anyway, this parameter is
> > ignored. Please find the attached to add this check.
>
> I don't see why we should check that. It makes this different from all
> the other cases and I don't see any benefit.
>

I thought it would be better if we don't restart the worker unless it
is required. In case, the subscription's owner is a superuser, the
'password_required' is ignored, so why restart the apply worker when
somebody changes it in such a case? I understand that there may not be
a need to change the 'password_required' option when the
subscription's owner is the superuser but one may first choose to
change the password_required flag and then the owner of a subscription
to a non-superuser. Anyway, I don't think as such there is any problem
with restarting the worker even when the subscription owner is a
superuser, so adjusted the check accordingly.

-- 
With Regards,
Amit Kapila.


exit_on_sub_opt_change_2.patch
Description: Binary data


Re: Non-superuser subscription owners

2023-04-11 Thread Robert Haas
On Tue, Apr 11, 2023 at 5:53 AM Amit Kapila  wrote:
> I think additionally, we should check that the new owner of the
> subscription is not a superuser, otherwise, anyway, this parameter is
> ignored. Please find the attached to add this check.

I don't see why we should check that. It makes this different from all
the other cases and I don't see any benefit.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-04-11 Thread Amit Kapila
On Mon, Apr 10, 2023 at 9:15 PM Robert Haas  wrote:
>
> On Sat, Apr 8, 2023 at 1:35 AM Amit Kapila  wrote:
> > Do we need to have a check for this new option "password_required" in
> > maybe_reread_subscription() where we "Exit if any parameter that
> > affects the remote connection was changed."? This new option is
> > related to the remote connection so I thought it is worth considering
> > whether we want to exit and restart the apply worker when this option
> > is changed.
>
> Hmm, good question. I think that's probably a good idea. If the
> current connection is already working, the only possible result of
> getting rid of it and trying to create a new one is that it might now
> fail instead, but someone might want that behavior. Otherwise, they'd
> instead find the failure at a later, maybe less convenient, time.
>

I think additionally, we should check that the new owner of the
subscription is not a superuser, otherwise, anyway, this parameter is
ignored. Please find the attached to add this check.

-- 
With Regards,
Amit Kapila.


exit_on_sub_opt_change_1.patch
Description: Binary data


Re: Non-superuser subscription owners

2023-04-10 Thread Robert Haas
On Sat, Apr 8, 2023 at 1:35 AM Amit Kapila  wrote:
> Do we need to have a check for this new option "password_required" in
> maybe_reread_subscription() where we "Exit if any parameter that
> affects the remote connection was changed."? This new option is
> related to the remote connection so I thought it is worth considering
> whether we want to exit and restart the apply worker when this option
> is changed.

Hmm, good question. I think that's probably a good idea. If the
current connection is already working, the only possible result of
getting rid of it and trying to create a new one is that it might now
fail instead, but someone might want that behavior. Otherwise, they'd
instead find the failure at a later, maybe less convenient, time.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-04-07 Thread Amit Kapila
On Thu, Mar 30, 2023 at 9:35 PM Robert Haas  wrote:
>
> On Tue, Mar 28, 2023 at 1:52 PM Jeff Davis  wrote:
> > On Fri, 2023-03-24 at 00:17 -0700, Jeff Davis wrote:
> > > The other patch you posted seems like it makes a lot of progress in
> > > that direction, and I think that should go in first. That was one of
> > > the items I suggested previously[2], so thank you for working on
> > > that.
> >
> > The above is not a hard objection.
>
> The other patch is starting to go in a direction that is going to have
> some conflicts with this one, so I went ahead and committed this one
> to avoid rebasing pain.
>

Do we need to have a check for this new option "password_required" in
maybe_reread_subscription() where we "Exit if any parameter that
affects the remote connection was changed."? This new option is
related to the remote connection so I thought it is worth considering
whether we want to exit and restart the apply worker when this option
is changed.

-- 
With Regards,
Amit Kapila.




Re: Non-superuser subscription owners

2023-04-03 Thread Robert Haas
On Sat, Apr 1, 2023 at 12:00 PM Alexander Lakhin  wrote:
> I've managed to reproduce it using the following script:
> for ((i=1;i<=10;i++)); do
> echo "iteration $i"
> echo "
> CREATE ROLE sub_user;
> CREATE SUBSCRIPTION testsub CONNECTION 'dbname=db'
>   PUBLICATION testpub WITH (connect = false);
> ALTER SUBSCRIPTION testsub ENABLE;
> DROP SUBSCRIPTION testsub;
> SELECT pg_sleep(0.001);
> DROP ROLE sub_user;
> " | psql
> psql -c "ALTER SUBSCRIPTION testsub DISABLE;"
> psql -c "ALTER SUBSCRIPTION testsub SET (slot_name = NONE);"
> psql -c "DROP SUBSCRIPTION testsub;"
> grep 'TRAP' server.log && break
> done

After a bit of experimentation this repro worked for me -- I needed
-DRELCACHE_FORCE_RELEASE as well, and a bigger iteration count. I
verified that the patch fixed it, and committed the patch with the
addition of a comment.

Thanks very much for this repro, and likewise many thanks to Hou
Zhijie for the report and patch.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-04-01 Thread Andres Freund
Hi, 

On April 1, 2023 9:00:00 AM PDT, Alexander Lakhin  wrote:
>Hello Robert,
>
>31.03.2023 23:00, Robert Haas wrote:
>> That looks like a reasonable fix but I can't reproduce the problem
>> locally. I thought the reason why that machine sees the problem might
>> be that it uses -DRELCACHE_FORCE_RELEASE, but I tried that option here
>> and the tests still pass. Anyone ideas how to reproduce?
>
>I've managed to reproduce it using the following script:
>for ((i=1;i<=10;i++)); do
>echo "iteration $i"
>echo "
>CREATE ROLE sub_user;
>CREATE SUBSCRIPTION testsub CONNECTION 'dbname=db'
>  PUBLICATION testpub WITH (connect = false);
>ALTER SUBSCRIPTION testsub ENABLE;
>DROP SUBSCRIPTION testsub;
>SELECT pg_sleep(0.001);
>DROP ROLE sub_user;
>" | psql
>psql -c "ALTER SUBSCRIPTION testsub DISABLE;"
>psql -c "ALTER SUBSCRIPTION testsub SET (slot_name = NONE);"
>psql -c "DROP SUBSCRIPTION testsub;"
>grep 'TRAP' server.log && break
>done
>
>iteration 3
>CREATE ROLE
>...
>ALTER SUBSCRIPTION
>WARNING:  terminating connection because of crash of another server process
>DETAIL:  The postmaster has commanded this server process to roll back the 
>current transaction and exit, because ano
>ther server process exited abnormally and possibly corrupted shared memory.
>HINT:  In a moment you should be able to reconnect to the database and repeat 
>your command.
>server closed the connection unexpectedly
>   This probably means the server terminated abnormally
>   before or while processing the request.
>connection to server was lost
>TRAP: failed Assert("IsTransactionState()"), File: "catcache.c", Line: 1208, 
>PID: 1001242

Errors like that are often easier to reproduce with clobber caches (or whatever 
the name is these days) enabled.

Andres
-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.




Re: Non-superuser subscription owners

2023-04-01 Thread Alexander Lakhin

Hello Robert,

31.03.2023 23:00, Robert Haas wrote:

That looks like a reasonable fix but I can't reproduce the problem
locally. I thought the reason why that machine sees the problem might
be that it uses -DRELCACHE_FORCE_RELEASE, but I tried that option here
and the tests still pass. Anyone ideas how to reproduce?


I've managed to reproduce it using the following script:
for ((i=1;i<=10;i++)); do
echo "iteration $i"
echo "
CREATE ROLE sub_user;
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=db'
  PUBLICATION testpub WITH (connect = false);
ALTER SUBSCRIPTION testsub ENABLE;
DROP SUBSCRIPTION testsub;
SELECT pg_sleep(0.001);
DROP ROLE sub_user;
" | psql
psql -c "ALTER SUBSCRIPTION testsub DISABLE;"
psql -c "ALTER SUBSCRIPTION testsub SET (slot_name = NONE);"
psql -c "DROP SUBSCRIPTION testsub;"
grep 'TRAP' server.log && break
done

iteration 3
CREATE ROLE
...
ALTER SUBSCRIPTION
WARNING:  terminating connection because of crash of another server process
DETAIL:  The postmaster has commanded this server process to roll back the 
current transaction and exit, because ano
ther server process exited abnormally and possibly corrupted shared memory.
HINT:  In a moment you should be able to reconnect to the database and repeat 
your command.
server closed the connection unexpectedly
   This probably means the server terminated abnormally
   before or while processing the request.
connection to server was lost
TRAP: failed Assert("IsTransactionState()"), File: "catcache.c", Line: 1208, 
PID: 1001242

Best regards,
Alexander

RE: Non-superuser subscription owners

2023-03-31 Thread houzj.f...@fujitsu.com
On Saturday, April 1, 2023 4:00 AM Robert Haas 

Hi,

> 
> On Thu, Mar 30, 2023 at 9:49 PM houzj.f...@fujitsu.com
>  wrote:
> > It looks like the super user check is out of a transaction, I haven't
> > checked why it only failed on one BF animal, but it seems we can put
> > the check into the transaction like the following:
> 
> That looks like a reasonable fix but I can't reproduce the problem locally. I
> thought the reason why that machine sees the problem might be that it uses
> -DRELCACHE_FORCE_RELEASE, but I tried that option here and the tests still 
> pass.
> Anyone ideas how to reproduce?

I think it's a timing problem because superuser_arg() function will cache the
roleid that passed in last time, so it might not search the syscache to hit the
Assert() check each time. And in the regression test, the roleid cache happened
to be invalidated before the superuser_arg() by some concurrently ROLE change(
maybe in subscription.sql and publication.sql).

I can reproduce it by using gdb and starting another session to change the ROLE.

When the apply worker starts, use the gdb to block the apply worker in the
transaction before the super user check. Then start another session to ALTER
ROLE to invalidate the roleid cache in superuser_arg() which will cause the
apply worker to search the syscache and hit the Assert().

--
origin_startpos = replorigin_session_get_progress(false);
B*  CommitTransactionCommand();

/* Is the use of a password mandatory? */
must_use_password = MySubscription->passwordrequired &&
! superuser_arg(MySubscription->owner);
--

Best Regards,
Hou zj


Re: Non-superuser subscription owners

2023-03-31 Thread Robert Haas
On Thu, Mar 30, 2023 at 9:49 PM houzj.f...@fujitsu.com
 wrote:
> It looks like the super user check is out of a transaction, I haven't checked 
> why
> it only failed on one BF animal, but it seems we can put the check into the
> transaction like the following:

That looks like a reasonable fix but I can't reproduce the problem
locally. I thought the reason why that machine sees the problem might
be that it uses -DRELCACHE_FORCE_RELEASE, but I tried that option here
and the tests still pass. Anyone ideas how to reproduce?

-- 
Robert Haas
EDB: http://www.enterprisedb.com




RE: Non-superuser subscription owners

2023-03-30 Thread houzj.f...@fujitsu.com
On Friday, March 31, 2023 12:05 AM Robert Haas  wrote:

Hi,

> 
> On Tue, Mar 28, 2023 at 1:52 PM Jeff Davis  wrote:
> > On Fri, 2023-03-24 at 00:17 -0700, Jeff Davis wrote:
> > > The other patch you posted seems like it makes a lot of progress in
> > > that direction, and I think that should go in first. That was one of
> > > the items I suggested previously[2], so thank you for working on
> > > that.
> >
> > The above is not a hard objection.
> 
> The other patch is starting to go in a direction that is going to have some
> conflicts with this one, so I went ahead and committed this one to avoid
> rebasing pain.

I noticed the BF[1] report a core dump after this commit.

#0  0xfd581864 in _lwp_kill () from /usr/lib/libc.so.12
#0  0xfd581864 in _lwp_kill () from /usr/lib/libc.so.12
#1  0xfd5817dc in raise () from /usr/lib/libc.so.12
#2  0xfd581c88 in abort () from /usr/lib/libc.so.12
#3  0x01e6c8d4 in ExceptionalCondition 
(conditionName=conditionName@entry=0x2007758 "IsTransactionState()", 
fileName=fileName@entry=0x20565c4 "catcache.c", 
lineNumber=lineNumber@entry=1208) at assert.c:66
#4  0x01e4e404 in SearchCatCacheInternal (cache=0xfd21e500, 
nkeys=nkeys@entry=1, v1=v1@entry=28985, v2=v2@entry=0, v3=v3@entry=0, 
v4=v4@entry=0) at catcache.c:1208
#5  0x01e4eea0 in SearchCatCache1 (cache=, v1=v1@entry=28985) at 
catcache.c:1162
#6  0x01e66e34 in SearchSysCache1 (cacheId=cacheId@entry=11, 
key1=key1@entry=28985) at syscache.c:825
#7  0x01e98c40 in superuser_arg (roleid=28985) at superuser.c:70
#8  0x01c657bc in ApplyWorkerMain (main_arg=) at worker.c:4552
#9  0x01c1ceac in StartBackgroundWorker () at bgworker.c:861
#10 0x01c23be0 in do_start_bgworker (rw=) at postmaster.c:5762
#11 maybe_start_bgworkers () at postmaster.c:5986
#12 0x01c2459c in process_pm_pmsignal () at postmaster.c:5149
#13 ServerLoop () at postmaster.c:1770
#14 0x01c26cdc in PostmasterMain (argc=argc@entry=4, 
argv=argv@entry=0xe0e4) at postmaster.c:1463
#15 0x01ee2c8c in main (argc=4, argv=0xe0e4) at main.c:200

It looks like the super user check is out of a transaction, I haven't checked 
why
it only failed on one BF animal, but it seems we can put the check into the
transaction like the following:

diff --git a/src/backend/replication/logical/worker.c 
b/src/backend/replication/logical/worker.c
index 6fd674b5d6..08f10fc331 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -4545,12 +4545,13 @@ ApplyWorkerMain(Datum main_arg)
replorigin_session_setup(originid, 0);
replorigin_session_origin = originid;
origin_startpos = replorigin_session_get_progress(false);
-   CommitTransactionCommand();
 
/* Is the use of a password mandatory? */
must_use_password = MySubscription->passwordrequired &&
!superuser_arg(MySubscription->owner);
 
+   CommitTransactionCommand();
+

[1] 
https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=mamba=2023-03-30%2019%3A41%3A08

Best Regards,
Hou Zhijie


Re: Non-superuser subscription owners

2023-03-30 Thread Robert Haas
On Tue, Mar 28, 2023 at 1:52 PM Jeff Davis  wrote:
> On Fri, 2023-03-24 at 00:17 -0700, Jeff Davis wrote:
> > The other patch you posted seems like it makes a lot of progress in
> > that direction, and I think that should go in first. That was one of
> > the items I suggested previously[2], so thank you for working on
> > that.
>
> The above is not a hard objection.

The other patch is starting to go in a direction that is going to have
some conflicts with this one, so I went ahead and committed this one
to avoid rebasing pain.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-28 Thread Jeff Davis
On Fri, 2023-03-24 at 00:17 -0700, Jeff Davis wrote:
> The other patch you posted seems like it makes a lot of progress in
> that direction, and I think that should go in first. That was one of
> the items I suggested previously[2], so thank you for working on
> that.

The above is not a hard objection.

I still hold the opinion that the non-superuser subscriptions work is
feels premature without the apply-as-table-owner work. It would be
great if the other patch ends up ready quickly, which would moot the
commit-ordering question.

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-03-27 Thread Jeff Davis
On Mon, 2023-03-27 at 14:06 -0400, Robert Haas wrote:
> I thought you were asking for those changes to be made before this
> patch got committed, so that's what I was responding to. If you're
> asking for it not to be committed at all, that's a different
> discussion.

I separately had a complaint (in a separate subthread) about the scope
of the predefined role you are introducing, which I think encompasses
two concepts that should be treated differently and I think that may
need to be revisited later. If you ignore this complaint it wouldn't be
the end of the world.

This subthread is about the order in which the patches get committed
(which is a topic you brought up), not whether they are ever to be
committed.

> 
> I kind of agree with you about the feature itself. Even though the
> basic feature works quite well and does something people really want,
> there are a lot of loose ends to sort out, and not just about
> security. But I also want to make some progress. If there are
> problems
> with what I'm proposing that will make us regret committing things
> right before feature freeze, then we shouldn't. But waiting a whole
> additional year to see any kind of improvement is not free; these
> issues are serious.

The non-superuser-subscription-owner patch without the apply-as-table-
owner patch feels like a facade to me, at least right now. Perhaps I
can be convinced otherwise, but that's what it looks like to me.

> 
> I think this patch is a lot better-baked and less speculative than
> that one. I think that patch is more important, so if they were
> equally mature, I'd favor getting that one committed first. But
> that's
> not the case.

You explicitly asked about the order of the patches, which made me
think it was more of an option?

If the apply-as-table-owner patch gets held up for whatever reason, we
might have to make a difficult decision. I'd prefer focus on the apply-
as-table-owner patch briefly, and now that it's getting some review
attention, we might find out how ready it is quite soon.


Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-03-27 Thread Jeff Davis
On Mon, 2023-03-27 at 10:46 -0700, Andres Freund wrote:
> > There are some big issues, like the security model for replaying
> > changes.
> 
> That seems largely unrelated.

They are self-evidently related in a fundamental way. The behavior of
the non-superuser-subscription patch depends on the presence of the
apply-as-table-owner patch.

I think I'd like to understand the apply-as-table-owner patch better to
understand the interaction.

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-03-27 Thread Robert Haas
On Sat, Mar 25, 2023 at 3:16 PM Jeff Davis  wrote:
> On Fri, 2023-03-24 at 09:24 -0400, Robert Haas wrote:
> > I certainly agree that the security model isn't in a reasonable place
> > right now. However, I feel that:
> >
> > (1) adding an extra predefined role
>
> > (2) even adding the connection string security stuff
>
> I don't see how these points are related to the question of whether you
> should commit your non-superuser-subscription-owners patch or logical-
> repl-as-table-owner patch first.

I thought you were asking for those changes to be made before this
patch got committed, so that's what I was responding to. If you're
asking for it not to be committed at all, that's a different
discussion.

> My perspective is that logical replication is an unfinished feature
> with an incomplete design. As I said earlier, that's why I backed away
> from trying to do non-superuser subscriptions as a documented feature:
> it feels like we need to settle some of the underlying pieces first.

I kind of agree with you about the feature itself. Even though the
basic feature works quite well and does something people really want,
there are a lot of loose ends to sort out, and not just about
security. But I also want to make some progress. If there are problems
with what I'm proposing that will make us regret committing things
right before feature freeze, then we shouldn't. But waiting a whole
additional year to see any kind of improvement is not free; these
issues are serious.

> I don't mean to say all of the above issues are blockers or that they
> should all be resolved in my favor. But there are enough issues and
> some of those issues are serious enough that I feel like it's premature
> to just go ahead with the non-superuser subscriptions and the
> predefined role.
>
> There are already users, which complicates things. And you make a good
> point that some important users may be already working around the
> flaws. But there's already a patch and discussion going on for some
> security model improvements (thanks to you), so let's try to get that
> one in first. If we can't, it's probably because we learned something
> important.

I think this patch is a lot better-baked and less speculative than
that one. I think that patch is more important, so if they were
equally mature, I'd favor getting that one committed first. But that's
not the case.

Also, I don't really understand how we could end up not wanting this
patch. I mean there's a lot of things I don't understand that are
still true anyway, so the mere fact that I don't understand how we
could not end up wanting this patch doesn't mean that it couldn't
happen. But like, the current state of play is that subscription
owners are always going to be superusers at the time the subscription
is created, and literally nobody thinks that's a good idea. Some
people (like me) think that we ought to assume that subscription
owners will be and need to be high-privilege users like superusers,
but to my knowledge every such person thinks that it's OK for the
subscription owner to be a non-superuser if they have adequate
privileges. I just think that's a high amount of privileges, not that
it has to be all the privileges i.e. superuser. Other people (like
you, AIUI) think that we ought to try to set things up so that
subscription owners can be low-privilege users, in which case we, once
again, don't want the user who owns the subscription to start out a
superuser. I actually can't imagine anyone defending the idea of
having the subscription owner always be a superuser at the time they
first own the subscription. That's a weird rule that can only serve to
reduce security. Nor can I imagine anyone saying that forcing
subscriptions to be created only by superusers improves security. I
don't think anyone thinks that.

If we're going to delay this patch, probably for a full year, because
of other ongoing discussions, it should be because there is some
outcome of those discussions that would involve deciding that this
patch isn't needed or should be significantly redesigned. If this
patch is going to end up being desirable no matter how those
discussions turn out, and if it's not going to change significantly no
matter how those discussions turn out, then those discussions aren't a
reason not to get it into this release.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-27 Thread Andres Freund
Hi,

On 2023-03-25 12:16:35 -0700, Jeff Davis wrote:
> On Fri, 2023-03-24 at 09:24 -0400, Robert Haas wrote:
> > I certainly agree that the security model isn't in a reasonable place
> > right now. However, I feel that:
> > 
> > (1) adding an extra predefined role
> 
> > (2) even adding the connection string security stuff
> 
> I don't see how these points are related to the question of whether you
> should commit your non-superuser-subscription-owners patch or logical-
> repl-as-table-owner patch first.
> 
> 
> My perspective is that logical replication is an unfinished feature
> with an incomplete design.

I agree with that much.


>  As I said earlier, that's why I backed away from trying to do non-superuser
> subscriptions as a documented feature: it feels like we need to settle some
> of the underlying pieces first.

I don't agree. The patch allows to use logical rep in a far less dangerous
fashion than now. The alternative is to release 16 without a real way to use
logical rep less insanely. Which I think is work.


> There are some big issues, like the security model for replaying
> changes.

That seems largely unrelated.


> And some smaller issues like feature gaps (RLS doesn't work,
> if I remember correctly, and maybe something with partitioning).

Entirely unrelated?

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-03-25 Thread Jeff Davis
On Fri, 2023-03-24 at 09:24 -0400, Robert Haas wrote:
> I certainly agree that the security model isn't in a reasonable place
> right now. However, I feel that:
> 
> (1) adding an extra predefined role

> (2) even adding the connection string security stuff

I don't see how these points are related to the question of whether you
should commit your non-superuser-subscription-owners patch or logical-
repl-as-table-owner patch first.


My perspective is that logical replication is an unfinished feature
with an incomplete design. As I said earlier, that's why I backed away
from trying to do non-superuser subscriptions as a documented feature:
it feels like we need to settle some of the underlying pieces first.

There are some big issues, like the security model for replaying
changes. And some smaller issues like feature gaps (RLS doesn't work,
if I remember correctly, and maybe something with partitioning). There
are potential clashes with other proposals, like the CREATE
SUBSCRIPTION ... SERVER, which I hope can be sorted out later. And I
don't feel like I have a good handle on the publisher security model
and threats, which hopefully is just a matter of documenting some best
practices.

Each time we dig into one of these issues I learn something, and I
think others do, too. If we skip past that process and start adding new
features on top of this unfinished design, then I think we are setting
ourselves up for trouble that is going to be harder to fix later.

I don't mean to say all of the above issues are blockers or that they
should all be resolved in my favor. But there are enough issues and
some of those issues are serious enough that I feel like it's premature
to just go ahead with the non-superuser subscriptions and the
predefined role.

There are already users, which complicates things. And you make a good
point that some important users may be already working around the
flaws. But there's already a patch and discussion going on for some
security model improvements (thanks to you), so let's try to get that
one in first. If we can't, it's probably because we learned something
important.

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-03-24 Thread Robert Haas
On Fri, Mar 24, 2023 at 9:24 AM Robert Haas  wrote:
> > The other patch you posted seems like it makes a lot of progress in
> > that direction, and I think that should go in first. That was one of
> > the items I suggested previously[2], so thank you for working on that.
>
> Perhaps you could review that work?

Ah, you already did. Thanks.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-24 Thread Robert Haas
On Fri, Mar 24, 2023 at 3:17 AM Jeff Davis  wrote:
> The current patch (non-superuser-subscriptions) is the most user-facing
> aspect, and it seems wrong to commit it before we have the security
> model in a reasonable place. As you pointed out[1], it's not in a
> reasonable place now, so encouraging more use seems like a bad idea.

I certainly agree that the security model isn't in a reasonable place
right now. However, I feel that:

(1) adding an extra predefined role doesn't really help, because it
doesn't actually do anything in and of itself, it only prepares for
future work, and

(2) even adding the connection string security stuff that you're
proposing doesn't really help, because (2a) connection string security
is almost completely separate from the internal security
considerations addressed in the message to which you linked, and (2b)
in my opinion, there will be a lot of people who won't use that
connection string security stuff even if we had it, possibly even a
large majority of people won't use it, because it responds to a
specific use case which I think a lot of people don't have, and

(3) I don't agree either that this patch would encourage more use of
logical replication or that it would be bad if it did. I mean, there
could be someone who knows about this patch and will hesitate to
deploy logical replication if it doesn't get committed, or maybe
slightly more likely, won't be able to do so if this patch doesn't get
committed because they're running in a cloud environment. But probably
not. Cloud providers are already hacking around this problem,
Microsoft included. As a community, we're better off having a standard
solution in core than having every vendor hack it their own way. And
outside of a cloud environment, there's not really any reason for the
lack of this patch to make a potential user hesitate. Also, features
getting used is a thing that I think we should all want. If logical
replication is in such a bad state that we think people should be
using it, we should rip it out until the issues are fixed. I don't
think anyone would seriously propose that such a course of action is
advisable. So the alternative is to make it better.

To reiterate what I think the most important point here is, both Azure
and AWS already let you do this. EDB's own cloud offering is also
going to let you do this, whether this change goes in or not. But if
this patch gets committed, then eventually all of those vendors and
whatever others are out there will let you do this in the same way,
i.e. pg_create_subscription, instead of every vendor having their own
patch to the code that does what this patch does through some method
that is specific to that cloud vendor. That sort of fragmentation of
the ecosystem is not good for anyone, AFAICS.

> The other patch you posted seems like it makes a lot of progress in
> that direction, and I think that should go in first. That was one of
> the items I suggested previously[2], so thank you for working on that.

Perhaps you could review that work?

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-24 Thread Jeff Davis
On Wed, 2023-03-22 at 12:16 -0400, Robert Haas wrote:
> I've posted a
> patch for that at
> http://postgr.es/m/CA+TgmoaSCkg9ww9oppPqqs+9RVqCexYCE6Aq=usypfnoode...@mail.gmail.com
> and AFAICT everyone agrees with the idea, even if the patch itself
> hasn't yet attracted any code reviews. But although the two patches
> are fairly closely related, this seems to be a good idea whether that
> moves forward or not, and that seems to be a good idea whether this
> moves forward or not. As this one has had more review and discussion,
> my current thought is to try to get this one committed first.

The current patch (non-superuser-subscriptions) is the most user-facing
aspect, and it seems wrong to commit it before we have the security
model in a reasonable place. As you pointed out[1], it's not in a
reasonable place now, so encouraging more use seems like a bad idea.

The other patch you posted seems like it makes a lot of progress in
that direction, and I think that should go in first. That was one of
the items I suggested previously[2], so thank you for working on that.

Regards,
Jeff Davis


[1]
https://www.postgresql.org/message-id/CA%2BTgmoavSQVcvEW3ZgZ7a1Q-TJ-fp0%2BNt7W3D7FCawArtTCBCQ%40mail.gmail.com

[2]
https://www.postgresql.org/message-id/27c557b12a590067c5e00588009447bb5bb2dd42.ca...@j-davis.com




Re: Non-superuser subscription owners

2023-03-23 Thread Robert Haas
On Thu, Mar 23, 2023 at 1:41 PM Jeff Davis  wrote:
> Even if my changes don't happen, I would find it less confusing and
> more likely that users understand what they're doing.

I respectfully but firmly disagree. I think having two predefined
roles that are both required to create a subscription and neither of
which allows you to do anything other than create a subscription is
intrinsically confusing. I'm not willing to commit a patch that works
like that, and I will object if someone else wants to do so.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-23 Thread Jeff Davis
On Thu, 2023-03-23 at 11:52 -0400, Robert Haas wrote:
> What would this amount to concretely? Also adding a
> pg_connection_string predefined role and requiring both that and
> pg_create_subscription [to CREATE SUBSCRIPTION]

Yes.

> If so, I don't think that's a good idea. Maybe for some reason your
> proposed changes won't end up happening, and then we've just got a
> useless extra thing that makes things confusing.

Even if my changes don't happen, I would find it less confusing and
more likely that users understand what they're doing.

To most users, the consequences of allowing users to write connection
strings on the server are far from obvious. Even we, as developers,
needed to spend a lot of time discussing the nuances.

Someone merely granting the ability to CREATE SUBSCRIPTION would read
that page in the docs, which is dominated by the mechanics of a
subscription and says little about the connection string, let alone the
security nuances of using it on a server.

But if there is also a separate connection string privilege required,
we can document it better and they are more likely to find it and
understand.

Beyond that, the connection string and the mechanics of the
subscription are really different concepts.

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-03-23 Thread Robert Haas
On Wed, Mar 22, 2023 at 3:53 PM Jeff Davis  wrote:
> Is there any chance I can convince you to separate the privileges of
> using a connection string and creating a subscription, as I
> suggested[1] earlier?

What would this amount to concretely? Also adding a
pg_connection_string predefined role and requiring both that and
pg_create_subscription in all cases until your proposed changes get
made?

If so, I don't think that's a good idea. Maybe for some reason your
proposed changes won't end up happening, and then we've just got a
useless extra thing that makes things confusing. I think that adding a
pg_connection_string privilege properly belongs to whatever patch
makes it possible to separate the connection string from the
subscription, and that we probably shouldn't add those even in
separate commits, let alone in separate major releases.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-22 Thread Jeff Davis
On Wed, 2023-03-22 at 12:16 -0400, Robert Haas wrote:
> If nobody's too unhappy with the idea, I plan to commit this soon,
> both because I think that the feature is useful, and also because I
> think it's an important security improvement.

Is there any chance I can convince you to separate the privileges of
using a connection string and creating a subscription, as I
suggested[1] earlier?

It would be useful for dblink, and I also plan to propose CREATE
SUBSCRIPTION ... SERVER for v17 (it was too late for 16), for which it
would also be useful to make the distinction.

You seemed to generally think it was a reasonable idea, but wanted to
wait for the other patch. I think it's the right breakdown of
privileges even now, and I don't see a reason to give ourselves a
headache later trying to split up the privileges later.

Regards,
Jeff Davis

[1]
https://www.postgresql.org/message-id/fa1190c117c2455f2dd968a1a09f796ccef27b29.ca...@j-davis.com




Re: Non-superuser subscription owners

2023-03-22 Thread Robert Haas
On Wed, Mar 8, 2023 at 2:47 PM Andres Freund  wrote:
> Hm - it still feels wrong that we error out in case of failure, despite the
> comment to the function saying:
>  * Returns NULL on error and fills the err with palloc'ed error message.

I've amended the comment so that it explains why it's done that way.

> Other than this, the change looks ready to me.

Well, it still needed documentation changes and pg_dump changes. I've
added those in the attached version.

If nobody's too unhappy with the idea, I plan to commit this soon,
both because I think that the feature is useful, and also because I
think it's an important security improvement. Since replication is
currently run as the subscription owner, any table owner can
compromise the subscription owner's account, which is really bad, but
if the subscription owner can be a non-superuser, it's a little bit
less bad. From a security point of view, I think the right thing to do
and what would improve security a lot more is to run replication as
the table owner rather than the subscription owner. I've posted a
patch for that at
http://postgr.es/m/CA+TgmoaSCkg9ww9oppPqqs+9RVqCexYCE6Aq=usypfnoode...@mail.gmail.com
and AFAICT everyone agrees with the idea, even if the patch itself
hasn't yet attracted any code reviews. But although the two patches
are fairly closely related, this seems to be a good idea whether that
moves forward or not, and that seems to be a good idea whether this
moves forward or not. As this one has had more review and discussion,
my current thought is to try to get this one committed first.

-- 
Robert Haas
EDB: http://www.enterprisedb.com


v5-0001-Add-new-predefined-role-pg_create_subscriptions.patch
Description: Binary data


Re: Non-superuser subscription owners

2023-03-08 Thread Andres Freund
Hi,

On 2023-02-07 16:56:55 -0500, Robert Haas wrote:
> On Wed, Feb 1, 2023 at 4:02 PM Andres Freund  wrote:
> > > + /* Is the use of a password mandatory? */
> > > + must_use_password = MySubscription->passwordrequired &&
> > > + !superuser_arg(MySubscription->owner);
> >
> > There's a few repetitions of this - perhaps worth putting into a helper?
> 
> I don't think so. It's slightly different each time, because it's
> pulling data out of different data structures.
> 
> > This still leaks the connection on error, no?
> 
> I've attempted to fix this in v4, attached.

Hm - it still feels wrong that we error out in case of failure, despite the
comment to the function saying:
 * Returns NULL on error and fills the err with palloc'ed error message.

Other than this, the change looks ready to me.

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-03-03 Thread Robert Haas
On Wed, Mar 1, 2023 at 7:34 PM Andres Freund  wrote:
> ISTM that this would require annotating most functions in the system. There's
> many problems besides accessing database contents. Just a few examples:
>
> - dblink functions to access another system / looping back
> - pg_read_file()/pg_file_write() allows almost arbitrary mischief
> - pg_stat_reset[_shared]()
> - creating/dropping logical replication slots
> - use untrusted PL functions
> - many more
>
> A single wrongly annotated function would be sufficient to escape. This
> includes user defined functions.
>
> This basically proposes that we can implement a safe sandbox for executing
> arbitrary code in a privileged context. IMO history suggests that that's a
> hard thing to do.

Yeah, that's true, but I don't think switching users all the time is
going to be great either. And it's not like other people haven't gone
this way: that's what plperl (not plperlu) is all about, and
JavaScript running in your browser, and so on. Those things aren't
problem-free, of course, but we're all using them.

When I was initially thinking about this, I thought that maybe we
could just block access to tables and utility statements. That's got
problems in both directions. On the one hand, there are functions like
the ones you propose here that have side effects which we might not
want to allow, and on the other hand, somebody might have an index
expression that does a lookup in a table that they "never change". The
latter case is problematic for non-security reasons, because there's
an invisible dump-ordering constraint that must be obeyed for
dump/restore to work at all, but there's no security issue. Still, I'm
not sure this idea is completely dead in the water. It doesn't seem
unreasonable to me that if you have that kind of case, you have to
somehow opt into the behavior: yeah, I know that index functions I'm
executing are going to read from tables, and I consent to that. And
similarly, if your index expression calls pg_stat_reset_shared(), that
probably ought to be blocked by default too, and if you want to allow
it, you have to say so. Yes, that does require labelling functions, or
maybe putting run-time checks in them:

RequireAvailableCapability(CAP_MODIFY_DATABASE_STATE);

If that capability isn't available in the present context, the call
errors out. That way, it's possible for the required capabilities to
depend on the arguments to the function, and we can change markings in
minor releases without needing catalog changes.

There's another way of thinking about this problem, which involves
supposing that the invoker should only be induced to do things that
the definer could also have done. Basically do every privilege check
twice, and require that both pass. The problem I have with that is
that there are various operations which depend on your identity, not
just your privileges. For instance, a GRANT statement records a
grantor, and a REVOKE statement infers a grantor whose grant is to be
revoked. The operation isn't just allowed or disallowed based on who
performed it -- it actually does something different depending on who
performs it. I believe we have a number of cases like that, and I
think that they suggest that that whole model is pretty flawed. Even
if that were no issue, this also seems extremely complex to implement,
because we have an absolute crap-ton of places that perform privilege
checks and getting all of those places to check privileges as a second
user seems nightmarish. I also think that it might be lead to
confusing error messages: alice tried to do X but we're not allowing
it because bob isn't allowed to do X. Eh, what? As opposed to the
sandboxing approach, where I think you get something more like:

ERROR: database state cannot be modified now
DETAIL: The database system is evaluating an index expression.
HINT: Do $SOMETHING to allow this.

I don't want to press too hard on my idea here. I'm sure it has a
bunch of problems apart from those already mentioned, and those
already mentioned are not trivial. However, I do think there might be
ways to make it work, and I'm not at all convinced that trying to
switch users all over the place is going to be be better, either for
security or usability. Is there some other whole kind of approach we
can take here that we haven't discussed yet?

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-01 Thread Andres Freund
Hi,

On 2023-02-28 08:37:02 -0500, Robert Haas wrote:
> On Mon, Feb 27, 2023 at 7:37 PM Jeff Davis  wrote:
> > > Yeah. That's the idea I was floating, at least.
> >
> > Isn't that a hard problem; maybe impossible?
>
> It doesn't seem that hard to me; maybe I'm missing something.
>
> The existing SECURITY_RESTRICTED_OPERATION flag basically prevents you
> from tinkering with the session state. If we also had a similar flags
> like DATABASE_READS_PROHIBITED and DATABASE_WRITES_PROHIBITED (or just
> a combined DATABASE_ACCESS_PROHIBITED flag) I think that would be
> pretty close to what we need. The idea would be that, when a user
> executes a function or procedure owned by a user that they don't trust
> completely, we'd set
> SECURITY_RESTRICTED_OPERATION|DATABASE_READS_PROHIBITED|DATABASE_WRITES_PROHIBITED.
> And we could provide a user with a way to express the degree of trust
> they have in some other user or perhaps even some specific function,
> e.g.

ISTM that this would require annotating most functions in the system. There's
many problems besides accessing database contents. Just a few examples:

- dblink functions to access another system / looping back
- pg_read_file()/pg_file_write() allows almost arbitrary mischief
- pg_stat_reset[_shared]()
- creating/dropping logical replication slots
- use untrusted PL functions
- many more

A single wrongly annotated function would be sufficient to escape. This
includes user defined functions.


This basically proposes that we can implement a safe sandbox for executing
arbitrary code in a privileged context. IMO history suggests that that's a
hard thing to do.

Am I missing something?

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-03-01 Thread Andres Freund
Hi,

On 2023-02-28 12:36:38 -0800, Jeff Davis wrote:
> On Tue, 2023-02-28 at 11:28 -0800, Andres Freund wrote:
> > I can only repeat myself in stating that SECURITY DEFINER solves none
> > of the
> > relevant issues. I included several examples of why it doesn't in the
> > recent
> > thread about "blocking SECURITY INVOKER". E.g. that default arguments
> > of
> > SECDEF functions are evaluated with the current user's privileges,
> > not the
> > function owner's privs:
> > 
> > https://postgr.es/m/20230113032943.iyxdu7bnxe4cmbld%40awork3.anarazel.de
> 
> I was speaking a bit loosely, using "SECURITY DEFINER" to mean the
> semantics of executing code as the one who wrote it. I didn't
> specifically mean the function marker, because as you pointed out in
> the other thread, that's not enough.

Oh, ok.


> From your email it looks like there is still a path forward:
> 
> "The proposal to not trust any expressions controlled by untrusted
> users at least allows to prevent execution of code, even if it doesn't
> provide a way to execute the code in a safe manner.  Given that we
> don't have the former, it seems foolish to shoot for the latter."
> 
> And later:
> 
> "I think the combination of
> a) a setting that restricts evaluation of any non-trusted expressions,
>independent of the origin
> b) an easy way to execute arbitrary statements within
>SECURITY_RESTRICTED_OPERATION"
> 
> My takeaway from that thread was that we need a mechanism to deal with
> non-function code (e.g. default expressions) first; but once we have
> that, it opens up the design space to better solutions or at least
> mitigations. Is that right?

I doubt it's realistic to change the user for all kinds of expressions
individually. A query can involve expressions controlled by many users,
changing the current user in a super granular way seems undesirable from a
performance and complexity pov.

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-03-01 Thread Jeff Davis
On Wed, 2023-03-01 at 16:06 -0500, Robert Haas wrote:

> To be fair, it's possible that there's no solution to this class of
> problems that *doesn't* suck, but I think we should look a lot harder
> before coming to that conclusion.

Fair enough. The situation is bad enough that I'm willing to consider a
pretty wide range of solutions and mitigations that might otherwise be
unappealing.

I think there might be something promising in your idea to highly
restrict the privileges of code attached to a table. A lot of
expressions are really simple and don't need much to be both useful and
safe. We may not need the exact same solution for both default
expressions and triggers. Some details to work through, though.

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-03-01 Thread Robert Haas
On Wed, Mar 1, 2023 at 1:13 PM Jeff Davis  wrote:
> I don't think it's magic, as I said above. But I assume that your more
> general point is that if we take some responsibility away from the
> invoker and place it on the definer, then it creates room for new kinds
> of problems. And I agree.
>
> The point of moving responsibility to the definer is that the definer
> can actually do something to protect themselves (nail down search_path,
> restrict USAGE privs, and avoid dynamic SQL); whereas the invoker is
> nearly helpless.

I think there's some truth to that allegation, but I think it largely
comes from the fact that we've given very little thought or attention
to this problem. We have a section in the documentation on writing
SECURITY DEFINER functions safely because we've known for a long time
that it's dangerous and we've provided some (imperfect) tools for
dealing with it, like allowing a SET search_path clause to be attached
to a function definition. We have no comparable documentation section
about SECURITY INVOKER because we haven't historically taken that
seriously as a security hazard and we have no tools to make it safe.
But we could, as with what I'm proposing here, or the user/function
trust mechanism previously proposed by Noah, or various other ideas
that we might have.

I don't like the idea of saying that we're not going to try to invent
anything new and just push people into using the stuff we already
have. The stuff we have for security SECURITY DEFINER functions is not
very good. True, it's better than what we have for protecting against
the risks inherent in SECURITY INVOKER, but that's not saying much:
anything at all is better than nothing. But it's easy to forget a SET
search_path clause on one of your functions, or to include something
in that search path that's not actually safe, or to have a problem
that isn't blocked by just setting search_path. Also, not that it's
the most important consideration here, but putting a SET clause on
your functions is really kind of expensive if what the function does
is trivial, which if you're using it in an index expression or a
default expression, will often be the case. I don't want to pretend
like I have all the answers here, but I find it really hard to believe
that pushing people to do the same kind of nonsense that's currently
required when writing a SECURITY DEFINER function for a lot of their
other functions as well is going to be a win. I think it will probably
suck.

To be fair, it's possible that there's no solution to this class of
problems that *doesn't* suck, but I think we should look a lot harder
before coming to that conclusion. I've come to agree with your
contention that we're not taking the hazards of SECURITY INVOKER
nearly seriously enough, but I think you're underestimating the
hazards that SECURITY DEFINER poses, and overestimating how easy it is
to avoid them.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-01 Thread Jeff Davis
On Wed, 2023-03-01 at 10:05 -0500, Robert Haas wrote:
> For this reason, these expressions are, by
> default, restricted from doing .

The hard part is defining  without resorting to a bunch of
special cases, and also in a way that doesn't break a bunch of stuff.

> You earlier
> mentioned that switching to the table owner seems to be just a way of
> turning SECURITY INVOKER into SECURITY DEFINER in random places, or
> maybe that's not exactly what you said but that's what I took from
> it.

Yeah, though I glossed over some details, see below.

>  If we just slather user context switches
> everywhere, I'm not actually very sure that's going to be
> comprehensible behavior: if my trigger function is SECURITY INVOKER,
> why is it getting executed as me, not the inserting user?

Let's consider other expressions first. The proposal is that all
expressions attached to a table should run as the table owner (set
aside compatibility concerns for a moment). If those expressions call a
SECURITY INVOKER function, the invoker would need to be the table owner
as well. Users could get confused by that, but I think it's
documentable and understandable; and it's really the only thing that
makes sense -- otherwise changing the user is completely useless.

We should consider triggers as just another expression being executed,
and the invoker is the table owner. The problem is that it's a little
annoying to users because they probably defined the function for the
sole purpose of being a trigger function for a single table, and it
might look as though the SECURITY INVOKER label was ignored.

But there is a difference, which I glossed over before: SECURITY
INVOKER on a trigger function would still have significance, because
the function owner (definer) and table owner (invoker) could still be
different in the case of a trigger, just like in an expression.

This goes back to my point that SECURITY INVOKER is more complex for us
to document and for users to understand. The user *must* understand who
the invoker is in various contexts. That's the situation today and
there's no escaping it. We aren't making things any worse, at least as
long as we can sort out compatibility in a reasonable way.

(Aside: I'm having some serious concerns about how the invoker of a
function called in a view is not the view definer. That's another thing
we'll need to fix, because it's another way of putting SECURITY INVOKER
code in front of someone without them knowing.)

(Aside: We should take a second look at the security invoker views
before we release them. I know that I learned some things during this
discussion and a fresh look might be useful.)

> As soon as you magically turn
> that into a SECURITY DEFINER function, you've provided a way for the
> users performing DML to attack the table owner.

I don't think it's magic, as I said above. But I assume that your more
general point is that if we take some responsibility away from the
invoker and place it on the definer, then it creates room for new kinds
of problems. And I agree.

The point of moving responsibility to the definer is that the definer
can actually do something to protect themselves (nail down search_path,
restrict USAGE privs, and avoid dynamic SQL); whereas the invoker is
nearly helpless.

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-03-01 Thread Robert Haas
On Wed, Mar 1, 2023 at 10:48 AM Stephen Frost  wrote:
> > Yeah, or any other expressions. Basically impose restrictions when the
> > user running the code is not the same as the user who provided the
> > code.
>
> Would this have carve-outs for things like "except if the user providing
> the code is trusted/superuser"?  Seems like that would be necessary for
> the function to be able to do more-or-less anything, but then I worry
> that there's superuser-owned code which could leak information or be
> used by a malicious owner as that code would still be running as the
> invoking user..  Perhaps we could say that the function also has to be
> leakproof, but that isn't quite the same issue and therefore it seems
> like we'd need to decorate all of the functions with another flag that's
> allowed to be run in this manner.

Yes, I think there can be carve-outs based on the relationship of the
users involved -- if the user who provided the code is the superuser
or some other user who can anyway run whatever they want as the user
performing the operation, then there's no point in imposing any
restrictions -- and I think there can also be some way of setting
policy. I proposed a GUC in an earlier email, and you proposed one
with somewhat different semantics in this email, and I'm not sure that
either of those things in particular is right or that we ought to be
using a GUC for this at all. However, there should almost certainly be
SOME way for the superuser to turn any new restrictions off, and there
should probably also be some way for an unprivileged user to say "you
know, I am totally OK with running any code that alice provides --
just go with it."

I don't think we're at a point where we can conclude on what those
mechanisms should look like just yet, but I think that everyone who
has spoken up agrees that they ought to exist, assuming we go in this
direction at all.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-03-01 Thread Stephen Frost
Greetings,

* Robert Haas (robertmh...@gmail.com) wrote:
> On Tue, Feb 28, 2023 at 4:01 PM Jeff Davis  wrote:
> > Or default expressions, I presume. If we at least agree on this point,
> > then I think we should try to find a way to treat these other hunks of
> > code in a secure way (which I think is what Andres was suggesting).
> 
> Yeah, or any other expressions. Basically impose restrictions when the
> user running the code is not the same as the user who provided the
> code.

Would this have carve-outs for things like "except if the user providing
the code is trusted/superuser"?  Seems like that would be necessary for
the function to be able to do more-or-less anything, but then I worry
that there's superuser-owned code which could leak information or be
used by a malicious owner as that code would still be running as the
invoking user..  Perhaps we could say that the function also has to be
leakproof, but that isn't quite the same issue and therefore it seems
like we'd need to decorate all of the functions with another flag that's
allowed to be run in this manner.

Random thought- what if the function has a NOTIFY in it with a payload
of some kind of sensitive information?

> > Unless the trusted roles defaults to '*', then I think it will still
> > break some things.
> 
> Definitely. IMHO, it's OK to break some things, certainly in a major
> release and maybe even in a minor release. But we don't want to break
> more things that we really need to break. And as you say, we want the
> restrictions to be comprehensible.

Really hard to say if whatever this is is OK for back-patching and
breaking minor releases without knowing exactly what is getting broken
... but it'd have to be a very clear edge case of what gets broken for
it to be sensible for breaking in a minor release without a very clear
vulnerability or such that's being fixed with a simple work-around.
Just making all auditing triggers break in a minor release certainly
wouldn't be acceptable, as an example that I imagine we all agree with.

> > Each of these ideas and sub-ideas affect the semantics, and should be
> > documented. But how do we document that some code runs as you, some as
> > the person who wrote it, sometimes we obey SECURITY INVOKER and
> > sometimes we ignore it and use DEFINER semantics, some code is outside
> > a function and always executes as the invoker, some code has some
> > security flags, and some code has more security flags, code can change
> > between the time you look at it and the time it runs, and it's all
> > filtered through GUCs with their own privilege sub-language?
> >
> > OK, let's assume that we have all of that documented, then how do we
> > guide users on what reasonable best practices are for the GUC settings,
> > etc.? Or do we just say "this is mechanically how all these parts work,
> > good luck assembling it into a secure system!". [ Note: I feel like
> > this is the state we are in now. Even if technically we don't have live
> > security bugs that I'm aware of, we are setting users up for security
> > problems. ]
> >
> > On the other hand, if we focus on executing code as the user who wrote
> > it in most places, then the documentation will be something like: "you
> > defined the table, you wrote the code, it runs as you, here are some
> > best practices for writing secure code". And we have some different
> > documentation for writing a cool SECURITY INVOKER function and how to
> > get other users to trust you enough to run it. That sounds a LOT more
> > understandable for users.
> 
> What I was imagining is that we would document something like: A table
> can have executable code associated with it in a variety of ways. For
> example, it can have triggers, default expressions, check constraints,
> or row-level security filters. In most cases, these expressions are
> executed with the privileges of the user performing the operation on
> the table, except when SECURITY DEFINER functions are used. Because
> these expressions are set by the table owner and executed by the users
> accessing the table, there is a risk that the table owner could
> include malicious code that usurps the privileges of the user
> accessing the table. For this reason, these expressions are, by
> default, restricted from doing . If you want to allow those
> operations, you can .

Well, one possible answer to 'something' might be 'use SECURITY DEFINER
functions which are owned by a role allowed to do '.  Note that
that doesn't have to be the table owner though, it could be a much more
constrained role.  That approach would allow us to leverage the existing
GRANT/RLS/et al system for what's allowed and avoid having to create new
things like a complex permission system inside of a GUC for users to
have to understand.

> I agree that running code as the table owner is helpful in a bunch of
> scenarios, but I also don't think it fixes everything. You earlier
> mentioned that switching to the table owner seems to be just a 

Re: Non-superuser subscription owners

2023-03-01 Thread Robert Haas
On Tue, Feb 28, 2023 at 4:01 PM Jeff Davis  wrote:
> You're suggesting using the SECURITY_RESTRICTED_OPERATION flag, along
> with the new security flags, but not switch to the table owner, right?

Correct.

> Or default expressions, I presume. If we at least agree on this point,
> then I think we should try to find a way to treat these other hunks of
> code in a secure way (which I think is what Andres was suggesting).

Yeah, or any other expressions. Basically impose restrictions when the
user running the code is not the same as the user who provided the
code.

> It seems like you're saying to basically just keep the user ID the
> same, and maybe keep USAGE privileges, but not be able to do anything
> else? Might be useful. Kind of like running it as a nobody user but
> without the problems you mentioned. Some details to think about, I'm
> sure.

Yep.

> I'm not very excited about inventing a new privilege language inside a
> GUC, but perhaps a simpler form could be a reasonable mitigation (or at
> least a starting place).

I'm not very sure about this part, either. I think we need some way of
shutting off whatever new controls we impose, but the shape of it is
unclear to me and I think there are a bunch of problems.

> Unless the trusted roles defaults to '*', then I think it will still
> break some things.

Definitely. IMHO, it's OK to break some things, certainly in a major
release and maybe even in a minor release. But we don't want to break
more things that we really need to break. And as you say, we want the
restrictions to be comprehensible.

> Each of these ideas and sub-ideas affect the semantics, and should be
> documented. But how do we document that some code runs as you, some as
> the person who wrote it, sometimes we obey SECURITY INVOKER and
> sometimes we ignore it and use DEFINER semantics, some code is outside
> a function and always executes as the invoker, some code has some
> security flags, and some code has more security flags, code can change
> between the time you look at it and the time it runs, and it's all
> filtered through GUCs with their own privilege sub-language?
>
> OK, let's assume that we have all of that documented, then how do we
> guide users on what reasonable best practices are for the GUC settings,
> etc.? Or do we just say "this is mechanically how all these parts work,
> good luck assembling it into a secure system!". [ Note: I feel like
> this is the state we are in now. Even if technically we don't have live
> security bugs that I'm aware of, we are setting users up for security
> problems. ]
>
> On the other hand, if we focus on executing code as the user who wrote
> it in most places, then the documentation will be something like: "you
> defined the table, you wrote the code, it runs as you, here are some
> best practices for writing secure code". And we have some different
> documentation for writing a cool SECURITY INVOKER function and how to
> get other users to trust you enough to run it. That sounds a LOT more
> understandable for users.

What I was imagining is that we would document something like: A table
can have executable code associated with it in a variety of ways. For
example, it can have triggers, default expressions, check constraints,
or row-level security filters. In most cases, these expressions are
executed with the privileges of the user performing the operation on
the table, except when SECURITY DEFINER functions are used. Because
these expressions are set by the table owner and executed by the users
accessing the table, there is a risk that the table owner could
include malicious code that usurps the privileges of the user
accessing the table. For this reason, these expressions are, by
default, restricted from doing . If you want to allow those
operations, you can .

I agree that running code as the table owner is helpful in a bunch of
scenarios, but I also don't think it fixes everything. You earlier
mentioned that switching to the table owner seems to be just a way of
turning SECURITY INVOKER into SECURITY DEFINER in random places, or
maybe that's not exactly what you said but that's what I took from it.
And I think that's right. If we just slather user context switches
everywhere, I'm not actually very sure that's going to be
comprehensible behavior: if my trigger function is SECURITY INVOKER,
why is it getting executed as me, not the inserting user? I also think
there are plenty of cases where that could just replace the current
set of security problems with a new set of security problems. If the
trigger function is SECURITY INVOKER, then the user who wrote it
doesn't have to worry about securing it against attacks by users
accessing the table; it's just running with the permissions of the
user performing the DML. Maybe there are correctness issues if you
don't lock down search_path etc., but there's no security compromise
because there's no user ID switching. As soon as you magically turn
that into a SECURITY DEFINER function, 

Re: Non-superuser subscription owners

2023-02-28 Thread Stephen Frost
Greetings,

* Jeff Davis (pg...@j-davis.com) wrote:
> On Tue, 2023-02-28 at 08:37 -0500, Robert Haas wrote:
> > The existing SECURITY_RESTRICTED_OPERATION flag basically prevents
> > you
> > from tinkering with the session state.
> 
> Currently, every time we set that flag we also run all the code as the
> table owner.
> 
> You're suggesting using the SECURITY_RESTRICTED_OPERATION flag, along
> with the new security flags, but not switch to the table owner, right?

I'm having trouble following this too, I have to admit.  If we aren't
changing who we're running the code under.. but making it so that the
code isn't actually able to do anything then that doesn't strike me as
likely to actually be useful?  Surely things like triggers which are
used to update another table or insert into another table what happened
on the table with the trigger need to be allowed to modify the database-
how do we make that possible while the code runs as the invoker and not
the table owner when the table owner is the one who gets to write the
code?

> >  If we also had a similar flags
> > like DATABASE_READS_PROHIBITED and DATABASE_WRITES_PROHIBITED (or
> > just
> > a combined DATABASE_ACCESS_PROHIBITED flag) I think that would be
> > pretty close to what we need. The idea would be that, when a user
> > executes a function or procedure 
> 
> Or default expressions, I presume. If we at least agree on this point,
> then I think we should try to find a way to treat these other hunks of
> code in a secure way (which I think is what Andres was suggesting).

Would need to apply to functions in views and functions in RLS too,
along wth default expressions and everything else that could be defined
by one person and run by another.

> > owned by a user that they don't trust
> > completely, we'd set
> > SECURITY_RESTRICTED_OPERATION|DATABASE_READS_PROHIBITED|DATABASE_WRIT
> > ES_PROHIBITED.
> 
> It seems like you're saying to basically just keep the user ID the
> same, and maybe keep USAGE privileges, but not be able to do anything
> else? Might be useful. Kind of like running it as a nobody user but
> without the problems you mentioned. Some details to think about, I'm
> sure.

While there's certainly some use-cases where a completely unprivileged
user would work, there's certainly an awful lot where it wouldn't.
Having that as an option might be interesting for those much more
limited use-cases and maybe you could even say "only run functions which
are owned by a superuser or X roles" but it's certainly not a general
solution to the problem.

> > And we could provide a user with a way to express the degree of trust
> > they have in some other user or perhaps even some specific function,
> > e.g.
> > 
> > SET trusted_roles='alice:read';
> > 
> > ...could mean that I trust alice to read from the database with my
> > permissions, should I happen to run code provided by her in SECURITY
> > INVOKER modacke.
> 
> I'm not very excited about inventing a new privilege language inside a
> GUC, but perhaps a simpler form could be a reasonable mitigation (or at
> least a starting place).

I'm pretty far down the path of "wow that looks really difficult to work
with", to put it nicely.

> > I'm sure there's some details to sort out here, e.g. around security
> > related to the trusted_roles GUC itself. But I don't really see a
> > fundamental problem. We can invent arbitrary flags that prohibit
> > classes of operations that are of concern, set them by default in
> > cases where concern is justified, and then give users who want the
> > current behavior some kind of escape hatch that causes those flags to
> > not get set after all. Not only does such a solution not seem
> > impossible, I can possibly even imagine back-patching it, depending
> > on
> > exactly what the shape of the final solution is, how important we
> > think it is to get a fix out there, and how brave I'm feeling that
> > day.
> 
> Unless the trusted roles defaults to '*', then I think it will still
> break some things.

Defaulting to an option that is "don't break anything" while giving
users flexibility to test out other, more secure, options seems like it
would be a pretty reasonable way forward, generally.  That said.. I
don't really think this particular approach ends up being a good
direction to go in...

> One of my key tests for user-facing proposals is whether the
> documentation will be reasonable or not. Most of these proposals to
> make SECURITY INVOKER less bad fail that test.

and this is certainly a very good point as to why.

Thanks,

Stephen


signature.asc
Description: PGP signature


Re: Non-superuser subscription owners

2023-02-28 Thread Jeff Davis
On Tue, 2023-02-28 at 08:37 -0500, Robert Haas wrote:
> The existing SECURITY_RESTRICTED_OPERATION flag basically prevents
> you
> from tinkering with the session state.

Currently, every time we set that flag we also run all the code as the
table owner.

You're suggesting using the SECURITY_RESTRICTED_OPERATION flag, along
with the new security flags, but not switch to the table owner, right?

>  If we also had a similar flags
> like DATABASE_READS_PROHIBITED and DATABASE_WRITES_PROHIBITED (or
> just
> a combined DATABASE_ACCESS_PROHIBITED flag) I think that would be
> pretty close to what we need. The idea would be that, when a user
> executes a function or procedure 

Or default expressions, I presume. If we at least agree on this point,
then I think we should try to find a way to treat these other hunks of
code in a secure way (which I think is what Andres was suggesting).

> owned by a user that they don't trust
> completely, we'd set
> SECURITY_RESTRICTED_OPERATION|DATABASE_READS_PROHIBITED|DATABASE_WRIT
> ES_PROHIBITED.

It seems like you're saying to basically just keep the user ID the
same, and maybe keep USAGE privileges, but not be able to do anything
else? Might be useful. Kind of like running it as a nobody user but
without the problems you mentioned. Some details to think about, I'm
sure.

> And we could provide a user with a way to express the degree of trust
> they have in some other user or perhaps even some specific function,
> e.g.
> 
> SET trusted_roles='alice:read';
> 
> ...could mean that I trust alice to read from the database with my
> permissions, should I happen to run code provided by her in SECURITY
> INVOKER modacke.

I'm not very excited about inventing a new privilege language inside a
GUC, but perhaps a simpler form could be a reasonable mitigation (or at
least a starting place).

> I'm sure there's some details to sort out here, e.g. around security
> related to the trusted_roles GUC itself. But I don't really see a
> fundamental problem. We can invent arbitrary flags that prohibit
> classes of operations that are of concern, set them by default in
> cases where concern is justified, and then give users who want the
> current behavior some kind of escape hatch that causes those flags to
> not get set after all. Not only does such a solution not seem
> impossible, I can possibly even imagine back-patching it, depending
> on
> exactly what the shape of the final solution is, how important we
> think it is to get a fix out there, and how brave I'm feeling that
> day.

Unless the trusted roles defaults to '*', then I think it will still
break some things.


One of my key tests for user-facing proposals is whether the
documentation will be reasonable or not. Most of these proposals to
make SECURITY INVOKER less bad fail that test.

Each of these ideas and sub-ideas affect the semantics, and should be
documented. But how do we document that some code runs as you, some as
the person who wrote it, sometimes we obey SECURITY INVOKER and
sometimes we ignore it and use DEFINER semantics, some code is outside
a function and always executes as the invoker, some code has some
security flags, and some code has more security flags, code can change
between the time you look at it and the time it runs, and it's all
filtered through GUCs with their own privilege sub-language?

OK, let's assume that we have all of that documented, then how do we
guide users on what reasonable best practices are for the GUC settings,
etc.? Or do we just say "this is mechanically how all these parts work,
good luck assembling it into a secure system!". [ Note: I feel like
this is the state we are in now. Even if technically we don't have live
security bugs that I'm aware of, we are setting users up for security
problems. ]

On the other hand, if we focus on executing code as the user who wrote
it in most places, then the documentation will be something like: "you
defined the table, you wrote the code, it runs as you, here are some
best practices for writing secure code". And we have some different
documentation for writing a cool SECURITY INVOKER function and how to
get other users to trust you enough to run it. That sounds a LOT more
understandable for users.

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-02-28 Thread Jeff Davis
On Tue, 2023-02-28 at 11:28 -0800, Andres Freund wrote:
> I can only repeat myself in stating that SECURITY DEFINER solves none
> of the
> relevant issues. I included several examples of why it doesn't in the
> recent
> thread about "blocking SECURITY INVOKER". E.g. that default arguments
> of
> SECDEF functions are evaluated with the current user's privileges,
> not the
> function owner's privs:
> 
> https://postgr.es/m/20230113032943.iyxdu7bnxe4cmbld%40awork3.anarazel.de

I was speaking a bit loosely, using "SECURITY DEFINER" to mean the
semantics of executing code as the one who wrote it. I didn't
specifically mean the function marker, because as you pointed out in
the other thread, that's not enough.

>From your email it looks like there is still a path forward:

"The proposal to not trust any expressions controlled by untrusted
users at least allows to prevent execution of code, even if it doesn't
provide a way to execute the code in a safe manner.  Given that we
don't have the former, it seems foolish to shoot for the latter."

And later:

"I think the combination of
a) a setting that restricts evaluation of any non-trusted expressions,
   independent of the origin
b) an easy way to execute arbitrary statements within
   SECURITY_RESTRICTED_OPERATION"

My takeaway from that thread was that we need a mechanism to deal with
non-function code (e.g. default expressions) first; but once we have
that, it opens up the design space to better solutions or at least
mitigations. Is that right?

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-02-28 Thread Andres Freund
Hi,

On 2023-02-22 09:18:34 -0800, Jeff Davis wrote:
> I can't resist mentioning that these are all SECURITY INVOKER problems.
> SECURITY INVOKER is insecure unless the invoker absolutely trusts the
> definer, and that only really makes sense if the definer is a superuser
> (or something very close). That's why we keep adding exceptions with
> SECURITY_RESTRICTED_OPERATION, which is really just a way to silently
> ignore the SECURITY INVOKER label and use SECURITY DEFINER instead.
> 
> At some point we need to ask: "when is SECURITY INVOKER both safe and
> useful?" and contain it to those cases, rather than silently ignoring
> it in an expanding list of cases.

I can only repeat myself in stating that SECURITY DEFINER solves none of the
relevant issues. I included several examples of why it doesn't in the recent
thread about "blocking SECURITY INVOKER". E.g. that default arguments of
SECDEF functions are evaluated with the current user's privileges, not the
function owner's privs:

https://postgr.es/m/20230113032943.iyxdu7bnxe4cmbld%40awork3.anarazel.de

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-02-28 Thread Robert Haas
On Mon, Feb 27, 2023 at 7:37 PM Jeff Davis  wrote:
> > Yeah. That's the idea I was floating, at least.
>
> Isn't that a hard problem; maybe impossible?

It doesn't seem that hard to me; maybe I'm missing something.

The existing SECURITY_RESTRICTED_OPERATION flag basically prevents you
from tinkering with the session state. If we also had a similar flags
like DATABASE_READS_PROHIBITED and DATABASE_WRITES_PROHIBITED (or just
a combined DATABASE_ACCESS_PROHIBITED flag) I think that would be
pretty close to what we need. The idea would be that, when a user
executes a function or procedure owned by a user that they don't trust
completely, we'd set
SECURITY_RESTRICTED_OPERATION|DATABASE_READS_PROHIBITED|DATABASE_WRITES_PROHIBITED.
And we could provide a user with a way to express the degree of trust
they have in some other user or perhaps even some specific function,
e.g.

SET trusted_roles='alice:read';

...could mean that I trust alice to read from the database with my
permissions, should I happen to run code provided by her in SECURITY
INVOKER modacke.

I'm sure there's some details to sort out here, e.g. around security
related to the trusted_roles GUC itself. But I don't really see a
fundamental problem. We can invent arbitrary flags that prohibit
classes of operations that are of concern, set them by default in
cases where concern is justified, and then give users who want the
current behavior some kind of escape hatch that causes those flags to
not get set after all. Not only does such a solution not seem
impossible, I can possibly even imagine back-patching it, depending on
exactly what the shape of the final solution is, how important we
think it is to get a fix out there, and how brave I'm feeling that
day.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-02-27 Thread Stephen Frost
Greetings,

* Jeff Davis (pg...@j-davis.com) wrote:
> Not all steps would be breaking changes, and a lot of those steps are
> things we should do anyway. We could make it easier to write safe
> SECURITY DEFINER functions, provide more tools for users to opt-out of
> executing SECURITY INVOKER code, provide a way for superusers to safely
> drop privileges, document the problems with security invoker and what
> to do about them, etc.

Agreed.

> But we also shouldn't exaggerate it -- for instance, others have
> proposed that we run code as the table owner for logical subscriptions,
> and that's going to break things in the same way. Arguably, if we are
> going to break something, it's better to break it consistently rather
> than one subsystem at a time.

I tend to agree with this.

> Back to the $SUBJECT, if we allow non-superusers to run subscriptions,
> and the subscription runs the code as the table owner, that might also
> lead to some weird behavior for triggers that rely on SECURITY INVOKER
> semantics.

Indeed.

Thanks,

Stephen


signature.asc
Description: PGP signature


Re: Non-superuser subscription owners

2023-02-27 Thread Stephen Frost
Greetings,

* Jeff Davis (pg...@j-davis.com) wrote:
> On Mon, 2023-02-27 at 14:10 -0500, Stephen Frost wrote:
> > I do think there are some use-cases for it, but agree that it'd be
> > better to encourage more use of SECURITY DEFINER and one approach to
> > that might be to have a way for users to explicitly say "don't run
> > code
> > that isn't mine or a superuser's with my privileges." 
> 
> I tried that:
> 
> https://www.postgresql.org/message-id/75b0dbb55e9febea54c441efff8012a6d2cb5bd7.ca...@j-davis.com
> 
> but Andres pointed out some problems with my implementation. They
> didn't seem easily fixable, but perhaps with more effort it could work
> (run all the expressions as security definer, as well?).

Presumably.  Ultimately, I tend to agree it won't be easy.  That doesn't
mean it's not a worthwhile effort.

> >  Of course, we
> > need to make sure it's possible to write safe SECURITY DEFINER
> > functions
> > and to be clear about how to do that to avoid the risk in the other
> > direction.
> 
> Agreed. Perhaps we can force search_path to be set for SECURITY
> DEFINER, and require that the temp schema be explicitly included rather
> than the current "must be at the end". We could also provide a way to
> turn public access off in the same statement, so that you don't need to
> use a transaction block to keep the function private.

We do pretty strongly encourage a search_path setting for SECURITY
DEFINER today..  That said, I'm not against pushing on that harder.  The
issue about temporary schemas is a more difficult issue... but frankly,
I'd like an option to say "no temporary schemas should be allowed in my
search path" when it comes to a security definer function.

> > I don't think we'd be able to get away with just getting rid of
> > SECURITY
> > INVOKER entirely or even in changing the current way triggers (or
> > functions in views, etc) are run by default.
> 
> I didn't propose anything radical. I'm just trying to get some
> agreement that SECURITY INVOKER is central to a lot of our security
> woes, and that we should be treating it with skepticism on a
> fundamental level.

Sure, but if we want to make progress then we have to provide a
direction for folks to go in that's both secure and convenient.

> Individual proposals for how to get away from SECURITY INVOKER should
> be evaluated on their merits (i.e. don't break a bunch of stuff).

Of course.  That said ... we don't want to spend a lot of time
going in a direction that won't bear fruit; I'm hopeful that this
direction will though.

Thanks,

Stephen


signature.asc
Description: PGP signature


Re: Non-superuser subscription owners

2023-02-27 Thread Jeff Davis
On Mon, 2023-02-27 at 16:13 -0500, Robert Haas wrote:
> On Mon, Feb 27, 2023 at 1:25 PM Jeff Davis  wrote:
> > I think you are saying that we should still run Alice's code with
> > the
> > privileges of Bob, but somehow make that safe(r) for Bob. Is that
> > right?
> 
> Yeah. That's the idea I was floating, at least.

Isn't that a hard problem; maybe impossible?

> 
> I guess I have a pretty hard time imagining that we can just
> obliterate SECURITY INVOKER entirely.

Of course not.

>  It seems fundamentally
> reasonable to me that Alice might want to make some code available to
> be executed in the form of a function or procedure but without
> offering to execute it with her own privileges.

It also seems fundamentally reasonable that if someone grants you
privileges on one of their tables, it might be safe to access it.

I'm sure there are a few use cases for SECURITY INVOKER, but they are
quite narrow.

Perhaps most frustratingly, even if none of the users on a system has
any use case for SECURITY INVOKER, they still must all live in fear of
accessing each others' tables, because at any time a SECURITY INVOKER
function could be attached to one of the tables.

I feel like we are giving up mainstream utility and safety in exchange
for contrived or exceptional cases. That's not a good trade.

> We already take the position that VACUUM always runs as the
> table owner, and while VACUUM runs index expressions but not for
> example triggers, why not just be consistent and run all code that is
> tied to the table as the table owner, all the time?

I'd also extend this to default expressions and other code that can be
executed implicitly.

> Maybe that's the right thing to do

If it's the right place to go, then I think we should consider
reasonable steps to take in that direction that don't cause unnecessary
breakage.

> , but I think it would inevitably
> break some things for some users.

Not all steps would be breaking changes, and a lot of those steps are
things we should do anyway. We could make it easier to write safe
SECURITY DEFINER functions, provide more tools for users to opt-out of
executing SECURITY INVOKER code, provide a way for superusers to safely
drop privileges, document the problems with security invoker and what
to do about them, etc.

> Alice might choose to write her
> triggers or default expressions in ways that rely on them running
> with
> Bob's permissions in any number of ways.

Sure, breakage is possible, and we should mitigate it.

But we also shouldn't exaggerate it -- for instance, others have
proposed that we run code as the table owner for logical subscriptions,
and that's going to break things in the same way. Arguably, if we are
going to break something, it's better to break it consistently rather
than one subsystem at a time.

Back to the $SUBJECT, if we allow non-superusers to run subscriptions,
and the subscription runs the code as the table owner, that might also
lead to some weird behavior for triggers that rely on SECURITY INVOKER
semantics.

Regards,
Jeff Davis






Re: Non-superuser subscription owners

2023-02-27 Thread Jeff Davis
On Mon, 2023-02-27 at 14:10 -0500, Stephen Frost wrote:
> I do think there are some use-cases for it, but agree that it'd be
> better to encourage more use of SECURITY DEFINER and one approach to
> that might be to have a way for users to explicitly say "don't run
> code
> that isn't mine or a superuser's with my privileges." 

I tried that:

https://www.postgresql.org/message-id/75b0dbb55e9febea54c441efff8012a6d2cb5bd7.ca...@j-davis.com

but Andres pointed out some problems with my implementation. They
didn't seem easily fixable, but perhaps with more effort it could work
(run all the expressions as security definer, as well?).

>  Of course, we
> need to make sure it's possible to write safe SECURITY DEFINER
> functions
> and to be clear about how to do that to avoid the risk in the other
> direction.

Agreed. Perhaps we can force search_path to be set for SECURITY
DEFINER, and require that the temp schema be explicitly included rather
than the current "must be at the end". We could also provide a way to
turn public access off in the same statement, so that you don't need to
use a transaction block to keep the function private.

> I don't think we'd be able to get away with just getting rid of
> SECURITY
> INVOKER entirely or even in changing the current way triggers (or
> functions in views, etc) are run by default.

I didn't propose anything radical. I'm just trying to get some
agreement that SECURITY INVOKER is central to a lot of our security
woes, and that we should be treating it with skepticism on a
fundamental level.

Individual proposals for how to get away from SECURITY INVOKER should
be evaluated on their merits (i.e. don't break a bunch of stuff).

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-02-27 Thread Robert Haas
On Mon, Feb 27, 2023 at 1:25 PM Jeff Davis  wrote:
> I think you are saying that we should still run Alice's code with the
> privileges of Bob, but somehow make that safe(r) for Bob. Is that
> right?

Yeah. That's the idea I was floating, at least.

> That sounds hard, and I'm still stuck at the "why" question. Why do we
> want to run Alice's code with Bob's permissions?
>
> The answers I have so far are abstract. For instance, maybe it's a
> clever SRF that takes table names as inputs and you want people to only
> be able to use the clever SRF with tables they have privileges on. But
> that's not what most functions do, and it's certainly not what most
> default expressions do.

I guess I have a pretty hard time imagining that we can just
obliterate SECURITY INVOKER entirely. It seems fundamentally
reasonable to me that Alice might want to make some code available to
be executed in the form of a function or procedure but without
offering to execute it with her own privileges. But I think maybe
you're asking a different question, which is whether when the code is
attached to a table we ought to categorically switch to the table
owner before executing it. I'm less sure about the answer to that
question. We already take the position that VACUUM always runs as the
table owner, and while VACUUM runs index expressions but not for
example triggers, why not just be consistent and run all code that is
tied to the table as the table owner, all the time?

Maybe that's the right thing to do, but I think it would inevitably
break some things for some users. Alice might choose to write her
triggers or default expressions in ways that rely on them running with
Bob's permissions in any number of ways. For instance, maybe those
functions issue a SELECT query against an RLS-enabled table, such that
the answer depends on whose privileges are used to run the query. More
simply, she might refer to CURRENT_ROLE, say to record who inserted
any particular row into her table, which seems like a totally
reasonable thing to want to do. If she was feeling really clever, she
might even have designed queries that she's using inside those
triggers or default expressions to fail if Bob doesn't have enough
permissions to do some particular modification that he's attempting,
and thus block certain kinds of access to her own tables. That would
be pretty weird and perhaps too clever by half, but the point is that
the current behavior is probably known to many, many users and we
really can't know what they've done that depends on that. If we change
any behavior here, some people are going to notice those changes, and
they may not like them.

To put that another way, we're not talking about a black-and-white
security vulnerability here, like a buffer overrun that allows for
arbitrary code execution. We're talking about a set of semantics that
seem to be somewhat fragile and vulnerable to spawning security
problems. Nobody wants those security problems, for sure. But it
doesn't follow that nobody is relying on the semantics.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-02-27 Thread Stephen Frost
Greetings,

* Jeff Davis (pg...@j-davis.com) wrote:
> On Mon, 2023-02-27 at 10:45 -0500, Robert Haas wrote:
> >  Suppose Alice owns a table and attaches a trigger to it. If
> > Bob inserts into that table, I think we have to run the trigger,
> > because Alice is entitled to assume that, for example, any BEFORE
> > triggers she might have defined that block certain kinds of inserts
> > are actually going to block those inserts; any constraints that she
> > has applied to the table are going to be enforced against all new
> > rows; and any default expressions she supplies are actually going to
> > work.
> 
> True, but I still find myself suspending my disbelief. Which of these
> use cases make sense for SECURITY INVOKER?

I do think there are some use-cases for it, but agree that it'd be
better to encourage more use of SECURITY DEFINER and one approach to
that might be to have a way for users to explicitly say "don't run code
that isn't mine or a superuser's with my privileges."  Of course, we
need to make sure it's possible to write safe SECURITY DEFINER functions
and to be clear about how to do that to avoid the risk in the other
direction.  We also need to provide some additonal functions along the
lines of "calling_role()" or similar (so that the function can know who
the actual role is that's running the trigger) for the common case of
auditing or needing to know the calling role for RLS or similar.

I don't think we'd be able to get away with just getting rid of SECURITY
INVOKER entirely or even in changing the current way triggers (or
functions in views, etc) are run by default.

> > I think Bob has to be OK with those things too; otherwise, he
> > just shouldn't insert anything into the table.
> 
> Right, but why should Bob's privileges be needed to do any of those
> things? Any difference in privileges, for those use cases, could only
> either get in the way of achieving Alice's goals, or cause a security
> problem for Bob.
> 
> > But Bob doesn't have to be OK with Alice's code changing the session
> > state, or executing DML or DDL with his permissions.
> 
> What's left? Should Bob be OK with Alice's code using his permissions
> for anything?

I don't know about trying to define that X things are ok and Y things
are not, that seems like it would be more confusing and difficult to
work with.  Regular SELECT queries that pull data that Bob has access to
but Alice doesn't is a security issue too, were Alice to install a
function that Bob calls which writes that data into a place that Alice
could then access it.  Perhaps if we could allow Bob to say "these
things are ok for Alice's code to access" then it could work ... but if
that's what is going on then the code could run with Alice's permissions
and Bob could use our nice and granular GRANT/RLS system to say what
Alice is allowed to access.

> >  I wonder if
> > that's where we should be trying to insert restrictions here. Right
> > now, we think of SECURITY_RESTRICTED_OPERATION as a way to prevent a
> > function or procedure that runs under a different user ID than the
> > session user from poisoning the session state. But I'm thinking that
> > maybe the problem isn't really with code running under a different
> > user ID. It's with running code *provided by* a different user ID.
> > Maybe we should stop thinking about the security context as something
> > that you set when you switch to running as a different user ID, and
> > start thinking about it as something that needs to be set based on
> > the
> > relationship between the user that provided the code and the session
> > user. If they're not the same, some restrictions are probably
> > appropriate, except I think in the case where the user who provided
> > the code can become the session user anyway.
> 
> I think you are saying that we should still run Alice's code with the
> privileges of Bob, but somehow make that safe(r) for Bob. Is that
> right?
> 
> That sounds hard, and I'm still stuck at the "why" question. Why do we
> want to run Alice's code with Bob's permissions?
> 
> The answers I have so far are abstract. For instance, maybe it's a
> clever SRF that takes table names as inputs and you want people to only
> be able to use the clever SRF with tables they have privileges on. But
> that's not what most functions do, and it's certainly not what most
> default expressions do.

current_role / current_user are certainly common as a default
expression.  I agree that that's more of an edge case that would be nice
to solve in a different way though.  I do think there's some other use
cases for SECURITY INVOKER but not enough folks understand the security
risk associated with it and it'd be good for us to improve on that
situation.

Thanks,

Stephen


signature.asc
Description: PGP signature


Re: Non-superuser subscription owners

2023-02-27 Thread Jeff Davis
On Mon, 2023-02-27 at 10:45 -0500, Robert Haas wrote:

>  Suppose Alice owns a table and attaches a trigger to it. If
> Bob inserts into that table, I think we have to run the trigger,
> because Alice is entitled to assume that, for example, any BEFORE
> triggers she might have defined that block certain kinds of inserts
> are actually going to block those inserts; any constraints that she
> has applied to the table are going to be enforced against all new
> rows; and any default expressions she supplies are actually going to
> work.

True, but I still find myself suspending my disbelief. Which of these
use cases make sense for SECURITY INVOKER?

> I think Bob has to be OK with those things too; otherwise, he
> just shouldn't insert anything into the table.

Right, but why should Bob's privileges be needed to do any of those
things? Any difference in privileges, for those use cases, could only
either get in the way of achieving Alice's goals, or cause a security
problem for Bob.

> But Bob doesn't have to be OK with Alice's code changing the session
> state, or executing DML or DDL with his permissions.

What's left? Should Bob be OK with Alice's code using his permissions
for anything?

>  I wonder if
> that's where we should be trying to insert restrictions here. Right
> now, we think of SECURITY_RESTRICTED_OPERATION as a way to prevent a
> function or procedure that runs under a different user ID than the
> session user from poisoning the session state. But I'm thinking that
> maybe the problem isn't really with code running under a different
> user ID. It's with running code *provided by* a different user ID.
> Maybe we should stop thinking about the security context as something
> that you set when you switch to running as a different user ID, and
> start thinking about it as something that needs to be set based on
> the
> relationship between the user that provided the code and the session
> user. If they're not the same, some restrictions are probably
> appropriate, except I think in the case where the user who provided
> the code can become the session user anyway.

I think you are saying that we should still run Alice's code with the
privileges of Bob, but somehow make that safe(r) for Bob. Is that
right?

That sounds hard, and I'm still stuck at the "why" question. Why do we
want to run Alice's code with Bob's permissions?

The answers I have so far are abstract. For instance, maybe it's a
clever SRF that takes table names as inputs and you want people to only
be able to use the clever SRF with tables they have privileges on. But
that's not what most functions do, and it's certainly not what most
default expressions do.

Regards,
Jeff Davis






Re: Non-superuser subscription owners

2023-02-27 Thread Robert Haas
On Wed, Feb 22, 2023 at 12:18 PM Jeff Davis  wrote:
> There are two questions:
>
> 1. Is the security situation with logical replication bad? Yes. You
> nicely summarized just how bad.
>
> 2. Is it the same situation as accessing a table owned by a user you
> don't absolutely trust?
>
> Regardless of how the second question is answered, it won't diminish
> your point that logical replication is in a bad state. If another
> situation is also bad, we should fix that too.

Well said.

> So I don't think "shouldn't" is quite good enough. In the first place,
> the user needs to know that the risk exists. Second, what if they
> actually do want to access a table owned by someone else for whatever
> reason -- how do they do that safely?

Good question. I don't think we currently have a good answer.

> I can't resist mentioning that these are all SECURITY INVOKER problems.
> SECURITY INVOKER is insecure unless the invoker absolutely trusts the
> definer, and that only really makes sense if the definer is a superuser
> (or something very close). That's why we keep adding exceptions with
> SECURITY_RESTRICTED_OPERATION, which is really just a way to silently
> ignore the SECURITY INVOKER label and use SECURITY DEFINER instead.

That's an interesting way to look at it. I think there are perhaps two
different possible perspectives here. One possibility is to take the
view that you've adopted here, and blame it on SECURITY INVOKER. The
other possibility, at least as I see it, is to blame it on the fact
that we have so many places to attach executable code to tables and
very few ways for people using those tables to limit their exposure to
such code. Suppose Alice owns a table and attaches a trigger to it. If
Bob inserts into that table, I think we have to run the trigger,
because Alice is entitled to assume that, for example, any BEFORE
triggers she might have defined that block certain kinds of inserts
are actually going to block those inserts; any constraints that she
has applied to the table are going to be enforced against all new
rows; and any default expressions she supplies are actually going to
work. I think Bob has to be OK with those things too; otherwise, he
just shouldn't insert anything into the table.

But Bob doesn't have to be OK with Alice's code changing the session
state, or executing DML or DDL with his permissions. I wonder if
that's where we should be trying to insert restrictions here. Right
now, we think of SECURITY_RESTRICTED_OPERATION as a way to prevent a
function or procedure that runs under a different user ID than the
session user from poisoning the session state. But I'm thinking that
maybe the problem isn't really with code running under a different
user ID. It's with running code *provided by* a different user ID.
Maybe we should stop thinking about the security context as something
that you set when you switch to running as a different user ID, and
start thinking about it as something that needs to be set based on the
relationship between the user that provided the code and the session
user. If they're not the same, some restrictions are probably
appropriate, except I think in the case where the user who provided
the code can become the session user anyway.

> Another option is having some kind SECURITY NONE that would run the
> code as a very limited-privilege user that can basically only access
> the catalog. That would be useful for running default expressions and
> the like without the definer or invoker needing to be careful.

This might be possible, but I have some doubts about how difficult it
would be to get all the details right. We'd need to make sure that
this limited-privilege user couldn't ever create a table, or own one,
or be granted any privileges to do anything other than the minimal set
of things it's supposed to be able to do, or poison the session state,
etc. And it would have weird results like current_user returning the
name of the limited-privilege user rather than any of the users
involved in the operation. Maybe that's all OK, but I find it more
appealing to try to think about what kinds of operations can be
performed in what contexts than to invent entirely new users.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-02-22 Thread Joe Conway

On 2/22/23 14:12, Mark Dilger wrote:

On Feb 22, 2023, at 10:49 AM, Jeff Davis  wrote:
On Wed, 2023-02-22 at 09:27 -0800, Mark Dilger wrote:

Another option is to execute under the intersection of their
privileges, where both the definer and the invoker need the
privileges in order for the action to succeed.  That would be more
permissive than the proposed SECURITY NONE, while still preventing
either party from hijacking privileges of the other.


Interesting idea, I haven't heard of something like that being done
before. Is there some precedent for that or a use case where it's
helpful?

 > No current use case comes to mind, but I proposed it for event
triggers one or two development cycles ago, to allow for
non-superuser event trigger owners.  The problems associated with
allowing non-superusers to create and own event triggers were pretty
similar to the problems being discussed in this thread.



The intersection of privileges is used, for example, in multi-level 
security contexts where the intersection of the network-allowed levels 
and the subject allowed levels is used to bracket what can be accessed 
and how.


Other examples I found with a quick search:

https://docs.oracle.com/javase/8/docs/api/java/security/AccessController.html#doPrivileged-java.security.PrivilegedAction-java.security.AccessControlContext-

https://learn.microsoft.com/en-us/dotnet/api/system.security.permissions.dataprotectionpermission.intersect?view=dotnet-plat-ext-7.0


--
Joe Conway
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com





Re: Non-superuser subscription owners

2023-02-22 Thread Mark Dilger



> On Feb 22, 2023, at 10:49 AM, Jeff Davis  wrote:
> 
> On Wed, 2023-02-22 at 09:27 -0800, Mark Dilger wrote:
>> Another option is to execute under the intersection of their
>> privileges, where both the definer and the invoker need the
>> privileges in order for the action to succeed.  That would be more
>> permissive than the proposed SECURITY NONE, while still preventing
>> either party from hijacking privileges of the other.
> 
> Interesting idea, I haven't heard of something like that being done
> before. Is there some precedent for that or a use case where it's
> helpful?

No current use case comes to mind, but I proposed it for event triggers one or 
two development cycles ago, to allow for non-superuser event trigger owners.  
The problems associated with allowing non-superusers to create and own event 
triggers were pretty similar to the problems being discussed in this thread.

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-02-22 Thread Jeff Davis
On Wed, 2023-02-22 at 09:27 -0800, Mark Dilger wrote:
> Another option is to execute under the intersection of their
> privileges, where both the definer and the invoker need the
> privileges in order for the action to succeed.  That would be more
> permissive than the proposed SECURITY NONE, while still preventing
> either party from hijacking privileges of the other.

Interesting idea, I haven't heard of something like that being done
before. Is there some precedent for that or a use case where it's
helpful?

Regards,
Jeff Davis





Re: Non-superuser subscription owners

2023-02-22 Thread Mark Dilger



> On Feb 22, 2023, at 9:18 AM, Jeff Davis  wrote:
> 
> Another option is having some kind SECURITY NONE that would run the
> code as a very limited-privilege user that can basically only access
> the catalog. That would be useful for running default expressions and
> the like without the definer or invoker needing to be careful.

Another option is to execute under the intersection of their privileges, where 
both the definer and the invoker need the privileges in order for the action to 
succeed.  That would be more permissive than the proposed SECURITY NONE, while 
still preventing either party from hijacking privileges of the other.

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-02-22 Thread Jeff Davis
On Mon, 2023-02-06 at 14:40 -0500, Robert Haas wrote:
> On Mon, Feb 6, 2023 at 2:18 PM Andres Freund 
> wrote:
> > It's decidedly not great, yes. I don't know if it's quite a CVE
> > type issue,
> > after all, the same is true for any other type of query the
> > superuser
> > executes. But at the very least the documentation needs to be
> > better, with a
> > big red box making sure the admin is aware of the problem.
> 
> I don't think that's the same thing at all. A superuser executing a
> query interactively can indeed cause all sorts of bad things to
> happen, but you don't have to log in as superuser and run DML queries
> on tables owned by unprivileged users, and you shouldn't.

There are two questions:

1. Is the security situation with logical replication bad? Yes. You
nicely summarized just how bad.

2. Is it the same situation as accessing a table owned by a user you
don't absolutely trust? 

Regardless of how the second question is answered, it won't diminish
your point that logical replication is in a bad state. If another
situation is also bad, we should fix that too.

And I think the DML situation is really bad, too. Anyone reading our
documentation would find extensive explanations about GRANT/REVOKE, and
puzzle over the fine details of exactly how much they trust user foo.
Do I trust foo enough for WITH GRANT OPTION? Does foo really need to
see all of the columns of this table, or just a subset?

But there's no obvious mention that user foo must trust you absolutely
in order to exercise the GRANT at all, because you (as table owner) can
trivially cause foo to execute arbitrary code. There's no warning or
hint or suggestion at runtime to know that you are about to execute
someone else's code with your privileges or that it might be dangerous.

It gets worse. Let's say that user foo figures that out, and they're
extra cautious to SET SESSION AUTHORIZATION or SET ROLE to drop their
privileges before accessing a table. No good: the table owner can just
craft their arbitrary code with a "RESET SESSION AUTHORIZATION" or a
"RESET ROLE" at the top, and the code will still execute with the
privileges of user foo.

So I don't think "shouldn't" is quite good enough. In the first place,
the user needs to know that the risk exists. Second, what if they
actually do want to access a table owned by someone else for whatever
reason -- how do they do that safely?

I can't resist mentioning that these are all SECURITY INVOKER problems.
SECURITY INVOKER is insecure unless the invoker absolutely trusts the
definer, and that only really makes sense if the definer is a superuser
(or something very close). That's why we keep adding exceptions with
SECURITY_RESTRICTED_OPERATION, which is really just a way to silently
ignore the SECURITY INVOKER label and use SECURITY DEFINER instead.

At some point we need to ask: "when is SECURITY INVOKER both safe and
useful?" and contain it to those cases, rather than silently ignoring
it in an expanding list of cases.

I know that the response here is that SECURITY DEFINER is somehow
worse. Maybe for superuser-defined functions, it is. But basically, the
problems with SECURITY DEFINER all amount to "the author of the code
needs to be careful", which is a lot more intuitive than the problems
with SECURITY INVOKER.

Another option is having some kind SECURITY NONE that would run the
code as a very limited-privilege user that can basically only access
the catalog. That would be useful for running default expressions and
the like without the definer or invoker needing to be careful.


-- 
Jeff Davis
PostgreSQL Contributor Team - AWS






Re: Non-superuser subscription owners

2023-02-07 Thread Robert Haas
On Wed, Feb 1, 2023 at 4:02 PM Andres Freund  wrote:
> On 2023-01-30 15:32:34 -0500, Robert Haas wrote:
> > I had a long think about what to do with ALTER SUBSCRIPTION ... OWNER
> > TO in terms of permissions checks.
>
> As long as owner and run-as are the same, I think it's strongly
> preferrable to *not* require pg_create_subscription.

OK.

> > Another question around ALTER SUBSCRIPTION ... OWNER TO and also ALTER
> > SUBSCRIPTION .. RENAME is whether they ought to fail if you're not a
> > superuser and password_required false is set.
>
> I don't really see a benefit in allowing it, so I'm inclined to go for
> the more restrictive option. But this is a really weakly held opinion.

I went back and forth on this and ended up with what you propose here.
It's simpler to explain this way.

> > + /* Is the use of a password mandatory? */
> > + must_use_password = MySubscription->passwordrequired &&
> > + !superuser_arg(MySubscription->owner);
>
> There's a few repetitions of this - perhaps worth putting into a helper?

I don't think so. It's slightly different each time, because it's
pulling data out of different data structures.

> This still leaks the connection on error, no?

I've attempted to fix this in v4, attached.

-- 
Robert Haas
EDB: http://www.enterprisedb.com


v4-0001-Add-new-predefined-role-pg_create_subscriptions.patch
Description: Binary data


Re: Non-superuser subscription owners

2023-02-06 Thread Robert Haas
On Mon, Feb 6, 2023 at 2:18 PM Andres Freund  wrote:
> It's decidedly not great, yes. I don't know if it's quite a CVE type issue,
> after all, the same is true for any other type of query the superuser
> executes. But at the very least the documentation needs to be better, with a
> big red box making sure the admin is aware of the problem.

I don't think that's the same thing at all. A superuser executing a
query interactively can indeed cause all sorts of bad things to
happen, but you don't have to log in as superuser and run DML queries
on tables owned by unprivileged users, and you shouldn't.

But what we're talking about here is -- the superuser comes along and
sets up logical replication in the configuration in what seems to be
exactly the way it was intended to be used, and now any user who can
log into the subscriber node can become superuser for free whenever
they want, without the superuser doing anything at all, even logging
in. Saying it's "not ideal" seems like you're putting it in the same
category as "the cheese got moldy in the fridge" but to me it sounds
more like "the fridge exploded and the house is on fire."

If we were to document this, I assume that the warning we would add to
the documentation would look like this:

<-- begin documentation text -->
Pretty much don't ever use logical replication. In any normal
configuration, it lets every user on your system escalate to superuser
whenever they want. It is possible to make it safe, if you make sure
all the tables on the replica are owned by the superuser and none of
them have any triggers, defaults, expression indexes, or anything else
associated with them that might execute any code while replicating.
But notice that this makes logical replication pretty much useless for
one of its intended purposes, which is high availability, because if
you actually fail over, you're going to then have to change the owners
of all of those tables and apply any missing triggers, defaults,
expression indexes, or anything like that which you may want to have.
And then to fail back you're going to have to remove all of that stuff
again and once again make the tables superuser-owned. That's obviously
pretty impractical, so you probably shouldn't use logical replication
at all until we get around to fixing this. You might wonder why we
implemented a feature that can't be used in any kind of normal way
without completely and totally breaking your system security -- but
don't ask us, we don't know, either!
<-- end documentation text -->

Honestly, this makes the CREATEROLE exploit that I fixed recently in
master look like a walk in the park. Sure, it's a pain for service
providers, who might otherwise use it, but most normal users don't and
wouldn't no matter how it worked, and really are not going to care.
But people do use logical replication, and it seems to me that the
issue you're describing here means that approximately 100% of those
installations have a vulnerability allowing any local user who owns a
table or can create one to escalate to superuser. Far from being not
quite a CVE issue, that seems substantially more serious than most
things we get CVEs for.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-02-06 Thread Andres Freund
Hi,

On 2023-02-06 14:07:39 -0500, Robert Haas wrote:
> On Fri, Feb 3, 2023 at 3:47 AM Andres Freund  wrote:
> > On 2023-02-02 09:28:03 -0500, Robert Haas wrote:
> > > I don't know what you mean by this. DML doesn't confer privileges. If
> > > code gets executed and runs with the replication user's credentials,
> > > that could lead to privilege escalation, but just moving rows around
> > > doesn't, at least not in the database sense.
> >
> > Executing DML ends up executing code. Think predicated/expression
> > indexes, triggers, default expressions etc. If a badly written trigger
> > etc can be tricked to do arbitrary code exec, an attack will be able to
> > run with the privs of the run-as user.  How bad that is is influenced to
> > some degree by the amount of privileges that user has.
> 
> I spent some time studying this today. I think you're right. What I'm
> confused about is: why do we consider this situation even vaguely
> acceptable? Isn't this basically an admission that our logical
> replication security model is completely and totally broken and we
> need to fix it somehow and file for a CVE number? Like, in released
> branches, you can't even have a subscription owned by a non-superuser.
> But any non-superuser can set a default expression or create an enable
> always trigger and sure enough, if that table is replicated, the
> system will run that trigger as the subscription owner, who is a
> superuser. Which AFAICS means that if a non-superuser owns a table
> that is part of a subscription, they can instantly hack superuser.
> Which seems, uh, extremely bad. Am I missing something?

It's decidedly not great, yes. I don't know if it's quite a CVE type issue,
after all, the same is true for any other type of query the superuser
executes. But at the very least the documentation needs to be better, with a
big red box making sure the admin is aware of the problem.

I think we need some more fundamental ways to deal with this issue, including
but not restricted to the replication context. Some potentially relevant
discussion is in this thread:
https://postgr.es/m/75b0dbb55e9febea54c441efff8012a6d2cb5bd7.camel%40j-davis.com

I don't agree with Jeff's proposal, but I think there's some worthwhile ideas
in the idea + followups.


> And then, in master, where there's some provision for non-superuser
> subscription owners, we maybe need to re-think the privileges required
> to replicate into a table in the first place. I don't think that
> having I/U/D permissions on a table is really sufficient to justify
> performing those operations *as the table owner*; perhaps the check
> ought to be whether you have the privileges of the table owner.

Yes, I think we ought to check role membership, including non-inherited
memberships.

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-02-06 Thread Robert Haas
On Fri, Feb 3, 2023 at 3:47 AM Andres Freund  wrote:
> On 2023-02-02 09:28:03 -0500, Robert Haas wrote:
> > I don't know what you mean by this. DML doesn't confer privileges. If
> > code gets executed and runs with the replication user's credentials,
> > that could lead to privilege escalation, but just moving rows around
> > doesn't, at least not in the database sense.
>
> Executing DML ends up executing code. Think predicated/expression
> indexes, triggers, default expressions etc. If a badly written trigger
> etc can be tricked to do arbitrary code exec, an attack will be able to
> run with the privs of the run-as user.  How bad that is is influenced to
> some degree by the amount of privileges that user has.

I spent some time studying this today. I think you're right. What I'm
confused about is: why do we consider this situation even vaguely
acceptable? Isn't this basically an admission that our logical
replication security model is completely and totally broken and we
need to fix it somehow and file for a CVE number? Like, in released
branches, you can't even have a subscription owned by a non-superuser.
But any non-superuser can set a default expression or create an enable
always trigger and sure enough, if that table is replicated, the
system will run that trigger as the subscription owner, who is a
superuser. Which AFAICS means that if a non-superuser owns a table
that is part of a subscription, they can instantly hack superuser.
Which seems, uh, extremely bad. Am I missing something?

Based on other remarks you made upthread, it seems like we ought to be
doing the actual replication as the table owner, since the table owner
has to be prepared for executable code attached to the table to be
re-run on rows in the table at any table when somebody does a REINDEX.
And then, in master, where there's some provision for non-superuser
subscription owners, we maybe need to re-think the privileges required
to replicate into a table in the first place. I don't think that
having I/U/D permissions on a table is really sufficient to justify
performing those operations *as the table owner*; perhaps the check
ought to be whether you have the privileges of the table owner.

--
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-02-03 Thread Andres Freund
Hi,

On 2023-02-02 09:28:03 -0500, Robert Haas wrote:
> I don't know what you mean by this. DML doesn't confer privileges. If
> code gets executed and runs with the replication user's credentials,
> that could lead to privilege escalation, but just moving rows around
> doesn't, at least not in the database sense.

Executing DML ends up executing code. Think predicated/expression
indexes, triggers, default expressions etc. If a badly written trigger
etc can be tricked to do arbitrary code exec, an attack will be able to
run with the privs of the run-as user.  How bad that is is influenced to
some degree by the amount of privileges that user has.

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-02-02 Thread Robert Haas
On Wed, Feb 1, 2023 at 3:37 PM Andres Freund  wrote:
> The general point is that IMO is that in many setups you should use a
> user with fewer privileges than a superuser.  It doesn't really matter
> whether we have an ad-hoc restriction for system catalogs. More often
> than not being able to modify other tables will give you a lot of
> privileges too.

I don't know what you mean by this. DML doesn't confer privileges. If
code gets executed and runs with the replication user's credentials,
that could lead to privilege escalation, but just moving rows around
doesn't, at least not in the database sense. It might confer
unanticipated real-world benefits, like if you can update your own
salary or something, but in the context of replication you have to
have had the ability to do that on some other node anyway. If that
change wasn't supposed to get replicated to the local node, then why
are we using replication? Or why is that table in the publication? I'm
confused.

> > The thing I'm struggling to understand is: if you only want to
> > replicate into tables that Alice can write, why not just make Alice
> > own the subscription?
>
> Because it implies that the replication happens as a user that's
> privileged enough to change the configuration of replication.

But again, replication is just about inserting, updating, and deleting
rows. To change the replication configuration, you have to be able to
parlay that into the ability to execute code. That's why I think
trigger security is really important. But I'm wondering if there's
some way we can handle that that doesn't require us to make a decision
about arun-as user. For instance, if firing triggers as the table
owner is an acceptable solution, then the only thing that the run-as
user is actually controlling is which tables we're willing to
replicate into in the first place (unless there's some other way that
logical replication can run arbitrary code). The name almost becomes a
misnomer in that case. It's not a run-as user, it's
use-this-user's-permissions-to-see-if-I-should-fail-replication user.

> > I was thinking a little bit more about that. I
> > still maintain that the current system is poorly set up to make that
> > work, but suppose we wanted to do better. We could add filtering on
> > the subscriber side, like you list schemas or specific relations that
> > you are or are not willing to replicate into.
>
> Isn't that largely a duplication of the ACLs on relations etc?

Yeah, maybe.

> > I'm not quite sure what we do here now, but I agree that trigger
> > firing seems like a problem. It might be that we need to worry about
> > the user on the origin server, too. If Alice inserts a row that causes
> > a replicated table owned by Bob to fire a trigger or evaluate a
> > default expression or whatever due the presence of a subscription
> > owned by Charlie, there is a risk that Alice might try to attack
> > either Bob or Charlie, or that Bob might try to attack Charlie.
>
> The attack on Bob exists without logical replication too - a REINDEX or
> such is executed as the owner of the relation and re-evaluates index
> expressions, constraints etc.  Given our security model I don't think we
> can protect the relation owner if they trust somebody to insert rows, so
> I don't really know what we can do to protect Charlie against Bob.

Yikes.

> > > > And if we suppose that that already works and is safe, well then
> > > > what's the case where I do need a run-as user?
> > >
> > > It's not at all safe today, IMO. You need to trust that nothing bad will
> > > be replicated, otherwise the owner of the subscription has to be
> > > considered compromised.
> >
> > What kinds of things are bad to replicate?
>
> I think that's unfortunately going to be specific to a setup.

Can you give an example?

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-02-02 Thread Robert Haas
On Wed, Feb 1, 2023 at 1:09 PM Mark Dilger  wrote:
> > On Feb 1, 2023, at 6:43 AM, Robert Haas  wrote:
> > The thing I'm
> > struggling to understand is: if you only want to replicate into tables
> > that Alice can write, why not just make Alice own the subscription?
> > For a run-as user to make sense, you need a scenario where we want the
> > replication to target only tables that Alice can touch, but we also
> > don't want Alice herself to be able to touch the subscription, so you
> > make Alice the run-as user and yourself the owner, or something like
> > that. But I'm not sure what that scenario is exactly.
>
> This "run-as" idea came about because we didn't want arbitrary roles to be 
> able to change the subscription's connection string.  A competing idea was to 
> have a server object rather than a string, with roles like Alice being able 
> to use the server object if they have been granted usage privilege, and not 
> otherwise.  So the "run-as" and "server" ideas were somewhat competing.

As far as not changing the connection string goes, a few more ideas
have entered the fray: the current patch uses a password_required
property that is modelled on postgres_fdw, and I've elsewhere proposed
a reverse pg_hba.conf.

IMHO, for the use cases that I can imagine, the reverse pg_hba.conf
idea feels better than all competitors, because it's the only idea
that lets you define a class of acceptable connection strings. Jeff's
idea of a separate connection object is fine if you have a specific,
short list of connection strings and you want to allow those and
disallow everything else, and there may be cases where people want
that, and that's fine, but my guess is that it's overly restrictive in
a lot of environments. The password_required property has the virtue
of being compatible with what we do in other places right now, and of
preventing wraparound-to-superuser attacks effectively, but it's
totally unconfigurable and that sucks. The runas user idea gives you
some control over who is allowed to set the connection string, but it
doesn't help you delegate that to a non-superuser, because the idea
there is that you want the non-superuser to be able to set connection
strings that are OK with the actual superuser but not others.

I think part of my confusion here is that I thought that the point of
the runas user was to defend against logical replication itself
changing the connection string, and I don't see how it would do that.
It's just moving rows around. If the point is that somebody who can
log in as the runas user might change the connection string to
something we don't like, that makes somewhat more sense. I think I had
in my head that you wouldn't use someone's actual login role to run
logical replication, but rather some role specifically set up for that
purpose. In that scenario, nobody's running SQL commands as the runas
user, so even if they also own the subscription, there's no way for it
to get modified.

> > Mark was postulating a scenario where the publisher and subscriber
> > don't trust each other. I was thinking a little bit more about that. I
> > still maintain that the current system is poorly set up to make that
> > work, but suppose we wanted to do better. We could add filtering on
> > the subscriber side, like you list schemas or specific relations that
> > you are or are not willing to replicate into. Then you could, for
> > example, connect your subscription to a certain remote publication,
> > but with the restriction that you're only willing to replicate into
> > the "headquarters" schema. Then we'll replicate whatever tables they
> > send us, but if the dorks at headquarters mess up the publications on
> > their end (intentionally or otherwise) and add some tables from the
> > "locally_controlled_stuff" schema, we'll refuse to replicate that into
> > our eponymous schema.
>
> That example is good, though I don't see how "filters" are better than 
> roles+privileges.  Care to elaborate?

I'm not sure that they are. Are we assuming that the user who is
creating subscriptions is also powerful enough to create roles and
give them just the required amount of privilege? If so, it seems like
they might as well just do it that way. And maybe we should assume
that, because in most cases, a dedication replication role makes more
sense to me than running replication under some role that you're also
using for other things. On the other hand, I bet a lot of people today
are just running replication as a superuser, in which case maybe this
could be useful? This whole idea was mostly just me spitballing to see
what other people thought. I'm not wild about the complexity involved
for what you get out of it, so if we don't need it, that's more than
fine with me.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-02-01 Thread Andres Freund
Hi,

On 2023-01-30 15:32:34 -0500, Robert Haas wrote:
> I had a long think about what to do with ALTER SUBSCRIPTION ... OWNER
> TO in terms of permissions checks. The previous version required that
> the new owner have permissions of pg_create_subscription, but there
> seems to be no particular reason for that rule except that it happens
> to be what I made the code do. So I changed it to say that the current
> owner must have CREATE privilege on the database, and must be able to
> SET ROLE to the new owner. This matches the rule for CREATE SCHEMA.
> Possibly we should *additionally* require that the person performing
> the rename still have pg_create_subscription, but that shouldn't be
> the only requirement.

As long as owner and run-as are the same, I think it's strongly
preferrable to *not* require pg_create_subscription.


> There seems to be a good deal of inconsistency here. If you want to
> give someone a schema, YOU need CREATE on the database. But if you
> want to give someone a table, THEY need CREATE on the containing
> schema. It make sense that we check permissions on the containing
> object, which could be a database or a schema depending on what you're
> renaming, but it's unclear to me why we sometimes check on the person
> performing the ALTER command and at other times on the recipient. It's
> also somewhat unclear to me why we are checking CREATE in the first
> place, especially on the donor. It might make sense to have a rule
> that you can't own an object in a place where you couldn't have
> created it, but there is no such rule, because you can give someone
> CREATE on a schema, they can create an object, and they you can take
> CREATE a way and they still own an object there. So it kind of looks
> to me like we made it up as we went along and that the result isn't
> very consistent, but I'm inclined to follow CREATE SCHEMA here unless
> there's some reason to do otherwise.

Yuck. No idea what the best policy around this is.


> Another question around ALTER SUBSCRIPTION ... OWNER TO and also ALTER
> SUBSCRIPTION .. RENAME is whether they ought to fail if you're not a
> superuser and password_required false is set.

I don't really see a benefit in allowing it, so I'm inclined to go for
the more restrictive option. But this is a really weakly held opinion.



> > > If there is, I think we could fix it by moving the LockSharedObject call 
> > > up
> > > higher, above object_ownercheck. The only problem with that is it lets you
> > > lock an object on which you have no permissions: see
> > > 2ad36c4e44c8b513f6155656e1b7a8d26715bb94. To really fix that, we'd need an
> > > analogue of RangeVarGetRelidExtended.
> >
> > Yea, we really should have something like RangeVarGetRelidExtended() for 
> > other
> > kinds of objects. It'd take a fair bit of work / time to use it widely, but
> > it'll take even longer if we start in 5 years ;)
>
> We actually have something sort of like that in the form of
> get_object_address(). It doesn't allow for a callback, but it does
> have a retry loop.

Hm, sure looks like that code doesn't do any privilege checking...


> @@ -1269,13 +1270,19 @@ LogicalRepSyncTableStart(XLogRecPtr *origin_startpos)
>   
> slotname,
>   
> NAMEDATALEN);
>
> + /* Is the use of a password mandatory? */
> + must_use_password = MySubscription->passwordrequired &&
> + !superuser_arg(MySubscription->owner);

There's a few repetitions of this - perhaps worth putting into a helper?


> @@ -180,6 +181,13 @@ libpqrcv_connect(const char *conninfo, bool logical, 
> const char *appname,
>   if (PQstatus(conn->streamConn) != CONNECTION_OK)
>   goto bad_connection_errmsg;
>
> + if (must_use_password && !PQconnectionUsedPassword(conn->streamConn))
> + ereport(ERROR,
> + 
> (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
> +  errmsg("password is required"),
> +  errdetail("Non-superuser cannot connect if the 
> server does not request a password."),
> +  errhint("Target server's authentication method 
> must be changed. or set password_required=false in the subscription 
> attributes\
.")));
> +
>   if (logical)
>   {
>   PGresult   *res;

This still leaks the connection on error, no?

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-02-01 Thread Andres Freund
Hi,

On 2023-02-01 09:43:39 -0500, Robert Haas wrote:
> On Tue, Jan 31, 2023 at 7:01 PM Andres Freund  wrote:
> > I don't really understand that - the run-as approach seems like a
> > necessary piece of improving the security model.
> >
> > I think it's perfectly reasonable to want to replicate from one system
> > in another, but to not want to allow logical replication to insert into
> > pg_class or whatnot. So not using superuser to execute the replication
> > makes sense.
> >
> > This is particularly the case if you're just replicating a small part of
> > the tables from one system to another. E.g. in a sharded setup, you may
> > want to replicate metadata too servers.
> 
> I don't think that a system catalog should be considered a valid
> replication target, no matter who owns the subscription, so ISTM that
> writing to pg_class should be blocked regardless.

The general point is that IMO is that in many setups you should use a
user with fewer privileges than a superuser.  It doesn't really matter
whether we have an ad-hoc restriction for system catalogs. More often
than not being able to modify other tables will give you a lot of
privileges too.


> The thing I'm struggling to understand is: if you only want to
> replicate into tables that Alice can write, why not just make Alice
> own the subscription?

Because it implies that the replication happens as a user that's
privileged enough to change the configuration of replication.


> Mark was postulating a scenario where the publisher and subscriber
> don't trust each other.

FWIW, I don't this this is mainly about "trust", but instead about
layering security / the principle of least privilege. The "run-as" user
(i.e. currently owner) is constantly performing work on behalf of a
remote node, including executing code (default clauses etc). To make it
harder to use such a cross-system connection to move from one system to
the next, it's a good idea to execute it in the least privileged context
possible. And I don't see why it'd need the permission to modify the
definition of the subscription and similar "admin" tasks.

It's not that such an extra layer would necessarily completely stop an
attacker. But it might delay them and make their attack more noisy.


Similarly, if I were to operate an important production environment
again, I'd not have relations owned by the [pseudo]superuser, but by a
user controlled by the [pseudo]superuser. That way somebody tricking the
superuser into a REINDEX or such only gets the ability to execute code
in a less privileged context.




> I was thinking a little bit more about that. I
> still maintain that the current system is poorly set up to make that
> work, but suppose we wanted to do better. We could add filtering on
> the subscriber side, like you list schemas or specific relations that
> you are or are not willing to replicate into.

Isn't that largely a duplication of the ACLs on relations etc?


> > I think we'll need two things to improve upon the current situation:
> >
> > 1) run-as user, to reduce the scope of potential danger
> >
> > 2) Option to run the database inserts as the owner of the table, with a
> >check that the run-as is actually allowed to perform work as the
> >owning role. That prevents escalation from table owner (who could add
> >default expressions etc) from gettng the privs of the
> >run-as/replication owner.
> 
> I'm not quite sure what we do here now, but I agree that trigger
> firing seems like a problem. It might be that we need to worry about
> the user on the origin server, too. If Alice inserts a row that causes
> a replicated table owned by Bob to fire a trigger or evaluate a
> default expression or whatever due the presence of a subscription
> owned by Charlie, there is a risk that Alice might try to attack
> either Bob or Charlie, or that Bob might try to attack Charlie.

The attack on Bob exists without logical replication too - a REINDEX or
such is executed as the owner of the relation and re-evaluates index
expressions, constraints etc.  Given our security model I don't think we
can protect the relation owner if they trust somebody to insert rows, so
I don't really know what we can do to protect Charlie against Bob.



> > > And if we suppose that that already works and is safe, well then
> > > what's the case where I do need a run-as user?
> >
> > It's not at all safe today, IMO. You need to trust that nothing bad will
> > be replicated, otherwise the owner of the subscription has to be
> > considered compromised.
> 
> What kinds of things are bad to replicate?

I think that's unfortunately going to be specific to a setup.

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-02-01 Thread Mark Dilger



> On Feb 1, 2023, at 6:43 AM, Robert Haas  wrote:

> The thing I'm
> struggling to understand is: if you only want to replicate into tables
> that Alice can write, why not just make Alice own the subscription?
> For a run-as user to make sense, you need a scenario where we want the
> replication to target only tables that Alice can touch, but we also
> don't want Alice herself to be able to touch the subscription, so you
> make Alice the run-as user and yourself the owner, or something like
> that. But I'm not sure what that scenario is exactly.

This "run-as" idea came about because we didn't want arbitrary roles to be able 
to change the subscription's connection string.  A competing idea was to have a 
server object rather than a string, with roles like Alice being able to use the 
server object if they have been granted usage privilege, and not otherwise.  So 
the "run-as" and "server" ideas were somewhat competing.

> Mark was postulating a scenario where the publisher and subscriber
> don't trust each other. I was thinking a little bit more about that. I
> still maintain that the current system is poorly set up to make that
> work, but suppose we wanted to do better. We could add filtering on
> the subscriber side, like you list schemas or specific relations that
> you are or are not willing to replicate into. Then you could, for
> example, connect your subscription to a certain remote publication,
> but with the restriction that you're only willing to replicate into
> the "headquarters" schema. Then we'll replicate whatever tables they
> send us, but if the dorks at headquarters mess up the publications on
> their end (intentionally or otherwise) and add some tables from the
> "locally_controlled_stuff" schema, we'll refuse to replicate that into
> our eponymous schema.

That example is good, though I don't see how "filters" are better than 
roles+privileges.  Care to elaborate?

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-02-01 Thread Robert Haas
On Tue, Jan 31, 2023 at 7:01 PM Andres Freund  wrote:
> I don't really understand that - the run-as approach seems like a
> necessary piece of improving the security model.
>
> I think it's perfectly reasonable to want to replicate from one system
> in another, but to not want to allow logical replication to insert into
> pg_class or whatnot. So not using superuser to execute the replication
> makes sense.
>
> This is particularly the case if you're just replicating a small part of
> the tables from one system to another. E.g. in a sharded setup, you may
> want to replicate metadata too servers.

I don't think that a system catalog should be considered a valid
replication target, no matter who owns the subscription, so ISTM that
writing to pg_class should be blocked regardless. The thing I'm
struggling to understand is: if you only want to replicate into tables
that Alice can write, why not just make Alice own the subscription?
For a run-as user to make sense, you need a scenario where we want the
replication to target only tables that Alice can touch, but we also
don't want Alice herself to be able to touch the subscription, so you
make Alice the run-as user and yourself the owner, or something like
that. But I'm not sure what that scenario is exactly.

Mark was postulating a scenario where the publisher and subscriber
don't trust each other. I was thinking a little bit more about that. I
still maintain that the current system is poorly set up to make that
work, but suppose we wanted to do better. We could add filtering on
the subscriber side, like you list schemas or specific relations that
you are or are not willing to replicate into. Then you could, for
example, connect your subscription to a certain remote publication,
but with the restriction that you're only willing to replicate into
the "headquarters" schema. Then we'll replicate whatever tables they
send us, but if the dorks at headquarters mess up the publications on
their end (intentionally or otherwise) and add some tables from the
"locally_controlled_stuff" schema, we'll refuse to replicate that into
our eponymous schema. I don't think this kind of system is well-suited
to environments where people are totally hostile to each other,
because you still need to have replication slots on the remote side
and stuff. Also, having the remote side decode stuff and ignoring it
locally is expensive, and I bet if we add stuff like this then people
will misuse it and be sad. But it would make the system easier to
reason about: I know for sure that this subscription will only write
to these places, because that's all I've given it permission to do.

In the sharding scenario you mention, if you want to provide
accidental writes to unrelated tables due to the publication being not
what we expect, you can either make the subscription owned by the same
role that owns the sharded tables, or a special-purpose role that has
permission to write to exactly the set of tables that you expect to be
touched and no others. Or, if you had something like what I posited in
the last paragraph, you could use that instead. But I don't see how a
separate run-as user helps. If I'm just being super-dense here, I hope
that one of you will explain using short words. :-)

> I think we'll need two things to improve upon the current situation:
>
> 1) run-as user, to reduce the scope of potential danger
>
> 2) Option to run the database inserts as the owner of the table, with a
>check that the run-as is actually allowed to perform work as the
>owning role. That prevents escalation from table owner (who could add
>default expressions etc) from gettng the privs of the
>run-as/replication owner.

I'm not quite sure what we do here now, but I agree that trigger
firing seems like a problem. It might be that we need to worry about
the user on the origin server, too. If Alice inserts a row that causes
a replicated table owned by Bob to fire a trigger or evaluate a
default expression or whatever due the presence of a subscription
owned by Charlie, there is a risk that Alice might try to attack
either Bob or Charlie, or that Bob might try to attack Charlie.

> > And if we suppose that that already works and is safe, well then
> > what's the case where I do need a run-as user?
>
> It's not at all safe today, IMO. You need to trust that nothing bad will
> be replicated, otherwise the owner of the subscription has to be
> considered compromised.

What kinds of things are bad to replicate?

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-31 Thread Andres Freund
Hi,

On 2023-01-30 10:44:29 -0500, Robert Haas wrote:
> On a technical level, I think that the idea of having a separate
> objection for the connection string vs. the subscription itself is
> perfectly sound, and to repeat what I said earlier, if someone wants
> to implement that, cool. I also agree that it has the advantage that
> you specify, namely, that someone can have rights to modify one of
> those objects but not the other. What that lets you do is define a
> short list of known systems and say, hey, you can replicate whatever
> tables you want with whatever options you want, but only between these
> systems. I'm not quite sure what problem that solves, though.

That does seem somewhat useful, but also fairly limited, at least as
long as it's really just a single connection, rather than a "pattern" of
safe connections.


> Unfortunately, I have even less of an idea about what the run-as
> concept is supposed to accomplish. I mean, at one level, I see it
> quite clearly: the user creating the subscription wants replication to
> have restricted privileges when it's running, and so they make the
> run-as user some role with fewer privileges than their own. Brilliant.
> But then I get stuck: against what kind of attack does that actually
> protect us? If I'm a high privilege user, perhaps even a superuser,
> and it's not safe to have logical replication running as me, then it
> seems like the security model of logical replication is fundamentally
> busted and we need to fix that.

I don't really understand that - the run-as approach seems like a
necessary piece of improving the security model.

I think it's perfectly reasonable to want to replicate from one system
in another, but to not want to allow logical replication to insert into
pg_class or whatnot. So not using superuser to execute the replication
makes sense.

This is particularly the case if you're just replicating a small part of
the tables from one system to another. E.g. in a sharded setup, you may
want to replicate metadata too servers.

Even if all the systems are operated by people you trust (including
possibly even yourself, if you want to go that far), you may want to
reduce the blast radius of privilege escalation, or even just bugs, to a
smaller amount of data.


I think we'll need two things to improve upon the current situation:

1) run-as user, to reduce the scope of potential danger

2) Option to run the database inserts as the owner of the table, with a
   check that the run-as is actually allowed to perform work as the
   owning role. That prevents escalation from table owner (who could add
   default expressions etc) from gettng the privs of the
   run-as/replication owner.


I think it makes sense for 1) to be a fairly privileged user, but I
think it's good practice for that user to not be allowed to change the
system configuration etc.


> It can't be right to say that if you have 263 users in a database and
> you want to replicate the whole database to some other node, you need
> 263 different subscriptions with a different run-as user for each. You
> need to be able to run all of that logical replication as the
> superuser or some other high-privilege user and not end up with a
> security compromise.

I'm not quite following along here - are you thinking of 263 tables
owned by 263 users? If yes, that's why I am thinking that we need the
option to perform each table modification as the owner of that table
(with the same security restrictions we use for REINDEX etc).


> And if we suppose that that already works and is safe, well then
> what's the case where I do need a run-as user?

It's not at all safe today, IMO. You need to trust that nothing bad will
be replicated, otherwise the owner of the subscription has to be
considered compromised.

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-01-31 Thread Mark Dilger



> On Jan 30, 2023, at 1:29 PM, Robert Haas  wrote:
> 
> I feel like you're accusing me of removing functionality that has
> never existed. A subscription doesn't run as the subscription creator.
> It runs as the subscription owner. If you or anyone else had added the
> capability for it to run as someone other than the subscription owner,
> I certainly wouldn't be trying to back that capability out as part of
> this patch, and because there isn't, I'm not proposing to add that as
> part of this patch. I don't see how that makes me guilty of squashing
> anything together. The current state of affairs, where the run-as user
> is taken from pg_subscription.subowner, the same field that is updated
> by ALTER SUBSCRIPTION ... OWNER TO, is the result of your work, not
> anything that I have done or am proposing to do.
> 
> I also *emphatically* disagree with the idea that this undoes what you
> worked on. My patch would be *impossible* without your work. Prior to
> your work, the run-as user was always, basically, the superuser, and
> so the idea of allowing anyone other than a superuser to execute
> CREATE SUBSCRIPTION would be flat-out nuts. Because of your work,
> that's now a thing that we may be able to reasonably allow, if we can
> work through the remaining issues. So I'm grateful to you, and also
> sorry to hear that you're annoyed with me. But I still don't think
> that the fact that the division you want doesn't exist is somehow my
> fault.
> 
> I'm kind of curious why you *didn't* make this distinction at the time
> that you were did the other work in this area. Maybe my memory is
> playing tricks on me again, but I seem to recall talking about the
> idea with you at the time, and I seem to recall thinking that it
> sounded like an OK idea. I seem to vaguely recall us discussing
> hazards like: well, what if replication causes code to get executed as
> the subscription owner that that causes something bad to happen? But I
> think the only way that happens is if they put triggers on the tables
> that are being replicated, which is their choice, and they can avoid
> installing problematic code there if they want. I think there might
> have been some other scenarios, too, but I just can't remember. In any
> case, I don't think the idea is completely without merit. I think it
> could very well be something that we want to have for one reason or
> another. But I don't currently understand exactly what those reasons
> are, and I don't see any reason why one patch should both split owner
> from run-as user and also allow the owner to be a non-superuser. That
> seems like two different efforts to me.

I don't have a concrete problem with your patch, and wouldn't object if you 
committed it.  My concerns were more how you were phrasing things, but it seems 
not worth any additional conversation, because it's probably a distinction 
without a difference.

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-01-30 Thread Robert Haas
On Mon, Jan 30, 2023 at 3:27 PM Mark Dilger
 wrote:
> That was an aspirational example in which there's infinite daylight between 
> the publisher and subscriber.  I, too, doubt that's ever going to be 
> possible.  But I still think we should aspire to some extra daylight between 
> the two.  Perhaps IANA doesn't publish to the whole world, but instead 
> publishes only to subscribers who have a contract in place, and have agreed 
> to monetary penalties should they abuse the publishing server.  Whatever.  
> There's going to be some amount of daylight possible if we design for it, and 
> none otherwise.
>
> My real argument here isn't against your goal of having non-superusers who 
> can create subscriptions.  That part seems fine to me.
>
> Given that my work last year made it possible for subscriptions to run as 
> somebody other than the subscription creator, it annoys me that you now want 
> the subscription creator's privileges to be what the subscription runs as.  
> That seems to undo what I worked on.  In my mental model of a 
> (superuser-creator, non-superuser-owner) pair, it seems you're logically only 
> touching the lefthand side, so you should then have a (nonsuperuser-creator, 
> nonsuperuser-owner) pair.  But you don't.  You go the apparently needless 
> extra step of just squashing them together.  I just don't see why it needs to 
> be like that.

I feel like you're accusing me of removing functionality that has
never existed. A subscription doesn't run as the subscription creator.
It runs as the subscription owner. If you or anyone else had added the
capability for it to run as someone other than the subscription owner,
I certainly wouldn't be trying to back that capability out as part of
this patch, and because there isn't, I'm not proposing to add that as
part of this patch. I don't see how that makes me guilty of squashing
anything together. The current state of affairs, where the run-as user
is taken from pg_subscription.subowner, the same field that is updated
by ALTER SUBSCRIPTION ... OWNER TO, is the result of your work, not
anything that I have done or am proposing to do.

I also *emphatically* disagree with the idea that this undoes what you
worked on. My patch would be *impossible* without your work. Prior to
your work, the run-as user was always, basically, the superuser, and
so the idea of allowing anyone other than a superuser to execute
CREATE SUBSCRIPTION would be flat-out nuts. Because of your work,
that's now a thing that we may be able to reasonably allow, if we can
work through the remaining issues. So I'm grateful to you, and also
sorry to hear that you're annoyed with me. But I still don't think
that the fact that the division you want doesn't exist is somehow my
fault.

I'm kind of curious why you *didn't* make this distinction at the time
that you were did the other work in this area. Maybe my memory is
playing tricks on me again, but I seem to recall talking about the
idea with you at the time, and I seem to recall thinking that it
sounded like an OK idea. I seem to vaguely recall us discussing
hazards like: well, what if replication causes code to get executed as
the subscription owner that that causes something bad to happen? But I
think the only way that happens is if they put triggers on the tables
that are being replicated, which is their choice, and they can avoid
installing problematic code there if they want. I think there might
have been some other scenarios, too, but I just can't remember. In any
case, I don't think the idea is completely without merit. I think it
could very well be something that we want to have for one reason or
another. But I don't currently understand exactly what those reasons
are, and I don't see any reason why one patch should both split owner
from run-as user and also allow the owner to be a non-superuser. That
seems like two different efforts to me.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-30 Thread Robert Haas
On Fri, Jan 27, 2023 at 5:00 PM Andres Freund  wrote:
> > Or, another thought, maybe this should be checking for CREATE on the
> > current database + also pg_create_subscription. That seems like it
> > might be the right idea, actually.
>
> Yes, that seems like a good idea.

Done in this version. I also changed check_conninfo to take an extra
argument instead of returning a Boolean, as per your suggestion.

I had a long think about what to do with ALTER SUBSCRIPTION ... OWNER
TO in terms of permissions checks. The previous version required that
the new owner have permissions of pg_create_subscription, but there
seems to be no particular reason for that rule except that it happens
to be what I made the code do. So I changed it to say that the current
owner must have CREATE privilege on the database, and must be able to
SET ROLE to the new owner. This matches the rule for CREATE SCHEMA.
Possibly we should *additionally* require that the person performing
the rename still have pg_create_subscription, but that shouldn't be
the only requirement. This change means that you can't just randomly
give your subscription to the superuser (with or without concurrently
attempting some other change as per your other comments) which is good
because you can't do that with other object types either.

There seems to be a good deal of inconsistency here. If you want to
give someone a schema, YOU need CREATE on the database. But if you
want to give someone a table, THEY need CREATE on the containing
schema. It make sense that we check permissions on the containing
object, which could be a database or a schema depending on what you're
renaming, but it's unclear to me why we sometimes check on the person
performing the ALTER command and at other times on the recipient. It's
also somewhat unclear to me why we are checking CREATE in the first
place, especially on the donor. It might make sense to have a rule
that you can't own an object in a place where you couldn't have
created it, but there is no such rule, because you can give someone
CREATE on a schema, they can create an object, and they you can take
CREATE a way and they still own an object there. So it kind of looks
to me like we made it up as we went along and that the result isn't
very consistent, but I'm inclined to follow CREATE SCHEMA here unless
there's some reason to do otherwise.

Another question around ALTER SUBSCRIPTION ... OWNER TO and also ALTER
SUBSCRIPTION .. RENAME is whether they ought to fail if you're not a
superuser and password_required false is set. They are separate code
paths from the rest of the ALTER SUBSCRIPTION cases, so if we want
that to be a rule we need dedicated code for it. I'm not quite sure
what's right. There's no comparable case for ALTER USER MAPPING
because a user mapping doesn't have an owner and so can't be
reassigned to a new owner. I don't see what the harm is, especially
for RENAME, but I might be missing something, and it certainly seems
arguable.

> > I'm not entirely clear whether there's a hazard there.
>
> I'm not at all either. It's just a code pattern that makes me anxious - I
> suspect there's a few places it makes us more vulnerable.

It looks likely to me that it was cut down from the CREATE SCHEMA code, FWIW.

> > If there is, I think we could fix it by moving the LockSharedObject call up
> > higher, above object_ownercheck. The only problem with that is it lets you
> > lock an object on which you have no permissions: see
> > 2ad36c4e44c8b513f6155656e1b7a8d26715bb94. To really fix that, we'd need an
> > analogue of RangeVarGetRelidExtended.
>
> Yea, we really should have something like RangeVarGetRelidExtended() for other
> kinds of objects. It'd take a fair bit of work / time to use it widely, but
> it'll take even longer if we start in 5 years ;)

We actually have something sort of like that in the form of
get_object_address(). It doesn't allow for a callback, but it does
have a retry loop.

-- 
Robert Haas
EDB: http://www.enterprisedb.com


v3-0001-Add-new-predefined-role-pg_create_subscriptions.patch
Description: Binary data


Re: Non-superuser subscription owners

2023-01-30 Thread Mark Dilger



> On Jan 30, 2023, at 11:30 AM, Robert Haas  wrote:
> 
> CREATE SUBSCRIPTION
> provides no tools at all for filtering the data that the subscriber
> chooses to send.
> 
> Now that can be changed, I suppose, and a run-as user would be one way
> to make progress in that direction. But I'm not sure how viable that
> is, because...
> 
>>> In what
>>> circumstances would be it be reasonable to give responsibility for
>>> those objects to different and especially mutually untrusting users?
>> 
>> When public repositories of data, such as the IANA whois database, publish 
>> their data via postgres publications.
> 
> ... for that to work, IANA would need to set up the database so that
> untrusted parties can create logical replication slots on their
> PostgreSQL server. And I think that granting REPLICATION privilege on
> your database to random people on the Internet is not really viable,
> nor intended to be viable.

That was an aspirational example in which there's infinite daylight between the 
publisher and subscriber.  I, too, doubt that's ever going to be possible.  But 
I still think we should aspire to some extra daylight between the two.  Perhaps 
IANA doesn't publish to the whole world, but instead publishes only to 
subscribers who have a contract in place, and have agreed to monetary penalties 
should they abuse the publishing server.  Whatever.  There's going to be some 
amount of daylight possible if we design for it, and none otherwise.

My real argument here isn't against your goal of having non-superusers who can 
create subscriptions.  That part seems fine to me.

Given that my work last year made it possible for subscriptions to run as 
somebody other than the subscription creator, it annoys me that you now want 
the subscription creator's privileges to be what the subscription runs as.  
That seems to undo what I worked on.  In my mental model of a 
(superuser-creator, non-superuser-owner) pair, it seems you're logically only 
touching the lefthand side, so you should then have a (nonsuperuser-creator, 
nonsuperuser-owner) pair.  But you don't.  You go the apparently needless extra 
step of just squashing them together.  I just don't see why it needs to be like 
that.

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-01-30 Thread Robert Haas
On Mon, Jan 30, 2023 at 1:46 PM Mark Dilger
 wrote:
> I have a grim view of the requirement that publishers and subscribers trust 
> each other.  Even when they do trust each other, they can firewall attacks by 
> acting as if they do not.

I think it's OK if the CREATE PUBLICATION user doesn't particularly
trust the CREATE SUBSCRIPTION user, because the publication is just a
grouping of tables to which somebody can pay attention or not. The
CREATE PUBLICATION user isn't compromised either way. But, at least as
things stand, I don't see how the CREATE SUBSCRIPTION user get away
with not trusting the CREATE PUBLICATION user. CREATE SUBSCRIPTION
provides no tools at all for filtering the data that the subscriber
chooses to send.

Now that can be changed, I suppose, and a run-as user would be one way
to make progress in that direction. But I'm not sure how viable that
is, because...

> > In what
> > circumstances would be it be reasonable to give responsibility for
> > those objects to different and especially mutually untrusting users?
>
> When public repositories of data, such as the IANA whois database, publish 
> their data via postgres publications.

... for that to work, IANA would need to set up the database so that
untrusted parties can create logical replication slots on their
PostgreSQL server. And I think that granting REPLICATION privilege on
your database to random people on the Internet is not really viable,
nor intended to be viable.  As the CREATE ROLE documentation says, "A
role having the REPLICATION attribute is a very highly privileged
role."

Concretely, this kind of setup would have the problem that you could
kill the IANA database by just creating a replication slot and then
not using it (or replicating from it only very very slowly).
Eventually, the replication slot would either hold back xmin enough
that you got a lot of bloat, or cause enough WAL to be retained that
you ran out of disk space. Maybe you could protect yourself against
that kind of problem by cutting off users who get too far behind, but
that also cuts off people who just have an outage for longer than your
cutoff.

Also, anyone who can connection to a replication slot can also connect
to any other replication slot, and drop any replication slot. So if
IANA did grant REPLICATION privilege to random people on the Internet,
one of them could jump into the system and screw things up for all the
others.

This kind of setup just doesn't seem viable to me.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-30 Thread Mark Dilger



> On Jan 30, 2023, at 9:26 AM, Robert Haas  wrote:
> 
> So basically this doesn't really feel like a valid scenario to me.
> We're supposed to believe that Alice is hostile to Bob, but the
> superuser doesn't seem to have thought very carefully about how Bob is
> supposed to defend himself against Alice, and Bob doesn't even seem to
> be trying. Maybe we should rename the users to Samson and Delilah? :-)

No, Atahualpa and Pizarro.

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-01-30 Thread Mark Dilger



> On Jan 30, 2023, at 9:26 AM, Robert Haas  wrote:
> 
> First, it doesn't seem to make a lot of sense to have one person
> managing the publications and someone else managing the subscriptions,
> and especially if those parties are mutually untrusting. I can't think
> of any real reason to set things up that way. Sure, you could, but why
> would you? You could, equally, decide that one member of your
> household was going to decide what's for dinner every night, and some
> other member of your household was going to decide what gets purchased
> at the grocery store each week. If those two people exercise their
> responsibilities without tight coordination, or with hostile intent
> toward each other, things are going to go badly, but that's not an
> argument for putting a combination lock on the flour canister. It's an
> argument for getting along better, or not having such a dumb system in
> the first place. I don't quite see how the situation you postulate in
> (A) and (B) is any different. Publications and subscriptions are as
> closely connected as food purchases and meals. The point of a
> publication is for it to connect up to a subscription.

I have a grim view of the requirement that publishers and subscribers trust 
each other.  Even when they do trust each other, they can firewall attacks by 
acting as if they do not.

> In what
> circumstances would be it be reasonable to give responsibility for
> those objects to different and especially mutually untrusting users?

When public repositories of data, such as the IANA whois database, publish 
their data via postgres publications.

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-01-30 Thread Robert Haas
On Mon, Jan 30, 2023 at 11:11 AM Mark Dilger
 wrote:
> > On Jan 30, 2023, at 7:44 AM, Robert Haas  wrote:
> >
> > And if we suppose that
> > that already works and is safe, well then what's the case where I do
> > need a run-as user?
>
> A) Alice publishes tables, and occasionally adds new tables to existing 
> publications.
>
> B) Bob manages subscriptions, and periodically runs "refresh publication".  
> Bob also creates new subscriptions for people when a row is inserted into the 
> "please create a subscription for me" table which Bob owns, using a trigger 
> that Bob created on that table.
>
> C) Alice creates a "please create a subscription for me" table on the 
> publishing database, adds lots of malicious requests, and adds that table to 
> the publication.
>
> D) Bob replicates the table, fires the trigger, creates the malicious 
> subscriptions, and starts replicating all that stuff, too.
>
> I think that having Charlie, not Bob, as the "run-as" user helps somewhere 
> right around (D).

I suppose it does, but I have some complaints.

First, it doesn't seem to make a lot of sense to have one person
managing the publications and someone else managing the subscriptions,
and especially if those parties are mutually untrusting. I can't think
of any real reason to set things up that way. Sure, you could, but why
would you? You could, equally, decide that one member of your
household was going to decide what's for dinner every night, and some
other member of your household was going to decide what gets purchased
at the grocery store each week. If those two people exercise their
responsibilities without tight coordination, or with hostile intent
toward each other, things are going to go badly, but that's not an
argument for putting a combination lock on the flour canister. It's an
argument for getting along better, or not having such a dumb system in
the first place. I don't quite see how the situation you postulate in
(A) and (B) is any different. Publications and subscriptions are as
closely connected as food purchases and meals. The point of a
publication is for it to connect up to a subscription. In what
circumstances would be it be reasonable to give responsibility for
those objects to different and especially mutually untrusting users?

Second, in step (B), we may ask why Bob is doing this with a trigger.
If he's willing to create any subscription for which Alice asks, we
could have just given Alice the authority to do those actions herself.
Presumably, therefore, Bob is willing to create some subscriptions for
which Alice may ask and not others. Perhaps this whole arrangement is
just a workaround for the lack of a sensible system for controlling
which connection strings Alice can use, in which case what is really
needed here might be something like the separate connection object
which Jeff postulated or my idea of a reverse pg_hba.conf. That kind
of approach would give a better user interface to Alice, who wouldn't
have to rephrase all of her CREATE SUBSCRIPTION commands as insert
statements. Conversely, if Alice and Bob are truly dedicated to this
convoluted system of creating subscriptions, then Bob needs to put
logic into his trigger that's smart enough to block any malicious
requests that Alice may make. He really brought this problem on
himself by not doing that.

Third, in step (C), it seems to me that whoever set up Alice's
permissions has really messed up. Either the schema Bob is using for
his create-me-a-subscription table exists on the primary and Alice has
permission to create tables in that schema, or else that schema does
not exist on the primary and Alice has permission to create it. Either
way, that's a bad setup. Bob's table should be located in a schema for
which Alice has only USAGE permissions and shouldn't have excess
permissions on the table, either. Then this step can't happen. This
step could also be blocked if, instead of using a table with a
trigger, Bob wrote a security definer function or procedure and
granted EXECUTE permission on that function or procedure to Alice.
He's still going to need sanity checks, though, and if the function or
procedure inserts into a logging table or something, he'd better make
sure that table is adequately secured rather than being, say, a table
owned by Alice with malicious triggers on it.

So basically this doesn't really feel like a valid scenario to me.
We're supposed to believe that Alice is hostile to Bob, but the
superuser doesn't seem to have thought very carefully about how Bob is
supposed to defend himself against Alice, and Bob doesn't even seem to
be trying. Maybe we should rename the users to Samson and Delilah? :-)

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-30 Thread Mark Dilger



> On Jan 30, 2023, at 7:44 AM, Robert Haas  wrote:
> 
> And if we suppose that
> that already works and is safe, well then what's the case where I do
> need a run-as user?

A) Alice publishes tables, and occasionally adds new tables to existing 
publications.

B) Bob manages subscriptions, and periodically runs "refresh publication".  Bob 
also creates new subscriptions for people when a row is inserted into the 
"please create a subscription for me" table which Bob owns, using a trigger 
that Bob created on that table.

C) Alice creates a "please create a subscription for me" table on the 
publishing database, adds lots of malicious requests, and adds that table to 
the publication.

D) Bob replicates the table, fires the trigger, creates the malicious 
subscriptions, and starts replicating all that stuff, too.

I think that having Charlie, not Bob, as the "run-as" user helps somewhere 
right around (D). 

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-01-30 Thread Robert Haas
On Fri, Jan 27, 2023 at 5:56 PM Mark Dilger
 wrote:
> If the owner cannot modify the subscription, then the owner degenerates into 
> a mere "run-as" user.  Note that this isn't how things work now, and even if 
> we disallowed owners from modifying the connection string, there would still 
> be other attributes the owner could modify, such as the set of publications 
> subscribed.

The proposed patch blocks every form of ALTER SUBSCRIPTION if
password_required false is set and you aren't a superuser. Is there
some other DML command that could be used to modify the set of
publications subscribed?

> More generally, my thinking on this thread is that there needs to be two 
> nosuperuser roles:  A higher privileged role which can create a subscription, 
> and a lower privileged role serving the "run-as" function.  Those shouldn't 
> be the same, because the "run-as" concept doesn't logically need to have 
> subscription creation power, and likely *shouldn't* have that power.  
> Depending on which sorts of attributes a subscription object has, such as the 
> connection string, the answer differs for whether the owner/"run-as" user 
> should get to change those attributes.  One advantage of Jeff's idea of using 
> a server object rather than a string is that it becomes more plausibly safe 
> to allow the subscription owner to make changes to that attribute of the 
> subscription.

There's some question in my mind about what these different mechanisms
are intended to accomplish.

On a technical level, I think that the idea of having a separate
objection for the connection string vs. the subscription itself is
perfectly sound, and to repeat what I said earlier, if someone wants
to implement that, cool. I also agree that it has the advantage that
you specify, namely, that someone can have rights to modify one of
those objects but not the other. What that lets you do is define a
short list of known systems and say, hey, you can replicate whatever
tables you want with whatever options you want, but only between these
systems. I'm not quite sure what problem that solves, though.

>From my point of view, the two things that the superuser is most
likely to want to do are (1) control the replication setup themselves
and delegate nothing to any non-superuser or (2) give a non-superuser
pretty much complete control over replication with just enough
restrictions to avoid letting them do things that would compromise
security, such as hacking the local superuser account. In other words,
I expect that delegation of the logical replication configuration is
usually going to be all or nothing. Jeff's system allows for a
situation where you want to delegate some stuff but not everything,
and specifically where you want to dedicate control over the
subscription options and the tables being replicated, but not the
connection strings. To me, that feels like a bit of an awkward
configuration; I don't really understand in what situation that
division of responsibility would be particularly useful. I trust that
Jeff is proposing it because he knows of such a situation, but I don't
know what it is. I feel like, even if I wanted to let people use some
connection strings and not others, I'd probably want that control in
some form other than listing a specific list of allowable connection
strings -- I'd want to say things like "you have to use SSL" or "no
connecting back to the local host," because that lets me enforce some
general organizational policy without having to care specifically
about how each subscription is being set up.

Unfortunately, I have even less of an idea about what the run-as
concept is supposed to accomplish. I mean, at one level, I see it
quite clearly: the user creating the subscription wants replication to
have restricted privileges when it's running, and so they make the
run-as user some role with fewer privileges than their own. Brilliant.
But then I get stuck: against what kind of attack does that actually
protect us? If I'm a high privilege user, perhaps even a superuser,
and it's not safe to have logical replication running as me, then it
seems like the security model of logical replication is fundamentally
busted and we need to fix that. It can't be right to say that if you
have 263 users in a database and you want to replicate the whole
database to some other node, you need 263 different subscriptions with
a different run-as user for each. You need to be able to run all of
that logical replication as the superuser or some other high-privilege
user and not end up with a security compromise. And if we suppose that
that already works and is safe, well then what's the case where I do
need a run-as user?

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-27 Thread Mark Dilger



> On Jan 27, 2023, at 1:35 PM, Robert Haas  wrote:
> 
>> I started out asking what benefits it provides to own a subscription one
>> cannot modify. But I think it is a good capability to have, to restrict the
>> set of relations that replication could target.  Although perhaps it'd be
>> better to set the "replay user" as a separate property on the subscription?
> 
> That's been proposed previously, but for reasons I don't quite
> remember it seems not to have happened. I don't think it achieved
> consensus.
> 
>> Does owning a subscription one isn't allowed to modify useful outside of 
>> that?
> 
> Uh, possibly that's a question for Mark or Jeff. I don't know. I can't
> see what they would be, but I just work here.

If the owner cannot modify the subscription, then the owner degenerates into a 
mere "run-as" user.  Note that this isn't how things work now, and even if we 
disallowed owners from modifying the connection string, there would still be 
other attributes the owner could modify, such as the set of publications 
subscribed.


More generally, my thinking on this thread is that there needs to be two 
nosuperuser roles:  A higher privileged role which can create a subscription, 
and a lower privileged role serving the "run-as" function.  Those shouldn't be 
the same, because the "run-as" concept doesn't logically need to have 
subscription creation power, and likely *shouldn't* have that power.  Depending 
on which sorts of attributes a subscription object has, such as the connection 
string, the answer differs for whether the owner/"run-as" user should get to 
change those attributes.  One advantage of Jeff's idea of using a server object 
rather than a string is that it becomes more plausibly safe to allow the 
subscription owner to make changes to that attribute of the subscription.



—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company







Re: Non-superuser subscription owners

2023-01-27 Thread Andres Freund
Hi,

On 2023-01-27 16:35:11 -0500, Robert Haas wrote:
> > Maybe a daft question:
> >
> > Have we considered using a "normal grant", e.g. on the database, instead of 
> > a
> > role?  Could it e.g. be useful to grant a user the permission to create a
> > subscription in one database, but not in another?
> 
> Potentially, but I didn't think we'd want to burn through permissions
> bits that fast, even given 7b378237aa805711353075de142021b1d40ff3b0.
> Still, if the consensus is otherwise, I can change it.

I don't really have an opinion on what's better. I looked briefly whether
there was discussion around ithis but I didn't see anything.

pg_create_subcription feels a bit different than most of the other pg_*
roles. For most of those there is no schema object to tie permissions to. But
here there is.

But I think there's good arguments against a GRANT approach, too. GRANT ALL ON
DATABASE would suddenly be dangerous. How does it interact with database
ownership? Etc.


> Then I guess we'd end up with GRANT CREATE ON DATABASE and GRANT CREATE
> SUBSCRIPTION ON DATABASE, which I'm sure wouldn't be confusing at all.

Heh. I guess it could just be GRANT SUBSCRIBE.



> Or, another thought, maybe this should be checking for CREATE on the
> current database + also pg_create_subscription. That seems like it
> might be the right idea, actually.

Yes, that seems like a good idea.



> > The subscription code already does ownership checks before locking and now
> > there's also the passwordrequired before.  Is it possible that this could 
> > open
> > up some sort of race? Could e.g. the user change the ownership to the
> > superuser in one session, do an ALTER in the other?
> >
> > It looks like your change won't increase the danger of that, as the
> > superuser() check just checks the current users permissions.
> 
> I'm not entirely clear whether there's a hazard there.

I'm not at all either. It's just a code pattern that makes me anxious - I
suspect there's a few places it makes us more vulnerable.


> If there is, I think we could fix it by moving the LockSharedObject call up
> higher, above object_ownercheck. The only problem with that is it lets you
> lock an object on which you have no permissions: see
> 2ad36c4e44c8b513f6155656e1b7a8d26715bb94. To really fix that, we'd need an
> analogue of RangeVarGetRelidExtended.

Yea, we really should have something like RangeVarGetRelidExtended() for other
kinds of objects. It'd take a fair bit of work / time to use it widely, but
it'll take even longer if we start in 5 years ;)

Perhaps the bulk of RangeVarGetRelidExtended() could be generalized by having
a separate name->oid lookup callback?

Greetings,

Andres Freund




Re: Non-superuser subscription owners

2023-01-27 Thread Robert Haas
On Fri, Jan 27, 2023 at 4:09 PM Andres Freund  wrote:
> Hm, compared to postgres_fdw, the user has far less control over what's
> happening using that connection. Is there a way a subscription owner can
> trigger evaluation of near-arbitrary SQL on the publisher side?

I'm not aware of one, but what I think it would let you do is
exfiltrate data you're not entitled to see.

> I started out asking what benefits it provides to own a subscription one
> cannot modify. But I think it is a good capability to have, to restrict the
> set of relations that replication could target.  Although perhaps it'd be
> better to set the "replay user" as a separate property on the subscription?

That's been proposed previously, but for reasons I don't quite
remember it seems not to have happened. I don't think it achieved
consensus.

> Does owning a subscription one isn't allowed to modify useful outside of that?

Uh, possibly that's a question for Mark or Jeff. I don't know. I can't
see what they would be, but I just work here.

> Maybe a daft question:
>
> Have we considered using a "normal grant", e.g. on the database, instead of a
> role?  Could it e.g. be useful to grant a user the permission to create a
> subscription in one database, but not in another?

Potentially, but I didn't think we'd want to burn through permissions
bits that fast, even given 7b378237aa805711353075de142021b1d40ff3b0.
Still, if the consensus is otherwise, I can change it. Then I guess
we'd end up with GRANT CREATE ON DATABASE and GRANT CREATE
SUBSCRIPTION ON DATABASE, which I'm sure wouldn't be confusing at all.

Or, another thought, maybe this should be checking for CREATE on the
current database + also pg_create_subscription. That seems like it
might be the right idea, actually.

> The subscription code already does ownership checks before locking and now
> there's also the passwordrequired before.  Is it possible that this could open
> up some sort of race? Could e.g. the user change the ownership to the
> superuser in one session, do an ALTER in the other?
>
> It looks like your change won't increase the danger of that, as the
> superuser() check just checks the current users permissions.

I'm not entirely clear whether there's a hazard there. If there is, I
think we could fix it by moving the LockSharedObject call up higher,
above object_ownercheck. The only problem with that is it lets you
lock an object on which you have no permissions: see
2ad36c4e44c8b513f6155656e1b7a8d26715bb94. To really fix that, we'd
need an analogue of RangeVarGetRelidExtended.

> and throwing an error like that will at the very least leak the connection,
> fd, fd reservation. Which I just had fixed :). At the very least you'd need to
> copy the stuff that "bad_connection:" does.

OK.

> I did wonder whether we should make libpqrcv_connect() use errsave() to return
> errors.  Or whether we should make libpqrcv register a memory context reset
> callback that'd close the libpq connection.

Yeah. Using errsave() might be better, but not sure I want to tackle
that just now.

> That is a somewhat odd API.  Why does it throw for some things, but not
> others? Seems a bit cleaner to pass in a parameter indicating whether it
> should throw when not finding a password? Particularly because you already
> pass that to walrcv_connect().

Will look into that.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-27 Thread Andres Freund
Hi,

On 2023-01-27 14:42:01 -0500, Robert Haas wrote:
> At first, I found it a bit tempting to see this as a further
> indication that the force-a-password approach is not the right idea,
> because the test case clearly memorializes a desire *not* to require a
> password in this situation. However, the loopback-to-superuser attack
> is just as viable for subscription as it in other cases, and my
> previous patch would have done nothing to block it.

Hm, compared to postgres_fdw, the user has far less control over what's
happening using that connection. Is there a way a subscription owner can
trigger evaluation of near-arbitrary SQL on the publisher side?


> So what I did instead is add a password_required attribute, just like what
> postgres_fdw has. As in the case of postgres_fdw, the actual rule is that if
> the attribute is false, a password is not required, and if the attribute is
> true, a password is required unless you are a superuser.  If you're a
> superuser, it still isn't. This is a slightly odd set of semantics but it
> has precedent and practical advantages. Also, as in the case of
> postgres_fdw, only a superuser can set password_required=false, and a
> subscription that has that setting can only be modified by a superuser, no
> matter who owns it.

I started out asking what benefits it provides to own a subscription one
cannot modify. But I think it is a good capability to have, to restrict the
set of relations that replication could target.  Although perhaps it'd be
better to set the "replay user" as a separate property on the subscription?

Does owning a subscription one isn't allowed to modify useful outside of that?



> Even though I hate the require-a-password stuff with the intensity of
> a thousand suns, I think this is better than the previous patch,
> because it's more consistent with what we do elsewhere and because it
> blocks the loopback-connection-to-superuser attack. I think we
> *really* need to develop a better system for restricting proxied
> connections (no matter how proxied) and I hope that we do that soon.
> But inventing something for this purpose that differs from what we do
> elsewhere will make that task harder, not easier.
> 
> Thoughts?

I think it's reasonable to mirror behaviour from elsewhere, and it'd let us
have this feature relatively soon - I think it's a common need to do this as a
non-superuser. It's IMO a very good idea to not subscribe as a superuser, even
if set up by a superuser...

But I also would understand if you / somebody else chose to focus on
implementing a less nasty connection model.


> Subject: [PATCH v2] Add new predefined role pg_create_subscriptions.

Maybe a daft question:

Have we considered using a "normal grant", e.g. on the database, instead of a
role?  Could it e.g. be useful to grant a user the permission to create a
subscription in one database, but not in another?


> @@ -1039,6 +1082,16 @@ AlterSubscription(ParseState *pstate, 
> AlterSubscriptionStmt *stmt,
>  
>   sub = GetSubscription(subid, false);
>  
> + /*
> +  * Don't allow non-superuser modification of a subscription with
> +  * password_required=false.
> +  */
> + if (!sub->passwordrequired && !superuser())
> + ereport(ERROR,
> + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
> +  
> errmsg("password_required=false is superuser-only"),
> +  errhint("Subscriptions with 
> the password_required option set to false may only be created or modified by 
> the superuser.")));
> +
>   /* Lock the subscription so nobody else can do anything with it. */
>   LockSharedObject(SubscriptionRelationId, subid, 0, AccessExclusiveLock);

The subscription code already does ownership checks before locking and now
there's also the passwordrequired before.  Is it possible that this could open
up some sort of race? Could e.g. the user change the ownership to the
superuser in one session, do an ALTER in the other?

It looks like your change won't increase the danger of that, as the
superuser() check just checks the current users permissions.


> @@ -180,6 +180,13 @@ libpqrcv_connect(const char *conninfo, bool logical, 
> const char *appname,
>   if (PQstatus(conn->streamConn) != CONNECTION_OK)
>   goto bad_connection_errmsg;
>  
> + if (must_use_password && !PQconnectionUsedPassword(conn->streamConn))
> + ereport(ERROR,
> + 
> (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
> +  errmsg("password is required"),
> +  errdetail("Non-superuser cannot connect if the 
> server does not request a password."),
> +  errhint("Target server's authentication method 
> must be changed.")));
> +

The documentation of libpqrcv_connect() says that:
 * Returns NULL on error and fills the err with 

Re: Non-superuser subscription owners

2023-01-27 Thread Robert Haas
On Thu, Jan 19, 2023 at 8:46 PM Andres Freund  wrote:
> > If we already had (or have) that logic someplace else, it would
> > probably make sense to reuse it
>
> We hve. See at least postgres_fdw's check_conn_params(), dblink's
> dblink_connstr_check() and dblink_security_check().

In the patch I posted previously, I had some other set of checks, more
or less along the lines suggested by Jeff. I looked into revising that
approach and making the behavior match exactly what we do in those
places instead. I find that it breaks 027_nosuperuser.pl.
Specifically, where without the patch I get "ok 6 - nosuperuser admin
with all table privileges can replicate into unpartitioned", with the
patch it goes boom, because the subscription can't connect any more
due to the password requirement.

At first, I found it a bit tempting to see this as a further
indication that the force-a-password approach is not the right idea,
because the test case clearly memorializes a desire *not* to require a
password in this situation. However, the loopback-to-superuser attack
is just as viable for subscription as it in other cases, and my
previous patch would have done nothing to block it. So what I did
instead is add a password_required attribute, just like what
postgres_fdw has. As in the case of postgres_fdw, the actual rule is
that if the attribute is false, a password is not required, and if the
attribute is true, a password is required unless you are a superuser.
If you're a superuser, it still isn't. This is a slightly odd set of
semantics but it has precedent and practical advantages. Also, as in
the case of postgres_fdw, only a superuser can set
password_required=false, and a subscription that has that setting can
only be modified by a superuser, no matter who owns it.

Even though I hate the require-a-password stuff with the intensity of
a thousand suns, I think this is better than the previous patch,
because it's more consistent with what we do elsewhere and because it
blocks the loopback-connection-to-superuser attack. I think we
*really* need to develop a better system for restricting proxied
connections (no matter how proxied) and I hope that we do that soon.
But inventing something for this purpose that differs from what we do
elsewhere will make that task harder, not easier.

Thoughts?

-- 
Robert Haas
EDB: http://www.enterprisedb.com


v2-0001-Add-new-predefined-role-pg_create_subscriptions.patch
Description: Binary data


Re: Non-superuser subscription owners

2023-01-26 Thread Robert Haas
On Thu, Jan 26, 2023 at 12:36 PM Jeff Davis  wrote:
> On Thu, 2023-01-26 at 09:43 -0500, Robert Haas wrote:
> > I have no issue with that as a long-term plan. However, I think that
> > for right now we should just introduce pg_create_subscription. It
> > would make sense to add pg_create_connection in the same patch that
> > adds a CREATE CONNECTION command (or whatever exact syntax we end up
> > with) -- and that patch can also change CREATE SUBSCRIPTION to
> > require
> > both privileges where a connection string is specified directly.
>
> I assumed it would be a problem to say that pg_create_subscription was
> enough to create a subscription today, and then later require
> additional privileges (e.g. pg_create_connection).
>
> If that's not a problem, then this sounds fine with me.

Wonderful! I'm working on a patch, but due to various distractions,
it's not done yet.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-26 Thread Jeff Davis
On Thu, 2023-01-26 at 09:43 -0500, Robert Haas wrote:
> I have no issue with that as a long-term plan. However, I think that
> for right now we should just introduce pg_create_subscription. It
> would make sense to add pg_create_connection in the same patch that
> adds a CREATE CONNECTION command (or whatever exact syntax we end up
> with) -- and that patch can also change CREATE SUBSCRIPTION to
> require
> both privileges where a connection string is specified directly.

I assumed it would be a problem to say that pg_create_subscription was
enough to create a subscription today, and then later require
additional privileges (e.g. pg_create_connection).

If that's not a problem, then this sounds fine with me.

-- 
Jeff Davis
PostgreSQL Contributor Team - AWS






Re: Non-superuser subscription owners

2023-01-26 Thread Robert Haas
On Wed, Jan 25, 2023 at 10:45 PM Jeff Davis  wrote:
> I propose that we have two predefined roles: pg_create_subscription,
> and pg_create_connection. If creating a subscription with a connection
> string, you'd need to be a member of both roles. But to create a
> subscription with a server object, you'd just need to be a member of
> pg_create_subscription and have the USAGE privilege on the server
> object.

I have no issue with that as a long-term plan. However, I think that
for right now we should just introduce pg_create_subscription. It
would make sense to add pg_create_connection in the same patch that
adds a CREATE CONNECTION command (or whatever exact syntax we end up
with) -- and that patch can also change CREATE SUBSCRIPTION to require
both privileges where a connection string is specified directly.

-- 
Robert Haas
EDB: http://www.enterprisedb.com




Re: Non-superuser subscription owners

2023-01-25 Thread Jeff Davis
On Tue, 2023-01-24 at 17:00 -0500, Robert Haas wrote:
> It seems to me that the relevant
> question isn't "are the servers tightly coupled?" but rather "could
> some user make a mess if we let them use any arbitrary connection
> string?".

The split I created is much easier for an admin to answer: is the list
of servers finite, or can users connect to new servers the admin isn't
even aware of? If it's a finite list, I feel there's a much better
solution with both security and UI benefits.

With your question, I'm not entirely clear if that's a question that we
already have an answer for (require a password parameter), or that we
will answer in this thread, or that the admin will answer.

> unless you've got users who are really shady 

Or compromised. Unfortunately, a role that's creating subscriptions has
a lot of surface area for escalation-of-privilege attacks, because they
have to trust all the owners of all the tables the subscriptions write
to.


> I think that you're basically trying to make an argument that some
> sort of complex outbound connection filtering is mandatory

No, I'm not asking for the validation to be more complex.

I believe use case (A) is a substantial use case, and I'd like to leave
space in the user interface to solve it a much better way than
connection string validation can offer. But to solve use case (A), we
need to separate the ability to create a subscription from the ability
to create a connection string.

Right now you see those as the same because they are done at the same
time in the same command; but I don't see it that way, because I had
plans to allow a variant of CREATE SUBSCRIPTION that uses foreign
servers. That plan would be consistent with dblink and postgres_fdw,
which already allow specifying foreign servers.

I propose that we have two predefined roles: pg_create_subscription,
and pg_create_connection. If creating a subscription with a connection
string, you'd need to be a member of both roles. But to create a
subscription with a server object, you'd just need to be a member of
pg_create_subscription and have the USAGE privilege on the server
object.


-- 
Jeff Davis
PostgreSQL Contributor Team - AWS






  1   2   3   >