I am using PostgreSQL 10.4 and I found a strange behavior.
If we create an role and grant it to CONNECT the database:
CREATE ROLE dummy;
GRANT CONNECT ON DATABASE test TO dummy;
Then we cannot drop this role, even if it owns no object at all, this command:
DROP ROLE dummy;
Raises:
ERROR: role "dummy" cannot be dropped because some objects depend on it
SQL state: 2BP01
Detail: privileges for database test
Documentation is a bit misleading:
Class 2B — Dependent Privilege Descriptors Still Exist
2B000 dependent_privilege_descriptors_still_exist
2BP01 dependent_objects_still_exist
It says dependent objects still exist, but it seems there are no objects dependent to this specific role, it owns nothing on the database.
Anyway, if we revoke the CONNECT privilege, then role can be dropped:
REVOKE CONNECT ON DATABASE test FROM dummy;
DROP ROLE dummy;
I just checked the behavior also exists on PostgreSQL 9.5. I feel it a bit strange and I cannot understand why this specific privilege makes dropping role fails.
Additional observations
This is really blocking, because we can neither reassign this object:
REASSIGN OWNED BY dummy TO postgres;
Nor drop the object:
DROP OWNED BY dummy;
Both raise related errors:
ERROR: permission denied to reassign objects
SQL state: 42501
ERROR: permission denied to drop objects
SQL state: 42501
As #RaymondNijland pointed out, this must be because the CONNECT privileges is viewed as a role dependent object. The following query:
WITH
R AS (SELECT * FROM pg_roles WHERE rolname = 'dummy')
SELECT
D.*
FROM
R, pg_shdepend AS D
WHERE
refobjid = R.oid;
Returns a single row when CONNECT is granted:
"dbid";"classid";"objid";"objsubid";"refclassid";"refobjid";"deptype"
0;1262;27961;0;1260;27966;"a"
And no row at all when the privilege is revoked. This at least explain why we cannot reassign the object.
About the Dependency Type, the documentation states:
SHARED_DEPENDENCY_ACL (a)
The referenced object (which must be a role) is mentioned in the
ACL (access control list, i.e., privileges list) of the dependent
object. (A SHARED_DEPENDENCY_ACL entry is not made for the owner of
the object, since the owner will have a SHARED_DEPENDENCY_OWNER entry
anyway.)
But I have not enough insight to understand it clearly.
My question are:
Do Postgres always require to revoke privileges before dropping a role?
If not, why this specific privilege behaves like this?
There are some very unintuitive permission requirements when using REASSIGN.
I have found that when a superuser account is not available (as in the case of RDS or Cloud SQL) I have to grant the target role to my current role in order to reassign or drop owned objects from the target role. For instance, if my active user is postsgres, and I'm trying to remove user_a:
> DROP OWNED BY user_a
ERROR: permission denied to drop objects
> GRANT user_a TO postgres;
GRANT ROLE
> DROP OWNED BY user_a;
DROP OWNED
Now, it becomes a little trickier if user_a happens to be a member of postgres, especially if it happens to inherit that membership through some other role, let's call it schema_admin...
> DROP OWNED BY user_a
ERROR: permission denied to drop objects
> GRANT user_a TO postgres;
ERROR: role "user_a" is a member of role "postgres"
-- Alright, let's try to revoke it...
> REVOKE postgres FROM user_a;
REVOKE ROLE
> GRANT user_a TO postgres;
ERROR: role "user_a" is a member of role "postgres"
-- It's still a member through the inherited grant - trying to revoke again doesn't work:
> REVOKE postgres FROM user_a;
WARNING: role "user_a" is not a member of role "postgres"
REVOKE ROLE
-- So you have to identify the role it's inheriting from, and revoke that:
> REVOKE schema_admin FROM user_a;
REVOKE ROLE
> GRANT user_a TO postgres;
GRANT ROLE
-- Now just to be safe, I'll reassign owned objects before actually dropping everything:
> REASSIGN OWNED BY user_a TO postgres;
REASSIGN OWNED
> DROP OWNED BY user_a;
DROP OWNED
> DROP ROLE user_a;
DROP ROLE;
Voila!
Note: There is another widely-referenced and effective answer here: https://sysadmintips.com/services/databases/postgresql-error-permission-denied-to-reassign-objects/ which works great, as long as you are able to create and log in as a new temporary user. However, in some contexts, that is a problem in itself (and then you also have the extra cleanup to handle of removing that temporary role when you're done), so I tried to avoid that here.
Related
I was trying to delete PostgreSQL user:
DROP USER ryan;
I received this error:
Error in query:
ERROR: role "ryan" cannot be dropped because some objects depend on it
DETAIL: privileges for database mydatabase
I looked for a solution from these threads:
PostgreSQL - how to quickly drop a user with existing privileges
How to drop user in postgres if it has depending objects
Still have the same error.
This happens after I grant all permission to user "ryan" with:
GRANT ALL PRIVILEGES ON DATABASE mydatabase ON SCHEMA public TO ryan;
DROP USER (or DROP ROLE, same thing) cannot proceed while the role still owns anything or has any granted privileges on other objects.
Get rid of all privileges with DROP OWNED (which isn't too obvious from the wording). The manual:
[...] Any privileges granted to the given roles on objects in the current
database and on shared objects (databases, tablespaces) will also be revoked.
So the reliable sequence of commands to drop a role is:
REASSIGN OWNED BY ryan TO postgres; -- or some other trusted role
DROP OWNED BY ryan;
Run both commands in every database of the same cluster where the role owns anything or has any privileges!
And finally:
DROP USER ryan;
REASSIGN OWNED changes ownership for all objects currently owned by the role.
DROP OWNED then only revokes privileges (ownerships out of the way).
Alternatively, you can skip REASSIGN OWNED. Then DROP OWNED will (also) drop all objects owned by the user. (Are you sure?!)
Related:
Drop a role with privileges (with a function to generate commands for all relevant DBs)
Find objects linked to a PostgreSQL role
What worked for me was to follow these steps:
Connecting to the database
\c mydatabase
Reassigning ownership
REASSIGN OWNED BY ryan TO <newuser>;
Or/and just deleting the object
DROP OWNED BY ryan;
Executing REVOKE PRIVILEGES
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM ryan;
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM ryan;
REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public FROM ryan;
Dropping the user
DROP USER ryan;
PS: You might not need to execute both Step 2 and 3, just one of the two steps might be usually enough.
What worked for me on RDS Postgres 13:
REVOKE ALL PRIVILEGES ON DATABASE <my_db> FROM <my_user>;
I also had a similar error where the role was owner for tables so it couldn't be dropped, had to re-assign table owner with:
ALTER TABLE <my_table> OWNER TO <trusted_role>;
Doing a REASSIGN like this didn't work for me on RDS because AWS doesn't give you full superuser to your master user:
REASSIGN OWNED BY <olduser> TO <newuser>;
REVOKE ALL ON SCHEMA "public" FROM "<user>";
Worked for me.
What worked for me was to recreate template1 database and then drop some role:
$ psql -U postgres postgres
postgres=# update pg_database set datistemplate = false where datname='template1';
UPDATE 1
postgres=# drop database template1;
DROP DATABASE
postgres=# create database template1 template=template0;
CREATE DATABASE
postgres=# update pg_database set datistemplate = true where datname='template1';
UPDATE 1
postgres=# DROP ROLE test;
DROP ROLE
For people who use AWS Postgresql RDS, you may try following
login to postgres user, then grant owner
postgres=> GRANT target_user to old_user;
GRANT ROLE
Login to target db using user that would like to remove(old_user), then reassign
target_db=> REASSIGN OWNED BY old_user TO target_user;
REASSIGN OWNED
Login back to postgres user, revoke all privileges then drop user
postgres=> REVOKE ALL PRIVILEGES ON DATABASE target_db FROM old_user;
REVOKE
postgres=> DROP USER old_user;
DROP ROLE
Ref. https://aws.amazon.com/premiumsupport/knowledge-center/rds-postgresql-drop-user-role/
This looks like a very basic need, but I do not find any quick and suitable answer. I have a role in Postgres which has privileges to many other tables in various databases.
I need to drop this role. I have one postgres instance and then many databases on top of it.
SELECT DISTINCT 'REVOKE ALL ON TABLE ' || table_schema || '.' || table_name || ' FROM ' || r.param_role_name || ';'
FROM information_schema.table_privileges CROSS JOIN (SELECT 'some_role_name'::text AS param_role_name) r
WHERE grantee ~* r.param_role_name;
I can do like above, by going to each and every database and find all revoke statements and then drop the role. Is there any way I can find all revoke statements at one place for all the databases.
Or something like I can alter owned by this role, can I alter all privileges with one statement?
Edit1: As most of the replies are targeted to reassign owned by and drop owned by, I want to be more specific.
I can execute below commands on each database and drop the roles once all the dependencies are removed.
REASSIGN OWNED BY some_role_name TO postgres;
DROP OWNED BY some_role_name;
but there are many databases so I am looking for something forcefully flush all privileges and drop this role.
I need to drop this role.
Run this in every database of the same cluster where the role might own anything or have any granted privileges:
REASSIGN OWNED BY some_role_name TO postgres;
DROP OWNED BY some_role_name;
postgres being the default superuser, you can pick any other. It is going to own objects currently owned by the old role. Immediately after REASSIGN OWNED, there are no objects left that would be owned by the same user. It may seem unintuitive to run DROP OWNED. The wording of the command is misleading, since it also revokes all privileges and default privileges for the role in the same database. The manual:
DROP OWNED drops all the objects within the current database that are owned by one of the specified roles. Any privileges granted to the given roles on objects in the current database and on shared objects (databases, tablespaces) will also be revoked.
Bold emphasis mine.
You still have to execute it in every single database where the role owns anything or has any granted privileges. The manual:
Because REASSIGN OWNED does not affect objects within other databases, it is usually necessary to execute this command in each database that contains objects owned by a role that is to be removed.
Finally, run (once):
DROP role some_role_name;
Roles are stored in a cluster-wide system catalog, while ownership and privileges on objects are stored in database-local system catalogs.
Detailed explanation in this related answer:
Find objects linked to a PostgreSQL role
There is a related page in the manual with instructions.
Full automation
There is no single command to do it all. But you can let Postgres generate a complete psql script for you.
Dependencies for roles are stored in the system catalog pg_shdepend:
This information allows PostgreSQL to ensure that those objects are unreferenced before attempting to delete them.
Since we (potentially) need to connect to different databases, we need a combination of psql meta-commands (\c my_database) and SQL DDL commands as shown above. Create this function somewhere in your DB cluster once:
CREATE OR REPLACE FUNCTION f_generate_ddl_to_remove_role(dead_role_walking regrole)
RETURNS text
LANGUAGE sql AS
$func$
SELECT concat_ws(
E'\n'
,(SELECT string_agg(format(E'\\c %I\nREASSIGN OWNED BY %2$s TO postgres; DROP OWNED BY %2$s;'
, d.datname, dead_role_walking)
, E'\n')
FROM (
SELECT DISTINCT dbid
FROM pg_shdepend
WHERE refobjid = dead_role_walking
) s
JOIN pg_database d ON d.oid = s.dbid)
, format(E'DROP role %s;\n', dead_role_walking)
)
$func$;
Call:
SELECT f_generate_ddl_to_remove_role('some_role_name');
Produces a string like:
\c my_db1
REASSIGN OWNED BY some_role_name TO postgres; DROP OWNED BY some_role_name;
\c my_db2
REASSIGN OWNED BY some_role_name TO postgres; DROP OWNED BY some_role_name;
DROP role some_role_name;
Or, if the role does not own anything and has no privileges, just:
DROP role some_role_name;
If you provide a non-existing role name, you get an error.
Copy the string (without enclosing single quotes) to a psql session opened with a superuser like postgres. Or concatenate a bash script with it. All done.
There are several related answers with more explanation for dynamic SQL:
https://stackoverflow.com/search?q=%5Bplpgsql%5D+%5Bdynamic-sql%5D+string_agg
You cannot drop a role until there are dependent objects in any of the database.
You will have to reassign the objects owned by this user (some_role_name) to another user.
Once it is done for all objects in all the databases, you can then delete the user.
REASSIGN OWNED BY some_role_name TO some_other_role_name;
If the dependent objects are not required, you can also go ahead using DROP OWNED BY, removing all the object that are owned by some_role_name.
DROP OWNED BY some_role_name;
Database idd owner is role idd_owner.
Database has 2 data schemas: public and firma1.
User may have directly or indirectly assigned rights in this database and objects.
User is not owner of any object. It has only granted rights.
How to drops such user ?
I tried
revoke all on all tables in schema public,firma1 from "vantaa" cascade;
revoke all on all sequences in schema public,firma1 from "vantaa" cascade;
revoke all on database idd from "vantaa" cascade;
revoke all on all functions in schema public,firma1 from "vantaa" cascade;
revoke all on schema public,firma1 from "vantaa" cascade;
revoke idd_owner from "vantaa" cascade;
ALTER DEFAULT PRIVILEGES IN SCHEMA public,firma1 revoke all ON TABLES from "vantaa";
DROP ROLE if exists "vantaa"
but got error
role "vantaa" cannot be dropped because some objects depend on it
DETAIL: privileges for schema public
DROP ROLE if exists "vantaa"
How to fix this so that user can dropped ?
How to create sql or plpgsql method which takes user name as parameter and drops this user in all cases without dropping data ?
Using Postgres 9.1+
Before dropping the user you can run :
REASSIGN OWNED BY vantaa TO <newuser>
you could just reassign to postgres if you don't know who to reassign that to ...
REASSIGN OWNED BY vantaa TO postgres;
Your reassignment can fail.
When you reassign to a new user/role
- you do it on the currently selected database
- the current user must belong to the 'from' role and 'to' (grant them and revoke them after)
Excerpt of a shell script of mine (a few things omitted)
# The DROP USER operation will fail if this user is the owner of an existing schema, table, index...
# The user creating a resource owns it. It should transfer the ownership to the role
# When reassigning, the current user needs to have the <<roles>> associated to BY and TO to execute the command.
GRANT $_roleservice TO $_superuser;
GRANT $_account TO $_superuser;
REASSIGN OWNED BY $_account TO $_roleservice;
# dropping the user removes it from the current user list of roles/users
DROP USER $_account;
REVOKE $_roleservice FROM $_superuser;
I would like to give a user all the permissions on a database without making it an admin.
The reason why I want to do that is that at the moment DEV and PROD are different DBs on the same cluster so I don't want a user to be able to change production objects but it must be able to change objects on DEV.
I tried:
grant ALL on database MY_DB to group MY_GROUP;
but it doesn't seem to give any permission.
Then I tried:
grant all privileges on schema MY_SCHEMA to group MY_GROUP;
and it seems to give me permission to create objects but not to query\delete objects on that schema that belong to other users
I could go on by giving USAGE permission to the user on MY_SCHEMA but then it would complain about not having permissions on the table ...
So I guess my question is: is there any easy way of giving all the permissions to a user on a DB?
I'm working on PostgreSQL 8.1.23.
All commands must be executed while connected to the right database cluster. Make sure of it.
Roles are objects of the database cluster. All databases of the same cluster share the set of defined roles. Privileges are granted / revoked per database / schema / table etc.
A role needs access to the database, obviously. That's granted to PUBLIC by default. Else:
GRANT CONNECT ON DATABASE my_db TO my_user;
Basic privileges for Postgres 14 or later
Postgres 14 adds the predefined, non-login roles pg_read_all_data / pg_write_all_data.
They have SELECT / INSERT, UPDATE, DELETE privileges for all tables, views, and sequences. Plus USAGE on schemas. We can GRANT membership in these roles:
GRANT pg_read_all_data TO my_user;
GRANT pg_write_all_data TO my_user;
This covers all basic DML commands (but not DDL, and not some special commands like TRUNCATE or the EXECUTE privilege for functions!). The manual:
pg_read_all_data
Read all data (tables, views, sequences), as if having SELECT rights
on those objects, and USAGE rights on all schemas, even without
having it explicitly. This role does not have the role attribute
BYPASSRLS set. If RLS is being used, an administrator may wish to
set BYPASSRLS on roles which this role is GRANTed to.
pg_write_all_data
Write all data (tables, views, sequences), as if having INSERT,
UPDATE, and DELETE rights on those objects, and USAGE rights on
all schemas, even without having it explicitly. This role does not
have the role attribute BYPASSRLS set. If RLS is being used, an
administrator may wish to set BYPASSRLS on roles which this role is
GRANTed to.
All privileges without using predefined roles (any Postgres version)
Commands must be executed while connected to the right database. Make sure of it.
The role needs (at least) the USAGE privilege on the schema. Again, if that's granted to PUBLIC, you are covered. Else:
GRANT USAGE ON SCHEMA public TO my_user;
Or grant USAGE on all custom schemas:
DO
$$
BEGIN
-- RAISE NOTICE '%', ( -- use instead of EXECUTE to see generated commands
EXECUTE (
SELECT string_agg(format('GRANT USAGE ON SCHEMA %I TO my_user', nspname), '; ')
FROM pg_namespace
WHERE nspname <> 'information_schema' -- exclude information schema and ...
AND nspname NOT LIKE 'pg\_%' -- ... system schemas
);
END
$$;
Then, all permissions for all tables (requires Postgres 9.0 or later).
And don't forget sequences (if any):
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO my_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO my_user;
Alternatively, you could use the "Grant Wizard" of pgAdmin 4 to work with a GUI.
This covers privileges for existing objects. To also cover future objects, set DEFAULT PRIVILEGES. See:
Grant privileges for a particular database in PostgreSQL
How to manage DEFAULT PRIVILEGES for USERs on a DATABASE vs SCHEMA?
There are some other objects, the manual for GRANT has the complete list. As of Postgres 14:
privileges on a database object (table, column, view, foreign table, sequence, database, foreign-data wrapper, foreign server, function, procedure, procedural language, schema, or tablespace)
But the rest is rarely needed. More details:
Grant privileges for a particular database in PostgreSQL
How to grant all privileges on views to arbitrary user
Consider upgrading to a current version.
GRANT ALL PRIVILEGES ON DATABASE "my_db" to my_user;
In PostgreSQL 9.0+ you would do the following:
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA MY_SCHEMA TO MY_GROUP;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA MY_SCHEMA TO MY_GROUP;
If you want to enable this for newly created relations too, then set the default permissions:
ALTER DEFAULT PRIVILEGES IN SCHEMA MY_SCHEMA
GRANT ALL PRIVILEGES ON TABLES TO MY_GROUP;
ALTER DEFAULT PRIVILEGES IN SCHEMA MY_SCHEMA
GRANT ALL PRIVILEGES ON SEQUENCES TO MY_GROUP;
However, seeing that you use 8.1 you have to code it yourself:
CREATE FUNCTION grant_all_in_schema (schname name, grant_to name) RETURNS integer AS $$
DECLARE
rel RECORD;
BEGIN
FOR rel IN
SELECT c.relname
FROM pg_class c
JOIN pg_namespace s ON c.namespace = s.oid
WHERE s.nspname = schname
LOOP
EXECUTE 'GRANT ALL PRIVILEGES ON ' || quote_ident(schname) || '.' || rel.relname || ' TO ' || quote_ident(grant_to);
END LOOP;
RETURN 1;
END; $$ LANGUAGE plpgsql STRICT;
REVOKE ALL ON FUNCTION grant_all_in_schema(name, name) FROM PUBLIC;
This will set the privileges on all relations: tables, views, indexes, sequences, etc. If you want to restrict that, filter on pg_class.relkind. See the pg_class docs for details.
You should run this function as superuser and as regular as your application requires. An option would be to package this in a cron job that executes every day or every hour.
I did the following to add a role 'eSumit' on PostgreSQL 9.4.15 database and provide all permission to this role :
CREATE ROLE eSumit;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO eSumit;
GRANT ALL PRIVILEGES ON DATABASE "postgres" to eSumit;
ALTER USER eSumit WITH SUPERUSER;
Also checked the pg_table enteries via :
select * from pg_roles;
Database queries snapshot :
In PostgreSQL 12 and later, it is possible to grant all privileges of a table in a database to a role/user/account.
The syntax is:
GRANT ALL ON table_name TO role_name;
If you want to grant it to all tables in the database then the syntax will be:
GRANT ALL ON ALL TABLES TO role_name;
If you want to grant it to all tables of a schema in the database then the syntax will be:
GRANT ALL ON ALL TABLES IN SCHEMA schema_name TO role_name;
Note: Remember you will need to select the database before you can grant its privileges to a user.
Resources: PostgreSQL GRANT
That's all
I hope this helps
GRANT USAGE ON SCHEMA schema_name TO user;
GRANT ALL ON SCHEMA schema_name TO user_name;
Give all permissions to a user on a PostgreSQL database:
Command:
grant all privileges on database [database_name] to [database_user_name];
Example:
grant all privileges on database studentdb to shaifullah;
OR
GRANT ALL PRIVILEGES ON DATABASE studentdb TO shaifullah;
I am trying to setup a new role for making the access rights granting easier. I was wondering if there is an easier way to give select on all tables (newly created tables should be accessible automatically) under a schema to selected users. I ran following queries for the same. But still my user is not able to access the specific table.
CREATE ROLE myrole;
GRANT SELECT ON myschema.mytable TO myrole;
GRANT usage ON schema myschema TO myrole;
CREATE USER mytest1 identified BY '***';
GRANT myrole TO mytest1;
After this, when I login with mytest1 user and trying to run select on myschema.mytable it is asking me to grant usage on schema to user. After I grant usage on schema to user directly it is failing with permission denied for that table.
Please help with the same. I am running on vertica 5.0
Update:
I find that u also have to make that role default or explicitely set that role as default for user session for making the role's effect take place.
ALTER USER mytest1 DEFAULT ROLE myrole;
But still, my another question of how to make all tables under a schema accessible to specific users remains.
As per the Vertica SQL Reference Manual.pdf (page 725) (doc version 5.0 - for page numbers)
GRANT (Schema)
...
USAGE
Allows the user access to the objects contained within the
schema. This allows the user to look up objects within the
schema. Note that the user must also be granted access to the
individual objects. See the GRANT TABLE (page 727) ... .
The the user must also be granted access to the individual objects means that you need to also GRANT table.
The two I use is GRANT SELECT and GRANT REFERENCES which allows the user to run queries and join (reference) tables in the query.
Example:
GRANT SELECT ON TABLE [schema].[Table1] TO myUser;
GRANT SELECT ON TABLE [schema].[Table2] TO myUser;
GRANT REFERENCES ON TABLE [schema].[Table1] TO myUser;
GRANT REFERENCES ON TABLE [schema].[Table2] TO myUser;
...
6.0 doc reference GRANT SCHEMA (page 808) and GRANT TABLE (page 813).