Forbid the owner of a user from GRANTing on that table - postgresql

I'm trying to allow a database user to be able to alter/drop (certain) tables, but not GRANT privileges on them. Is this possible?
It looks like they need to be the owner of the tables, but from https://www.postgresql.org/docs/current/sql-grant.html
The right to drop an object, or to alter its definition in any way, is not treated as a grantable privilege; it is inherent in the owner, and cannot be granted or revoked. (However, a similar effect can be obtained by granting or revoking membership in the role that owns the object; see below.) The owner implicitly has all grant options for the object, too.
This sounds like it's not possible. However, is this definitely the case? Is there some way with triggers for example to make certain GRANTs fail?

Yes, only the owner of a table or a superuser can ALTER or DROP it, and these users can always GRANT privileges on the table.
Your only option is to create an event trigger that fires on GRANT and throws an error for the tables where it should be forbidden.

Related

Readonly admin user in postgresql

we have a postgres database we want to run a number of checks against. Part of the tool involves looping over database all the database tables and views, checking grants and other things - so it would be entirely pointless if we had to grant access to this user to individual tables.
We want to be able to create a user that has full read privileges to anything, regardless of what permissions are set in the database - like a db owner - but has no write access at all.
Is this possible in any way?
The only way to do this is granting the SELECT privilege on every individual object that needs to be examined. You can make the work easier with
GRANT SELECT ON ALL TABLES/SEQUENCES/... IN SCHEMA ... TO ...;
You can also use ALTER DEFAULT PRIVILEGES to set the permissions on future objects.
I recommend that you create a readonly role and do all that once. Then you can create a read-only user by making the user a member of that role.
With postgresql 14 you can just do:
GRANT pg_read_all_data TO my_role;
https://www.postgresql.org/docs/14/predefined-roles.html

PostgreSQL Error [42501]: ERROR: must be owner of relation table

I am maintaining a database 'db' in which there are around 100 tables.I have one super user 'A' and 'A' is the owner of all tables. How can I give Alter permission to new user 'B' specific to single table without inheriting all permissions from 'A'.
I tried by providing Grant A to B;. This Grant option given all permissions from 'A' to 'B'. I want above scenario to restrict to one particular table.
Is this possible?
The documentation recently acquired this explanation:
The right to modify or destroy an object is inherent in being the object's owner, and cannot be granted or revoked in itself. (However, like all privileges, that right can be inherited by members of the owning role; see Section 21.3.)
So the only people who can run ALTER TABLE are:
Superusers
the table owner
members of the table owner role
So GRANT a TO b is the only way to give somebody the privilege.
You might be able to use a SECURITY DEFINER function that belongs to a, but be careful with that.

postgreSQL: How to use ROLE to allow full access to all users part of a given role (without using SET ROLE prior accessing a table for instance)

I'm coming to postgreSQL with a SQL Server background and was naively applying the same concepts to postgreSQL in order to allow different users to share 'by default' some objects within a database.
This is what I did:
CREATE DATABASE testdb;
CREATE ROLE testdb_role_full INHERIT;
GRANT ALL PRIVILEGES ON DATABASE testdb TO testdb_role_full;
CREATE USER user1 INHERIT;
GRANT testdb_role_full TO user1;
CREATE USER user2 INHERIT;
GRANT testdb_role_full TO user2;
Once done, I created a table t1 using the user1.
Then, I tried, as user2, to read the t1 table and I received a "permission denied error"... :-(
By reading the documentation, it seems that I have to issue a SET ROLE testdb_role_full first so as to act as the testdb_role_full.
However, this is not really that I want. I do not want the user to be aware of this.
So my question:
Is there any way to make this work?
Thanks a lot,
José
You've granted some privileges on the database, but that doesn't mean any user with the role testdb_role_full would have all privileges on all objects inside that database. To quote from the documentation:
When an object is created, it is assigned an owner. The owner is normally the role that executed the creation statement. For most kinds of objects, the initial state is that only the owner (or a superuser) can do anything with the object. To allow other roles to use it, privileges must be granted.
So after the user1 created the table t1, he is the owner and only he has the privileges on it. He would need to run
GRANT ALL PRIVILEGES ON TABLE t1 TO testdb_role_full;
then user2 would be able to access it as well (without having to switch any roles - that's only necessary when it has the NOINHERIT attribute on the role).
If you don't want your users to have to execute GRANT each time they create a new object in the database, you can alter the default privileges that will be applied whenever an object is created by user2:
ALTER DEFAULT PRIVILEGES FOR user2
GRANT ALL PRIVILEGES ON TABLES TO testdb_role_full;
Notice these specify the initial value only, and user2 could revoke the privileges on his tables if he wanted to prevent others from seeing them.

Locking down Public Group Role in PostgreSQL

Based on information I've been reading about privileges, I've learned it was good to revoke privileges before assigning any privileges to roles.
I had 1 user I was working with called appuser and I did the following:
REVOKE ALL PRIVILEGES ON SCHEMA PUBLIC FROM GROUP PUBLIC;
GRANT SELECT
ON public.table1 TO appuser;
GRANT SELECT
ON public.table1_id_seq TO appuser;
GRANT SELECT
ON public.table2 TO appuser;
GRANT SELECT
ON public.table2_id_seq TO appuser;
I did this in the hopes of removing any privileges to attached to any newly added users automatically part of the public role membership. Instead I got an error to the effect of appuser does not have permissions to the schema. However this is my misunderstanding with this error.
1. PgAdminIII doesn't show a public role under Group Roles for this schema
2. appuser does not appear to be a member of a group called public (because it doesn't exist in the interface).
3. appuser's privileges were explicitly granted, even if it were part of the public role
So...is there some sort of implicit group role called "Public" that is affecting this user's privileges? I don't understand what's going on. I've also attempted to find out where to display the group role membership from the pgAdminIII command line with no luck there either. By the way to fix it, I simply reversed the first command (i.e. GRANT ALL PRIVILEGES ON SCHEMA PUBLIC TO GROUP PUBLIC); However that basically undoes what I was originally trying to do (i.e. simply lock down the tables).
Any ideas?
Update: I have a hunch, I discovered what the issue may be. I don't think appuser has permissions to the schema. If I'm not mistaken schema permissions must be granted before access to any objects beneath the schema can happen.
Ok, so the answer here is kind of complicated as to why things behave the way they do and it is probably worth discussing the PostgreSQL security model to some extent.
PUBLIC is not a role or a group but rather a reserved word. The way the permissions work is that access granted to current inherited roles or PUBLIC apply. I have actually been bitten by this in the past as I build frameworks that wrap PostgreSQL roles.
In general, my view is that you want to do as follows:
Don't allow everyone to log into the db.
REVOKE CONNECT ON DATABASE mydb FROM public;
You may want to revoke access to schemas and tables from public too.
What I think you have done is something else, which is to revoke permissions from the schema (but not the tables in the schema!) and therefore reserve PUBLIC access for default permissions to tables in that schema. This may or may not be what you want. At any rate as you found out you need to add back permissions to the schema to get back to where you are.
Now I am not entirely sure what you are trying to do here. If you want to fully lock down your db, you need to do the same for all tables as well. Otherwise if you:
CREATE USER foo;
GRANT USAGE ON SCHEMA PUBLIC TO foo;
Then foo will have access to all the permissions that PUBLIC has on the tables.

Grant privileges to all users, current and future

I have a multi-schema, multi-user Postgres DB. There is one table that I would like ALL users, both current and future, to be able to SELECT from.
I can GRANT SELECT to all current users... but how can I create a table that allows any future user to select? Is there a way to set table permissions, rather than granting user privileges?
A filesystem analogy would be using chmod to make a file to be readable by the public.
grant select on the_table to public;
From the manual:
The key word PUBLIC indicates that the privileges are to be granted to all roles, including those that might be created later. PUBLIC can be thought of as an implicitly defined group that always includes all roles