Re: CREATEROLE and role ownership hierarchies - Mailing list pgsql-hackers

From Michael Banck
Subject Re: CREATEROLE and role ownership hierarchies
Date
Msg-id 32313a176ab33b47eed2a2084b99dd36ff4195db.camel@credativ.de
Whole thread Raw
In response to Re: CREATEROLE and role ownership hierarchies  (Mark Dilger <mark.dilger@enterprisedb.com>)
Responses Re: CREATEROLE and role ownership hierarchies
List pgsql-hackers
Hi,

Am Sonntag, dem 30.01.2022 um 17:11 -0800 schrieb Mark Dilger:
> > On Jan 30, 2022, at 2:38 PM, Michael Banck <   
> > michael.banck@credativ.de> wrote:
> > > The attached WIP patch attempts to solve most of the CREATEROLE
> 
> I'm mostly looking for whether the general approach in this Work In
> Progress patch is acceptable, so I was a bit sloppy with whitespace
> and such....

Ok, sure. I think this topic is hugely important and as I read the
patch anyway, I added some comments, but yeah, we need to figure out
the fundamentals first.
> 

> > One thing I noticed (and which will likely make DBAs grumpy) is that it
> > seems being able to create users (as opposed to non-login roles/groups)
> > depends on when you get the CREATEROLE attribute (on role creation or
> > later), viz:
> > 
> > postgres=# CREATE USER admin CREATEROLE;
> > CREATE ROLE
> > postgres=# SET ROLE admin;
> > SET
> > postgres=> CREATE USER testuser; -- this works
> > CREATE ROLE
> > postgres=> RESET ROLE;
> > RESET
> > postgres=# CREATE USER admin2;
> > CREATE ROLE
> > postgres=# ALTER ROLE admin2 CREATEROLE; -- we get CREATEROLE after the fact
> > ALTER ROLE
> > postgres=# SET ROLE admin2;
> > SET
> > postgres=> CREATE USER testuser2; -- bam
> > ERROR:  must have grant option on LOGIN privilege to create login users
> > postgres=# SELECT rolname, admcreaterole, admcanlogin FROM
> > pg_authid
> > WHERE rolname LIKE 'admin%';
> > rolname | admcreaterole | admcanlogin 
> > ---------+---------------+-------------
> > admin   | t             | t
> > admin2  | f             | f
> > (2 rows)
> > 
> > Is that intentional? If it is, I think it would be nice if this
> > could be
> > changed, unless I'm missing some serious security concerns or so. 
> 
> It's intentional, but part of what I wanted review comments about. 
> The issue is that historically:
> 
>   CREATE USER michael CREATEROLE
> 
> meant that you could go on to do things like create users with LOGIN
> privilege.  I could take that away, which would be a backwards
> compatibility break, or I can do the weird thing this patch does.  Or
> I could have your
> 
>   ALTER ROLE admin2 CREATEROLE;
> 
> also grant the other privileges like LOGIN unless you explicitly say
> otherwise with a bunch of explicit WITHOUT ADMIN OPTION clauses. 
> Finding out which of those this is preferred was a big part of why I
> put this up for review.  Thanks for calling it out in under 24 hours!

Ok, so what I would have needed to do in the above in order to have
"admin2" and "admin" be the same as far as creating login users is (I
believe):

ALTER ROLE admin2 CREATEROLE LOGIN WITH ADMIN OPTION;

I think if possible, it would be nice to just have this part as default
if possible. I.e. CREATEROLE and HASLOGIN are historically so much
intertwined that I think the above should be implicit (again, if that
is possible); I don't care and/or haven't made up my mind about any of
the other options so far...

Ok, so now that I had another look, I see we are going down Pandora's
box: For any of the other things a role admin would like to do (change
password, change conn limit), one would have to go with this weird
disconnect between CREATE USER admin CREATEROLE and ALTER USER admin2
CREATEROLE [massive list of WITH ADMIN OPTION], and then I'm not sure
where we stop.

By the way, is there now even a way to add admpassword to a role after
it got created?

postgres=# SET ROLE admin2;
SET
postgres=> \password test
Enter new password for user "test": 
Enter it again: 
ERROR:  must have admin on password to change password attribute
postgres=> RESET ROLE;
RESET
postgres=# ALTER ROLE admin2 PASSWORD WITH ADMIN OPTION;
ERROR:  syntax error at or near "WITH"
UPDATE pg_authid SET admpassword = 't' WHERE rolname = 'admin2';
UPDATE 1
postgres=# SET ROLE admin2;
SET
postgres=> \password test
Enter new password for user "test": 
Enter it again: 
postgres=> 

However, the next thing is:

postgres=# SET ROLE admin;
SET
postgres=> CREATE GROUP testgroup;
CREATE ROLE
postgres=> GRANT testgroup TO test;
ERROR:  must have admin option on role "testgroup"

First off, what does "admin option" mean on a role?

I then tried this:

postgres=# CREATE USER admin3 CREATEROLE WITH ADMIN OPTION;
CREATE ROLE
postgres=# SET ROLE admin3;
SET
postgres=> CREATE USER test3;
CREATE ROLE
postgres=> CREATE GROUP testgroup3;
CREATE ROLE
postgres=> GRANT testgroup3 TO test3;
ERROR:  must have admin option on role "testgroup3"

So I created both user and group, I have the CREATEROLE priv (with or
without admin option), but I still can't assign the group. Is that
(tracking who created a role and letting the creator do more thing) the
part that got chopped away in your last patch in order to find a common
ground?

Is there now any way non-Superusers can assign groups to other users? I
feel this (next to creating users/groups) is the primary thing those
CREATEROLE admins are supposed to do/where doing up to now.


Again, sorry if this was all discussed previously, I only skimmed this
thread.

Two more comments regarding the code:

> > > b/src/include/catalog/pg_authid.dat
> > > index 6c28119fa1..4829a6dbd2 100644
> > > --- a/src/include/catalog/pg_authid.dat
> > > +++ b/src/include/catalog/pg_authid.dat
> > > @@ -22,67 +22,93 @@
> > > { oid => '10', oid_symbol => 'BOOTSTRAP_SUPERUSERID',
> > >   rolname => 'POSTGRES', rolsuper => 't', rolinherit => 't',
> > >   rolcreaterole => 't', rolcreatedb => 't', rolcanlogin => 't',
> > > -  rolreplication => 't', rolbypassrls => 't', rolconnlimit =>
> > > '-1',
> > > +  rolreplication => 't', rolbypassrls => 't', adminherit => 't',
> > > admcreaterole => 't',
> > > +  admcreatedb => 't', admcanlogin => 't', admreplication => 't',
> > > admbypassrls => 't',
> > > +  admconnlimit => 't', admpassword => 't', admvaliduntil => 't',
> > > rolconnlimit => '-1',
> > >   rolpassword => '_null_', rolvaliduntil => '_null_' },
> > 
> > Those sure are a couple of new columns in pg_authid, but oh well...
> 
> Yes, that's also a big part of what people might object to.  I think
> it's a reasonable objection, but I don't know where else to put the
> information, given the lack of an aclitem[]?

Yeah, it crossed my mind that an array might not be bad. In any case,
if we can fix CREATEROLE for good, a couple of extra columns in
pg_authid might be a small price to pay.

diff --git a/src/include/catalog/pg_authid.h
> > > b/src/include/catalog/pg_authid.h
> > > index 4b65e39a1f..4acdcaa685 100644
> > > --- a/src/include/catalog/pg_authid.h
> > > +++ b/src/include/catalog/pg_authid.h
> > > @@ -39,6 +39,16 @@ CATALOG(pg_authid,1260,AuthIdRelationId)
> > > BKI_SHARED_RELATION BKI_ROWTYPE_OID(284
> > >         bool            rolcanlogin;    /* allowed to log in as
> > > session user? */
> > >         bool            rolreplication; /* role used for
> > > streaming replication */
> > >         bool            rolbypassrls;   /* bypasses row-level
> > > security? */
> > > +
> > > +       bool            adminherit;             /* allowed to
> > > administer inherit? */
> > > +       bool            admcreaterole;  /* allowed to administer
> > > createrole? */
> > > +       bool            admcreatedb;    /* allowed to administer
> > > createdb?? */
> > > +       bool            admcanlogin;    /* allowed to administer
> > > login? */
> > > +       bool            admreplication; /* allowed to administer
> > > replication? */
> > > +       bool            admbypassrls;   /* allowed to administer
> > > bypassesrls? */
> > > +       bool            admconnlimit;   /* allowed to administer
> > > connlimit? */
> > > +       bool            admpassword;    /* allowed to administer
> > > password? */
> > > +       bool            admvaliduntil;  /* allowed to administer
> > > validuntil? */
> > >         int32           rolconnlimit;   /* max connections
> > > allowed (-1=no limit) */
> > 
> > It's cosmetic, but the space between rolbypassrls and adminherit is
> > maybe not needed, and I'd put rolconnlimit first (even though it
> > has a different type).
> 
> Oh, totally agree.  I had that blank there during development because
> the "rol..." and "adm..." all started to blur together.

The way the adm* privs are now somewhere in the middle of the rol*
privs also looks weird for the end-user and there does not seems to be
some greater scheme behind it:

postgres=# SELECT * FROM pg_authid WHERE rolname = 'admin' \gx 
-[ RECORD 1 ]--+------
oid            | 16385
rolname        | admin
rolsuper       | f
rolinherit     | t
rolcreaterole  | t
rolcreatedb    | f
rolcanlogin    | t
rolreplication | f
rolbypassrls   | f
adminherit     | t
admcreaterole  | t
admcreatedb    | t
admcanlogin    | t
admreplication | f
admbypassrls   | f
admconnlimit   | t
admpassword    | t
admvaliduntil  | t
rolconnlimit   | -1
rolpassword    | 
rolvaliduntil  | 


Michael

-- 
Michael Banck
Teamleiter PostgreSQL-Team
Projektleiter
Tel.: +49 2166 9901-171
E-Mail: michael.banck@credativ.de

credativ GmbH, HRB Mönchengladbach 12080
USt-ID-Nummer: DE204566209
Trompeterallee 108, 41189 Mönchengladbach
Geschäftsführung: Dr. Michael Meskes, Geoff Richardson, Peter Lilley

Unser Umgang mit personenbezogenen Daten unterliegt
folgenden Bestimmungen: https://www.credativ.de/datenschutz




pgsql-hackers by date:

Previous
From: Kyotaro Horiguchi
Date:
Subject: Re: [PATCH] Accept IP addresses in server certificate SANs
Next
From: "Andrey V. Lepikhov"
Date:
Subject: Re: Multiple Query IDs for a rewritten parse tree