Create PostgreSQL read only user ERROR: permission denied for relation _foo - sql

I have an issue while trying to create a readonly user in PostgreSQL.
I want user ckan_default to create tables in database datastore_default.
And I want readonlyuser to read tables created by ckan_default in datastore_default.
I want this rule to apply to tables that will be created by ckan_default, not only the ones already created.
GRANT CONNECT ON DATABASE datastore_default TO readonlyuser;
GRANT USAGE ON SCHEMA public TO readonlyuser;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonlyuser;
ALTER DEFAULT PRIVILEGES FOR USER readonlyuser IN SCHEMA public GRANT SELECT ON TABLES TO readonlyuser;
acutally the complete script I ran was
sudo -u postgres psql postgres -f /tmp/set_permissions.sql
--content of /tmp/set_permissions.sql
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE USAGE ON SCHEMA public FROM PUBLIC;
GRANT CREATE ON SCHEMA public TO ckan_default;
GRANT USAGE ON SCHEMA public TO ckan_default;
GRANT CREATE ON SCHEMA public TO ckan_default;
GRANT USAGE ON SCHEMA public TO ckan_default;
REVOKE CONNECT ON DATABASE ckan_default FROM readonlyuser;
GRANT CONNECT ON DATABASE datastore_default TO readonlyuser;
GRANT USAGE ON SCHEMA public TO readonlyuser;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonlyuser;
ALTER DEFAULT PRIVILEGES FOR USER ckan_default IN SCHEMA public
GRANT SELECT ON TABLES TO readonlyuser;
I read this post How do you create a read-only user in PostgreSQL and I either tried it or it does not work for tables that will be created.
For more details and the complete script check out the pastebin http://pastebin.com/psDifhwd

My suspicion is that the search_path of all users is set to the typical default
"$user",public
Which means _foo without schema-qualification would resolve to $user._foo:
ckan_default._foo for ckan_default, and
readonlyuser._foo for readonlyuser.
Repeat your test with:
sudo -u postgres psql -d datastore_default -U ckan_default -c 'CREATE TABLE public._foo()'
sudo -u postgres psql -d datastore_default -U ckan_default -c 'SELECT * FROM public._foo'
sudo -u postgres psql -d datastore_default -U readonlyuser -c 'SELECT * FROM public._foo'
If that's the case, consider changing the default search_path for each user:
ALTER ROLE ckan_default SET search_path=public;
ALTER ROLE readonlyuser SET search_path=public;
Or whatever suits your needs.
Also consider changing the default setting in postgresql.conf.
More related answers:
How does the search_path influence identifier resolution and the "current schema"
Grant all on a specific schema in the db to a group role in PostgreSQL
Grant privileges for a particular database in PostgreSQL

Related

User management + grant

I have a database with multiple tables, functions, sequences, and types inside.
I want to create multiple "administrator"-like users:
they all might have all privileges to manage everything (existing and newly created items) in this database;
they all have the same privileges;
they might cross-manage entities (table created by administrator a should be available for a removal for administrator b)
I tried to create something like this, but failed on types:
"GRANT ALL PRIVILEGES ON DATABASE {dbname} TO {rw_user};"
"GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO {rw_user};"
"GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO {rw_user};"
"GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO {rw_user};"
"GRANT ALL PRIVILEGES ON ALL TYPES IN SCHEMA public TO {rw_user};" --not exists
"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO {rw_user};"
"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO {rw_user};"
"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO {rw_user};"
"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TYPES TO {rw_user};"
The only way I can think of to do that (if you don't want a shared database user) is the following:
CREATE ROLE admins;
CREATE ROLE a LOGIN NOINHERIT IN ROLE admins;
CREATE ROLE b LOGIN NOINHERIT IN ROLE admins;
CREATE SCHEMA shared;
GRANT CREATE; USAGE ON SCHEMA shared TO admins;
Then neither a nor b can create objects in shared unless they do the following:
SET ROLE admins;
CREATE TABLE shared.newtab (...);
RESET ROLE;
Such a table is then owned by admins, and both a and b can ALTER or DROP it.
Note that ALTER and DROP are restricted to the owner of the object, and you cannot GRANT these rights.

Preventing users from altering default privileges on PostgreSQL

I'm testing database permissions on PostgreSQL and i'm trying to prevent a common user (readuser) from executing an 'ALTER DEFAULT PRIVILEGES' statement. However i cannot find a way to revoke this specific permission, and couldn't find anything about it on documentation.
I started a local PostgreSQL 11.2 instance, removed connect permisssions, created a database testdb and revoked table creation on the public schema.
revoke connect on database postgres from public;
create database testdb with template template0 --lc_collate "pt_BR.utf8" lc_ctype "pt_BR.utf8";
revoke connect on database testdb from public;
\c :database
revoke all on schema public from public;
grant all on schema public to postgres;
create schema private;
After that, I created a user with read permissions only:
create user readuser
with nosuperuser
nocreatedb
nocreaterole
noreplication
login
encrypted password 'testpassword';
grant connect
on database testdb
to readuser;
Then create a schema testschema and granted read permissions on it's tables:
grant usage
on schema testschema
to readuser;
grant select
on all tables
in schema testschema
to readuser;
Even though i only set read permissions on all schemas and tables, the 'readuser' user can still perform 'alter default privileges' query without a permission error:
alter default privileges in schema testschema grant select on tables to readuser;
ALTER DEFAULT PRIVILEGES
I would like some help on preventing a user from altering it's default privileges, so that it cannot mess up permissions for tables created in the future.
Try this by revoking the EXECUTE from the role postgres that granted the default privilege of execute to readuser
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA testschema REVOKE EXECUTE ON FUNCTIONS FROM readuser;

Cannot drop PostgreSQL role. Error: `cannot be dropped because some objects depend on it`

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/

Grant privileges on future tables in PostgreSQL?

I am running PostgreSQL 9.3.1. I have test database and backup user which is used to backup the database. I have no problems with granting privileges to all current tables, but I have to grant privileges each time the new table is added to schema.
createdb test
psql test
test=# create table foo();
CREATE TABLE
test=# grant all on all tables in schema public to backup;
GRANT
test=# create table bar();
CREATE TABLE
psql -U backup test
test=> select * from foo;
test=> select * from bar;
ERROR: permission denied for relation bar
Is it possible to grant access to tables which will be created in future without making user owner of the table?
It looks like the solution is to alter default privileges for backup user:
alter default privileges in schema public grant all on tables to backup;
alter default privileges in schema public grant all on sequences to backup;
From the comment by Matt Schaffer:
As caveat, the default only applies to the user that executed the
alter statement. This confused me since I was driving most of my
permissions statements from the postgres user but creating tables from
an app user. In short, you might need something like this depending on
your setup:
ALTER DEFAULT PRIVILEGES FOR USER webapp IN SCHEMA public GRANT SELECT ON SEQUENCES TO backup;
ALTER DEFAULT PRIVILEGES FOR USER webapp IN SCHEMA public GRANT SELECT ON TABLES TO backup;
Where webapp is the user that will be creating new tables in the futrue and backup is the user that will be able to read from new tables created by webapp.
If you want the backup user to have access to the future tables of userN,
you must run the code below under each userN who creates new tables,
because ALTER DEFAULT PRIVILEGES...
works only for objects by that user under whom you run ALTER DEFAULT PRIVILEGES...
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO backup;
I am trying to create a role, grant connect access to the role and then alter default privileges to keep access for future objects. However, it seems that the below command doesn't work at role level.
alter default privileges in schema public grant all on tables to backup;
I followed the below documentation but seems that there are two command do not work for roles.
DOC: https://aws.amazon.com/blogs/database/managing-postgresql-users-and-roles/
First command:
GRANT CONNECT ON DATABASE mydatabase TO readonly;
Second command:
GRANT USAGE ON SCHEMA myschema TO readonly;
(For ROLES usually it needs TO ROLE, I also tried TO ROLE but still doesn't work.

How to grant all privileges on views to arbitrary user

How do you grant read/select access on all functions and views to an arbitrary user?
I use psql --user=postgres -d mydb -f myview.sql to create several functions and views, and then I run:
GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;
Having been granted all privileges, I would expect myuser to now have access to the functions and views created by the postgres user. However, when I try and access them with myuser, I get a "permission denied for relation..." error. Why is this?
The reason is that you need additional privileges to access a view or table. Privileges on the database do not cover access to all objects in it.
It is different with functions: EXECUTE privilege is granted to public by default. But the function is executed with the privileges of the current user. You may be interested in the SECURITY DEFINER modifier for CREATE FUNCTION. But normally it is enough to grant SELECT on involved tables.
Per documentation about default privileges:
Depending on the type of object, the initial default privileges might
include granting some privileges to PUBLIC. The default is no public
access for tables, columns, schemas, and tablespaces; CONNECT
privilege and TEMP table creation privilege for databases; EXECUTE
privilege for functions; and USAGE privilege for languages.
You may be interested in this DDL command (requires Postgres 9.0 or later):
GRANT SELECT ON ALL TABLES IN SCHEMA public TO myuser;
While connected to the database in question, of course (see #marcel's comment below), and as a user with sufficient privileges. You may also be interested in the setting DEFAULT PRIVILEGES:
Grant all on a specific schema in the db to a group role in PostgreSQL
More detailed answer how to manage privileges:
How to manage DEFAULT PRIVILEGES for USERs on a DATABASE vs SCHEMA?
pgAdmin has a feature for more sophisticated bulk operations:
Or you can query the system catalogs to create DDL statements for bulk granting / revoking ...