Postgresql: why can't you drop a role with privileges that does not own any ressource? - postgresql

I'm confused by the nomenclature around roles and privileges with postgresql.
Given a stock postgresql install, if I do this:
postgres=# create database foo;
CREATE DATABASE
Now, there is a database.
postgres=# create role bar;
CREATE ROLE
Now, there is a user. I can delete it:
postgres=# drop role bar;
DROP ROLE
And it's gone, and I can recreate it again.
postgres=# create role bar;
CREATE ROLE
postgres=# grant all privileges on database foo to bar;
GRANT
So this role does not own anything. (Since there is nothing to own.)
The database existed before the role. The way I understand it, it's an independent entity.
And you've just "GRANT"-ed the role "bar" to do some things with this database.
Plain english. Pretty logical.
Then you changed your mind, and remove the role:
postgres=# drop role bar;
ERROR: role "bar" cannot be dropped because some objects depend on it
DETAIL: privileges for database foo
"What the what ? What do you mean 'some objects depend on it' ? THERE IS NO OBJECT YET !!!", you ask.
As I understand it, the answer lies here:
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
--------------+----------+----------+-------------+-------------+---------------------------
foo | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres +
| | | | | postgres=CTc/postgres +
| | | | | bar=CTc/postgres
So the "ressource" that depends on you is the "privilege" itself.
So you can remove the privilege, and after that, drop the role:
postgres=# revoke all on database foo from bar;
REVOKE
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
--------------+----------+----------+-------------+-------------+---------------------------
foo | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres +
| | | | | postgres=CTc/postgres
postgres=# drop user bar;
DROP ROLE
So my question is: why ? In this situation, something is preventing postgresql from doing the (obvious / expected / arguably less confusing) thing, and "cascading" the dropping of "privileges", too.
What could it be ?
It might simply be a confusing error message over a n00b issue, but I suspect something more fundamental...

Related

Postgresql Access Control

I am trying to create a Postgresql database with a new owner for which I did the following:
postgres=# create user saurabhd;
postgres=# CREATE DATABASE test_db OWNER saurabhd;
postgres=# ALTER USER saurabhd PASSWORD 'spassword'
Evidently, the new user and Database were created from postgres user(default user). \l command showed the following:
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
postgres | postgres | UTF8 | en_GB.UTF-8 | en_GB.UTF-8 |
template0 | postgres | UTF8 | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_GB.UTF-8 | en_GB.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
test_db | saurabhd | UTF8 | en_GB.UTF-8 | en_GB.UTF-8 |
As can be seen, the owner name for database test_db is saurabhd. Although, I can still access the DB test_db with 'postgres' user and modify the DB.
Is there a way, I can restrict postgres user(and all other users except saurabhd) from accessing the DB test_db?
ALTER ROLE
The management of roles in PostgreSQL allows different configurations, among them are:
SUPERUSER / NOSUPERUSER. Super User, privileges to create databases
and users.
CREATEDB / NOCREATEDB. Create databases.
CREATEROLE / NOCREATEROLE. Create roles.
CREATEUSER / NOCREATEUSER. Create users.
LOGIN / NOLOGIN. This attribute makes the difference between a role
and a user. Since the user has permissions to access the database
through a client.
PASSWORD. Allows you to change the password.
VALID UNTIL. Expiration of users.
To change the configuration of a user or role we must execute the following command.
ALTE ROLE <nombre del rol> WITH <opciones>
Create a database with a specific user as owner
All databases that we create with a user that has the CREATEDB privileges automatically assign the user as the owner. If what we want to create is a limited user, the way to create it with a specific database will be:
CREATE DATABASE user OWNER saurabhd ;
Assigning super user permissions to a user
The super user license is the highest. With this user you can manage all the objects of the database engine.
To assign this privilege to a role we do it with the following command:
ALTER ROLE saurabhd WITH SUPERUSER;
Assign all permissions to a user to an existing database
When we have just created a user and want to give permissions to an existing database, we can use the following command:
GRANT ALL PRIVILEGES ON DATABASE nameBase TO saurabhd;

Restrict user to one schema in PostgreSQL?

Is it possible in PostgreSQL to create a user that can only access a single schema?
Here is what I tried:
REVOKE ALL ON DATABASE testdb FROM public;
GRANT CONNECT ON DATABASE testdb TO testuser;
When I connect as testuser indeed I cannot access the actual data:
> SELECT * FROM some_table;
ERROR: permission denied for relation some_table
However, I can still list all the tables, etc. in all the other schemas:
SELECT * FROM pg_tables;
schemaname | tablename | tableowner | tablespace | hasindexes | hasrules | hastriggers | rowsecurity
--------------------+-------------------------------------------+------------+------------+------------+----------+-------------+-------------
test2 | foo | postgres | | t | f | f | f
test2 | bar | postgres | | t | f | f | f
...
It is impossible to configure PostgreSQL so that a user can only see those objects in the system catalogs for which he or she has permissions.
If you need such a setup, you should create a database per user.
I was able to do this like so:
GRANT USAGE ON SCHEMA schema_name TO user_name;
ALTER USER user_name SET search_path = schema_name;
The ALTER USER statement like this is a way of permanently setting the search path for schemas the way you would set the schema search path of an individual sessions with
SET SEARCH_PATH= schema_name_1, schema_name_2;

Why aren't these commands creating a read-only user in PostgreSQL?

I've carefully reviewed similar questions on this site and I can't get it to work.
I'm using PostgreSQL 9.3.9 (installed from package) on Ubuntu 14.04 (Vagrant box).
I'm creating a new database called site owned by postgres.
I want to create a read-only user called readonly with access to this database.
I've tried to lock them out of SCHEMA public but whatever I try to do, they can still create tables.
Can anybody help me understand why this user can still write to the database, despite being locked out completely? Here's the steps I'm taking; first, set up the entities and explicitly lock out all the permissions:
postgres=# CREATE DATABASE site;
CREATE DATABASE
postgres=# CREATE ROLE readonly UNENCRYPTED PASSWORD 'password' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER CONNECTION LIMIT -1;
CREATE ROLE
postgres=# REVOKE ALL ON SCHEMA public FROM public;
REVOKE
postgres=# REVOKE ALL ON SCHEMA public FROM readonly;
REVOKE
postgres=# REVOKE ALL ON DATABASE site FROM public;
REVOKE
Let's check that readonly can't connect:
vagrant#vagrant-web1:~$ PGHOST=127.0.0.1 PGPASSWORD=password psql -U readonly site
psql: FATAL: permission denied for database "site"
DETAIL: User does not have CONNECT privilege.
Everything correct up to this point. Now the superuser grants a single permission:
postgres=# GRANT CONNECT ON DATABASE site TO readonly;
GRANT
This is where the system breaks. The readonly user can log in and can create tables:
vagrant#vagrant-web1:~$ PGHOST=127.0.0.1 PGPASSWORD=password psql -U readonly site
psql (9.3.9)
SSL connection (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256)
Type "help" for help.
site=> CREATE TABLE orders(id int);
CREATE TABLE
site=> \dt
List of relations
Schema | Name | Type | Owner
--------+--------+-------+----------
public | orders | table | readonly
(1 row)
This has had me stuck for a couple of hours. Any help would be greatly appreciated.
Extra information: There's only a single schema in the database. Here's what the output of \du is:
postgres=# \du
List of roles
Role name | Attributes | Member of
---------------------+------------------------------------------------+-----------------------------------------------
postgres | Superuser, Create role, Create DB, Replication | {}
readonly | | {}
Here's the output of \list:
postgres=# \list
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------------+---------------------+----------+-------------+-------------+---------------------------------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
site | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | postgres=CTc/postgres +
| | | | | readonly=c/postgres
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
You issued commands REVOKE ALL ON SCHEMA public ... in database postgres, not site. Check it:
site=> \dn+
List of schemas
Name | Owner | Access privileges | Description
--------+----------+----------------------+------------------------
public | postgres | postgres=UC/postgres+| standard public schema
| | =UC/postgres |
(1 row)
Line =UC/postgres means that public has Usage and Create privileges for schema public.
So do the following:
site=> \c site postgres
You are now connected to database "site" as user "postgres".
site=# REVOKE ALL ON SCHEMA public FROM public;
REVOKE
And now it works:
site=# \c site readonly
You are now connected to database "site" as user "readonly".
site=> create table t(n numeric);
ERROR: no schema has been selected to create in
site=> create table public.t(n numeric);
ERROR: permission denied for schema public

Revoke privilege "create table" from public schema but not from custom made schema

I am trying to create an account that is only able to use "SELECT" within the mydb_schema.
I am able to revoke the creation of a tables in public schema in my database (mydb) from a specific role but I am not able to revoke the creation of tables within the schema (mydb_schema) the role (user_role) is assigned to.
Can someone assist? What am I missing?
Below are the commands I used as user postgres and as the owner of the schema. At the end I also altered the postgres account by using the noinherit just as a desperate test. No result.
\c mydb
mydb=# create role user_account
mydb=# alter role user_account login noinherit;
mydb=# alter role user_account set search_path = 'mydb_schema';
##Up until this point I don't have SELECT pivileges but I can create a table within mydb_schema only and not in public.
mydb=# grant select on all tables in schema mydb_schema to user_account;
mydb=# revoke CREATE on SCHEMA public from public;
These are my databases:
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
--------------------------------------------------------------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 6820 kB | pg_default | default administrative connection database
mydb | seeker | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/seeker +| 3465 MB | pg_default |
seeker=CTc/seeker
These are my schemas:
List of schemas
Name | Owner | Access privileges | Description
----------------+----------+----------------------+------------------------
public | postgres | postgres=UC/postgres | standard public schema
mydb_schema | seeker | seeker=UC/seeker +|
| | =UC/seeker |
Found the solution here in dba.stackexchange
alter role servers_admin set default_transaction_read_only = 'ON';

postgres read only user not working

I have Postgresql 9.2 with database running and now try to create a read only user. I followed these descriptions:
ERROR: permission denied for relation tablename on Postgres while trying a SELECT as a readonly user
How do you create a read-only user in PostgreSQL?
BasicallyI have done the following:
jbossmanager=# CREATE USER jbcust WITH ENCRYPTED PASSWORD '#######';
CREATE ROLE
jbossmanager=# GRANT USAGE ON SCHEMA jbossmanager to jbcust;
GRANT
jbossmanager=# ALTER DEFAULT PRIVILEGES IN SCHEMA jbossmanager GRANT SELECT ON TABLES TO jbcust;
ALTER DEFAULT PRIVILEGES
jbossmanager=# GRANT CONNECT ON DATABASE jbossmanager to jbcust;
GRANT
jbossmanager=# GRANT SELECT ON ALL SEQUENCES IN SCHEMA jbossmanager TO jbcust;
GRANT
jbossmanager=# GRANT SELECT ON ALL TABLES IN SCHEMA jbossmanager TO jbcust;
GRANT
After this a "\l" shows the following:
jbossmanager=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
--------------+--------------+----------+-------------+-------------+-------------------------------
jbossmanager | jbossmanager | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/jbossmanager +
| | | | | jbossmanager=CTc/jbossmanager+
| | | | | jbcust=c/jbossmanager
which looks good to me, also a list of tables in that db / schema lokks fine:
jbossmanager=# \dp+
Access privileges
Schema | Name | Type | Access privileges | Column access privileges
--------------+-------------------------------+----------+-----------------------------------+--------------------------
jbossmanager | env_server_standalone_info | table | jbossmanager=arwdDxt/jbossmanager+|
| | | jbcust=r/jbossmanager |
But now when I connect as this jbcust user to database and try:
#psql -d jbossmanager -U jbcust -h 127.0.0.1
Password for user jbcust:
psql (9.2.4)
Type "help" for help.
jbossmanager=> \dp+
Access privileges
Schema | Name | Type | Access privileges | Column access privileges
--------+------+------+-------------------+--------------------------
(0 rows)
I have no idea what is wrong or what is missing.
Thanks a lot for your help!
The reason why I did not see any schema when connecting with read only user is that the default schema for this user was not set.
After this:
ALTER USER jbcust SET search_path = jbossmanager;
it works perfect.