Unable to drop default privileged user in Postgresql - postgresql

When we are trying to drop 1 particular user in PostgreSQL Datbase we are getting below error. 
postgres=# DROP user xyz;
ERROR:  role "xyz" cannot be dropped because some objects depend on it
DETAIL:  owner of default privileges on new functions belonging to role xyz
 Then we tried to check the default privileges by below command. 
postgres=# \ddp xyz
    Default access privileges
Owner  | Schema |   Type   | Access privileges
---------+--------+----------+-------------------
xyz |       | function | 
Also we tried below command but no luck for us.
postgres=# ALTER DEFAULT PRIVILEGES FOR ROLE xyz REVOKE ALL ON FUNCTIONS FROM xyz ;
ALTER DEFAULT PRIVILEGES
postgres=# ALTER DEFAULT PRIVILEGES FOR ROLE xyz REVOKE ALL ON FUNCTIONS FROM xyz ;
ALTER DEFAULT PRIVILEGES
postgres=# \ddp xyz
     Default access privileges
Owner  | Schema |   Type   | Access privileges
---------+--------+----------+-------------------
xyz |      | function | 

Since the “default” default privilege for functions is “EXECUTE for everyone and the owner”. you'll have to restore that default:
ALTER DEFAULT PRIVILEGES FOR ROLE xyz GRANT EXECUTE ON FUNCTIONS TO PUBLIC;
ALTER DEFAULT PRIVILEGES FOR ROLE xyz GRANT EXECUTE ON FUNCTIONS TO xyz;
Then you should be able to drop the role;

Related

Create true read only user in PostgreSQL

I've spanned a PostgreSQL database in Digital Ocean. I now need to come with a set of users and databases for which I've thought on creating several databases (production, staging, etc) and having 2 associated roles for each database with read-only and read-write permissions (production_ro, production_rw, staging_ro, staging_rw, etc). My idea is that, by having those roles, I can now create individual users and assign them one of the roles so that I can quickly change/remove them in case of a breach.
I've been researching on this and all pages I can find have a set of instructions similar to the ones in here:
-- Revoke privileges from 'public' role
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON DATABASE mydatabase FROM PUBLIC;
-- Read-only role
CREATE ROLE readonly;
GRANT CONNECT ON DATABASE mydatabase TO readonly;
GRANT USAGE ON SCHEMA myschema TO readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA myschema TO readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema GRANT SELECT ON TABLES TO readonly;
-- Read/write role
CREATE ROLE readwrite;
GRANT CONNECT ON DATABASE mydatabase TO readwrite;
GRANT USAGE, CREATE ON SCHEMA myschema TO readwrite;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA myschema TO readwrite;
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO readwrite;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA myschema TO readwrite;
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema GRANT USAGE ON SEQUENCES TO readwrite;
-- Users creation
CREATE USER reporting_user1 WITH PASSWORD 'some_secret_passwd';
CREATE USER reporting_user2 WITH PASSWORD 'some_secret_passwd';
CREATE USER app_user1 WITH PASSWORD 'some_secret_passwd';
CREATE USER app_user2 WITH PASSWORD 'some_secret_passwd';
-- Grant privileges to users
GRANT readonly TO reporting_user1;
GRANT readonly TO reporting_user2;
GRANT readwrite TO app_user1;
GRANT readwrite TO app_user2;
I've carefully followed those instructions and monitored that none of them failed but, after successfully running them all, I'm left with supposedly read-only users that can, in fact, create tables, not see the tables created by other users, and switch databases.
What am I doing wrong?
--- Edit ---
This is the result of the \dn+ command:
List of schemas
Name | Owner | Access privileges | Description
--------+----------+----------------------+------------------------
public | postgres | postgres=UC/postgres+| standard public schema
| | =UC/postgres |
--- Edit 2 ---
Here is what I do (for security reasons, I'll redact the users as <USER_A>, <USER_B>, etc. those redacted users will match 1 to 1 to the real ones):
$ psql "postgresql://USER_A:<PASSWORD>#<DOMAIN>:<PORT>/<DEFAULT_DB>?sslmode=require"
psql (15.1, server 14.6)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
<DEFAULT_DB>=> \connect production
psql (15.1, server 14.6)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
You are now connected to database "production" as user "USER_A"
production=> \du
List of roles
Role name | Attributes | Member of
-----------------+------------------------------------------------------------+---------------------------------------------------------------------------
USER_B | Superuser, Replication | {}
USER_A | Create role, Create DB, Replication, Bypass RLS | {pg_read_all_stats,pg_stat_scan_tables,pg_signal_backend,r_production_ro}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
production_ro | Cannot login | {}
production=> REVOKE CREATE ON SCHEMA public FROM PUBLIC;
WARNING: no privileges could be revoked for "public"
REVOKE
production=>
--- Edit 3 ---
Got in contact with DigitalOcean. This is their response:
Just to let you know that we are investigating this issue, so far I
was able to reproduce the behavior. It seems that in order to remove
the create table from the public schema from a user we would need to
"REVOKE CREATE ON SCHEMA public FROM PUBLIC;" which is not allowed as
the doadmin use is not a superuser and revoking this privilege would
impact other roles.
If the user can create tables it has CREATE permissions on the schema in question. Look at those permissions with \dn+ public in psql. Identify the permissions in question and REVOKE them.
Alternatively, if you use PostgreSQL v15 or above, it micht be that your database user is directly or indirectly a member of the predefiled role pg_write_all_data. Revoke that membership.
In your specific case, the correct thing to do is to revoke the default CREATE privilege on schema public from PUBLIC, that is, everyone:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
You say you already did that, and it caused a warning and had no effect. That is not what PostgreSQL would do. You'll have to ask the people who modified PostgreSQL, in your case DigitalOcean.

Schema privileges vs Database privileges in PostgreSQL

In a PostgreSQL server, I want to create a database (db1) and give all privileges on that database to a user (user1). I run these commands:
CREATE USER user1 WITH PASSWORD 'password';
CREATE DATABASE db1;
\c db1
CREATE SCHEMA user1;
DROP SCHEMA public;
Now the database (db1) has only the schema user1. The next step is to grant all privileges to the user (user1).
If I run the following commands, and try to create a table as user1, it works:
GRANT ALL PRIVILEGES ON SCHEMA user1 TO user1;
\c db1 user1
CREATE TABLE t1(a int);
If I only grant privileges on the database (and not the schema), it does not work:
GRANT ALL PRIVILEGES ON DATABASE db1 TO user1;
\c db1 user1
CREATE TABLE t1(a int);
The create table will fail with these errors:
db1=> CREATE TABLE t1(a int);
ERROR: no schema has been selected to create in
LINE 1: CREATE TABLE t1(a int);
^
db1=> CREATE TABLE user1.t1(a int);
ERROR: permission denied for schema user1
LINE 1: CREATE TABLE user1.t1(a int);
^
So, my questions are: Is the GRANT ALL PRIVILEGES ON DATABASE really needed here? What are the privileges granted by that command?
What are the privileges granted by that command?
According to the privileges documentation, a GRANT ALL on the DATABASE level encompasses:
CREATE: allows new schemas and publications to be created within the database, and allows trusted extensions to be installed within the database.
CONNECT: Allows the grantee to connect to the database. This privilege is checked at connection startup (in addition to checking any restrictions imposed by pg_hba.conf).
TEMPORARY: Allows temporary tables to be created while using the database.
By default, anyone (PUBLIC) has CONNECT and TEMPORARY privileges already, so GRANT ALL PRIVILEGES ON DATABASE db1 TO user1; will only affect the CREATE privilege. Judge yourself whether that's really needed.
Instead of creating the schema and granting all privileges on it to user1, you may want to grant the CREATE privilege on the database, and let the user1 create their schema themselves (so that they become its owner and will thereby get all the privileges on it). It will allow them to also create any other schema then.
Thanks #Bergi it is clear now. Using the GRANT ALL PRIVILEGES ON DATABASE the following works:
postgres=# CREATE USER user1 WITH PASSWORD 'password';
CREATE ROLE
postgres=# CREATE DATABASE db1;
CREATE DATABASE
postgres=# GRANT ALL PRIVILEGES ON DATABASE db1 TO user1;
GRANT
postgres=# \c db1 user1
You are now connected to database "db1" as user "user1".
db1=> CREATE SCHEMA user1;
CREATE SCHEMA
db1=> DROP SCHEMA public;
ERROR: must be owner of schema public
db1=> CREATE TABLE t1(a int);
CREATE TABLE
db1-> \dt
List of relations
Schema | Name | Type | Owner
--------+------+-------+-------
user1 | t1 | table | user1
(1 row)
db1-> \dn
List of schemas
Name | Owner
--------+----------
public | postgres
user1 | user1
(2 rows)
Observe that the user (user1) cannot delete the schema public because the owner is postgres, even the user has all privileges on the database (db1).

PostgreSQL - ALTER DEFAULT PRIVILEDGES....SELECT ON TABLES... in all schemas

Is it possible to alter default priviledges on PostgreSQL role, such that role has SELECT on any table in any schema (existing or created in future)
I have 3 roles (app_r is member of app_rw which is member of app_rwc)
and I am trying this:
ALTER DEFAULT PRIVILEGES FOR ROLE app_rwc GRANT USAGE ON SCHEMAS TO app_r;
ALTER DEFAULT PRIVILEGES FOR ROLE app_rwc GRANT SELECT ON TABLES TO app_r;
but it does not work.
SELECT has_table_privilege('app_r', 'some_schema.some_table', 'SELECT')
-- false
Is there a way to do this in PG or do I have to use IN SCHEMA and repeat for every schema? (ughhh)
ALTER DEFAULT PRIVILEGES FOR ROLE app_r IN SCHEMA some_schema GRANT SELECT ON TABLES TO app_r;
P.S.
I did try running ALTER DEFAULT before (and after also, just to test) creating schemas and tables...
P.P.S
My role setup is inspired by this answer and I saw in this answer that is not necessary having to explicitly specify schemas
UPDATE #1 - Here is exact role setup I am using:
CREATE ROLE app_rwc INHERIT CREATEDB CREATEROLE;
CREATE ROLE app_rw INHERIT;
CREATE ROLE app_r INHERIT;
GRANT app_r TO app_rw;
GRANT app_rw TO app_rwc;
-- these must be performed *before* any objects are created
ALTER DEFAULT PRIVILEGES FOR ROLE app_rwc GRANT USAGE ON SCHEMAS TO app_r;
ALTER DEFAULT PRIVILEGES FOR ROLE app_rwc GRANT SELECT ON TABLES TO app_r;
ALTER DEFAULT PRIVILEGES FOR ROLE app_rwc GRANT INSERT, UPDATE, DELETE ON TABLES TO app_rw;
ALTER DEFAULT PRIVILEGES FOR ROLE app_rwc REVOKE TRUNCATE ON TABLES TO app_rw;
ALTER DEFAULT PRIVILEGES FOR ROLE app_rwc GRANT SELECT, UPDATE ON SEQUENCES TO app_rw;
Is it possible to alter default priviledges on PostgreSQL role, such
that role has SELECT on any table in any schema (existing or created
in future)
As of version 9.6, no.

Postgresql forgets grants after recreating tables

We use liquibase to manage and execute our database changes. On our DEV environment (and especially on local machines) we frequently recreate the tables to have a clean slate.
We have just migrated from MySQL to Postgres and are facing a problem related to these table recreations.
Initially we have granted our DB user with this:
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO mydbuser;
GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA public TO mydbuser;
This is executed through psql after connecting to our own DB (where public is the default/only schema).
Everything is fine until we ask liquibase to recreate the tables in which case it will drop all tables and create them again.
After that it appears that mydbuser has lost all its grants on the tables.
According to several resources (like this) we need to alter the default privileges, so we obey:
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO mydbuser;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT,INSERT,UPDATE,DELETE ON TABLES TO mydbuser;
GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA public TO mydbuser;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, USAGE ON SEQUENCES TO mydbuser;
However, although this seems very logical it changed nothing. All grants (even select) are still lost after recreating the tables.
What are we doing wrong or what else do we need to do?
UPDATE
\ddp shows:
Default access privileges
Owner | Schema | Type | Access privileges
----------+--------+----------+--------------------
postgres | public | sequence | mydb=rU/postgres
postgres | public | table | mydb=arwd/postgres
If trying to mimic what liquibase is doing in a simplified test case, it just works.
Quick demo with 9.3:
1) Create the objects from scratch with the postgres user:
postgres=# create database dbtest;
CREATE DATABASE
postgres=# create user mydbuser;
CREATE ROLE
postgres=# \c dbtest
You are now connected to database "dbtest" as user "postgres".
dbtest=# ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT,INSERT,UPDATE,DELETE ON TABLES TO mydbuser;
ALTER DEFAULT PRIVILEGES
dbtest=# create table foobar(id int);
CREATE TABLE
2) In another session let's connect with mydbuser and see if SELECT is allowed.
dbtest=> select * from foobar;
id
----
(0 rows)
Result: Yes, it's allowed. Note the result of \ddp too:
dbtest=> \ddp
Default access privileges
Owner | Schema | Type | Access privileges
----------+--------+-------+------------------------
postgres | public | table | mydbuser=arwd/postgres
(1 row)
3) Let's have postgres drop the table and recreate it:
dbtest=# drop table foobar;
DROP TABLE
dbtest=# create table foobar(id int);
CREATE TABLE
4) See if mydbuser can still SELECT from it.
$ psql -d dbtest -U mydbuser
dbtest=> select * from foobar;
id
----
(0 rows)
Result: Yes, as expected.
5) See if another user can SELECT from it.
$ psql -d dbtest -U daniel
dbtest=> select * from foobar;
ERROR: permission denied for relation foobar
Result: No, as expected.
This does not explain what doesn't work for you, but you may compare the above with the set of commands issued by liquibase.

ERROR: permission denied for relation tablename on Postgres while trying a SELECT as a readonly user

GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
The readonly user can connect, see the tables but when it tries to do a simple select it gets:
ERROR: permission denied for relation mytable
SQL state: 42501
This is happening on PostgreSQL 9.1
What I did wrong?
Here is the complete solution for PostgreSQL 9+, updated recently.
CREATE USER readonly WITH ENCRYPTED PASSWORD 'readonly';
GRANT USAGE ON SCHEMA public to readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly;
-- repeat code below for each database:
GRANT CONNECT ON DATABASE foo to readonly;
\c foo
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly; --- this grants privileges on new tables generated in new database "foo"
GRANT USAGE ON SCHEMA public to readonly;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
Thanks to https://jamie.curle.io/creating-a-read-only-user-in-postgres/ for several important aspects
If anyone find shorter code, and preferably one that is able to perform this for all existing databases, extra kudos.
Try to add
GRANT USAGE ON SCHEMA public to readonly;
You probably were not aware that one needs to have the requisite permissions to a schema, in order to use objects in the schema.
This worked for me:
Check the current role you are logged into by using:
SELECT CURRENT_USER, SESSION_USER;
Note: It must match with Owner of the schema.
Schema | Name | Type | Owner
--------+--------+-------+----------
If the owner is different, then give all the grants to the current user role from the admin role by :
GRANT 'ROLE_OWNER' to 'CURRENT ROLENAME';
Then try to execute the query, it will give the output as it has access to all the relations now.
make sure your user has attributes on its role. for example:
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------+-----------
flux | | {}
postgres | Superuser, Create role, Create DB, Replication | {}
after performing the following command:
postgres=# ALTER ROLE flux WITH Superuser;
ALTER ROLE
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------+-----------
flux | Superuser | {}
postgres | Superuser, Create role, Create DB, Replication | {}
it fixed the problem.
see tutorial for roles and stuff here: https://www.digitalocean.com/community/tutorials/how-to-use-roles-and-manage-grant-permissions-in-postgresql-on-a-vps--2
You should execute the next query:
GRANT ALL ON TABLE mytable TO myuser;
Or if your error is in a view then maybe the table does not have permission, so you should execute the next query:
GRANT ALL ON TABLE tbm_grupo TO myuser;